Freezer Monitoring - using a Fibaro FGK-101 Temperature & Door/Window sensor



Hey, everyone. I’ve had SmartThings for about a year now and don’t have too many devices connected (21 total), but was really wanting to monitor a deep freezer from the 1980’s that I’m currently storing several hundred dollars worth of food in.

I ordered a Fibaro FGK-101 and a DS18B20 and thought it’d be an easy process to get it synced, not realizing it would require a custom device…

I tried relentlessly to get @geeji’s code to work at this link, but for some reason it wouldn’t. I think some of the Fibaro open/close sensors have a different firmware/code on them.

SmartThings support actually uncommented the standard device type that enabled the temperature to show up. I have never so much as looked at code in my life, but did some digging and put together a few extra items (making it so the temperature shows up by default on the ‘Things’ list rather than open/close status, color coding, including a temperature offset option, etc.)

I wanted to share in case anyone else is having issues. You could probably pick out 100 things wrong with my code, please feel free to edit and make it yours. I didn’t know what I was really doing, but I think it turned out okay. I’ve been using it for two weeks now. I get a push alert if it hits 5 degrees, a phone call from IFTTT if it hits 7 degrees, and a second phone call if it hits 9 degrees. Hoping this helps someone out there! I was frustrated for a while myself before figuring it out.

Please let me know the best way to copy code into the forum. This seems a little off-kilter…


  • Device Type Definition File
  • Device Type: Fibaro Door/Window Sensor
  • File Name: fibaro-door-window-sensor.groovy
  • Initial Release: 2014-12-10
  • @author: Todd Wackford
  • Email:
  • @version: 1.0
  • Copyright 2014 SmartThings
  • Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except
  • in compliance with the License. You may obtain a copy of the License at:
  • Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
  • on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
  • for the specific language governing permissions and limitations under the License.



  • Sets up metadata, simulator info and tile definition. The tamper tile is setup, but

  • not displayed to the user. We do this so we can receive events and display on device

  • activity. If the user wants to display the tamper tile, adjust the tile display lines

  • with the following:

  •    main(["contact", "temperature", "tamper"])
  •    details(["contact", "temperature", "battery", "tamper"])
  • @param none

  • @return none
    metadata {
    definition (name: “Nathaniel’s Fibaro Door/Window Sensor w Temp & Colors”, namespace: “smartthings”, author: “SmartThings”) {
    capability “Temperature Measurement” //UNCOMMENT ME IF TEMP INSTALLED
    capability "Contact Sensor"
    capability "Sensor"
    capability "Battery"
    capability “Configuration”

     command        "resetParams2StDefaults"
     command        "listCurrentParams"
     command        "updateZwaveParam"
     command        "test"
    fingerprint deviceId: "0x2001", inClusters: "0x30,0x9C,0x85,0x72,0x70,0x86,0x80,0x56,0x84,0x7A,0xEF,0x2B"
simulator {
    // messages the device returns in response to commands it receives
    status "open"  :      "command: 2001, payload: FF"
    status "closed":    "command: 2001, payload: 00"
    for (int i = 0; i <= 100; i += 20) {
        status "temperature ${i}F": new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
            scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1).incomingMessage()
    for (int i = 0; i <= 100; i += 20) {
        status "battery ${i}%": new physicalgraph.zwave.Zwave().batteryV1.batteryReport(
            batteryLevel: i).incomingMessage()

section {
        input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.", displayDuringSetup: false, type: "paragraph", element: "paragraph"
        input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
tiles {
    standardTile("contact", "", width: 1, height: 1) {
        state "open",   label: '${name}', icon: "",   backgroundColor: "#ffa81e"
        state "closed", label: '${name}', icon: "", backgroundColor: "#79b821"
    valueTile("temperature", "device.temperature", width: 2, height: 2, canChangeIcon: true, inactiveLabel: false) {
        state "temperature", label:'${currentValue}°F',
            [value: -1, color: "#0033ff"], //dark blue
            [value: 0, color: "#0033ff"], //dark blue
            [value: 3, color: "#00ccff"], //light blue?
            [value: 5, color: "#ffcc33"], //orange
            [value: 6, color: "#ff3300"], //red

    standardTile("tamper", "device.alarm") {
        state("secure", label:'secure',    icon:"st.locks.lock.locked",   backgroundColor:"#ffffff")
        state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
    valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
        state "battery", label:'${currentValue}% battery', unit:""
    standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
        state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
    //this will display a temperature tile for the DS18B20 sensor
    main(["temperature"])                        //COMMENT ME OUT IF NO TEMP INSTALLED
    details(["contact", "temperature", "battery"])            //COMMENT ME OUT IF NO TEMP INSTALLED
    //this will hide the temperature tile if the DS18B20 sensor is not installed
    //main(["contact"])                                        //UNCOMMENT ME IF NO TEMP INSTALLED
    //details(["contact", "battery"])                        //UNCOMMENT ME IF NO TEMP INSTALLED


// Parse incoming device messages to generate events
def parse(String description)
def result = []
def cmd = zwave.parse(description, [0x30: 1, 0x84: 1, 0x9C: 1, 0x70: 2, 0x80: 1, 0x72: 2, 0x56: 1, 0x60: 3])
if (cmd) {
result += zwaveEvent(cmd)
log.debug "parsed ‘$description’ to ${result.inspect()}"

def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
def versions = [0x30: 1, 0x84: 1, 0x9C: 1, 0x70: 2, 0x80: 1, 0x72: 2, 0x60: 3]
// def encapsulatedCommand = cmd.encapsulatedCommand(versions)
def version = versions[cmd.commandClass as Integer]
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(
if (!encapsulatedCommand) {
log.debug “Could not extract command from $cmd”
} else {
return zwaveEvent(encapsulatedCommand)

def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x30: 2, 0x31: 2]) // can specify command class versions here like in zwave.parse
log.debug (“Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}”)
if (encapsulatedCommand) {
return zwaveEvent(encapsulatedCommand)

def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
def event = createEvent(descriptionText: “${device.displayName} woke up”, isStateChange: false)
def cmds = []
if (!state.lastbat || now() - state.lastbat > 246060*1000) {
cmds << zwave.batteryV1.batteryGet().format()
} else {
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
[event, response(cmds)]

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd)
def map = [:]
switch (cmd.sensorType) {
case 1:
// temperature
def cmdScale = cmd.scale == 1 ? “F” : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale() = "temperature"

def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: “battery”, unit: “%” ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} has a low battery"
map.isStateChange = true
} else {
map.value = cmd.batteryLevel
state.lastbat = now()
[createEvent(map), response(zwave.wakeUpV1.wakeUpNoMoreInformation())]

def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv1.SensorBinaryReport cmd) {
def map = [:]
map.value = cmd.sensorValue ? “open” : "closed" = "contact"
if (map.value == “closed”) {
map.descriptionText = “$device.displayName is closed”
else {
map.descriptionText = “$device.displayName is open”

// added so UK (non-multichannel) and US device supported by same device file.
def sensorValueEvent(value) {
if (value) {
createEvent(name: “contact”, value: “open”, descriptionText: “$device.displayName is open”)
} else {
createEvent(name: “contact”, value: “closed”, descriptionText: “$device.displayName is closed”)

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd)

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd)

def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
def map = [:]
map.value = cmd.sensorState ? “tampered” : "secure" = "tamper"
if (map.value == “tampered”) {
map.descriptionText = “$device.displayName has been tampered with”
else {
map.descriptionText = “$device.displayName is secure”

def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.debug “Catchall reached for cmd: ${cmd.toString()}}”

def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) {
def result = []
log.debug “${device.displayName} parameter ‘${cmd.parameterNumber}’ with a byte size of ‘${cmd.size}’ is set to ‘${cmd.configurationValue}’”

if (cmd.parameterNumber == 15) {
    if (cmd.configurationValue[0] == 1) { //error in temp probe
        result << createEvent(name:"temperature", value:"-99")
    } else if (cmd.configurationValue[0] == 255) { //no temp probe
        result << createEvent(name:"temperature", value:"")
    result += response(zwave.batteryV1.batteryGet().format())  // send this after configure() runs


def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
def result = []

def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
log.debug "msr: $msr"
device.updateDataValue(["MSR", msr])
result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false)



  • Configures the device to settings needed by SmarthThings at device discovery time.

  • @param none

  • @return none
    def configure() {
    log.debug "Configuring Device…"
    def cmds = []
    cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format()
    // send associate to group 3 to get sensor data reported only to hub
    cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()

    // send associate to group 2 to get tamper alarm data reported
    cmds << zwave.associationV2.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()

// turn on the tamper alarm
cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 10, size: 1).format()
//cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()

// temperature change sensitivity
cmds << zwave.configurationV1.configurationSet(configurationValue: [4], parameterNumber: 12, size: 1).format()
//cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()

// remove group 1 association to stop redundant BasicSet
cmds << zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format()

// see if there is a temp probe on board and is it working
cmds << zwave.configurationV1.configurationGet(parameterNumber: 15).format()
delayBetween(cmds, 500)


//used to add “test” button for simulation of user changes to parameters
def test() {
def params = [paramNumber:10,value:1,size:1]
//zwave.wakeUpV1.wakeUpIntervalSet(seconds: 30, nodeid:zwaveHubNodeId).format()


  • This method will allow the user to update device parameters (behavior) from an app.
  • A “Zwave Tweaker” app will be developed as an interface to do this. Or the user can
  • write his/her own app to envoke this method. No type or value checking is done to
  • compare to what device capability or reaction. It is up to user to read OEM
  • documentation prio to envoking this method.

  • @param List[paramNumber:80,value:10,size:1]
  • @return none
    def updateZwaveParam(params) {
    if ( params ) {
    def pNumber = params.paramNumber
    def pSize = params.size
    def pValue = [params.value]
    log.debug "Make sure device is awake and in recieve mode"
    log.debug “Updating ${device.displayName} parameter number ‘${pNumber}’ with value ‘${pValue}’ with size of ‘${pSize}’”
    def cmds = []
    cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format()
    delayBetween(cmds, 1200)        



  • Sets all of available Fibaro parameters back to the device defaults except for what

  • SmartThings needs to support the stock functionality as released. This will be

  • called from the “Fibaro Tweaker” or user’s app.


  • @param none

  • @return none
    def resetParams2StDefaults() {
    log.debug "Resetting ${device.displayName} parameters to SmartThings compatible defaults"
    def cmds = []
    cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 2, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 7, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 9, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 10, size: 1).format() //ST Custom
    cmds << zwave.configurationV1.configurationSet(configurationValue: [4], parameterNumber: 12, size: 1).format() //St Custom
    cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 13, size: 1).format()
    cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 14, size: 1).format()

    delayBetween(cmds, 1200)


  • Lists all of available Fibaro parameters and thier current settings out to the

  • logging window in the IDE. This will be called from the “Fibaro Tweaker” or

  • user’s own app.


  • @param none

  • @return none
    def listCurrentParams() {
    log.debug "Listing of current parameter settings of ${device.displayName}"
    def cmds = []
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 1).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 3).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 5).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 7).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 9).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 13).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 14).format()
    cmds << zwave.configurationV1.configurationGet(parameterNumber: 15).format()

    delayBetween(cmds, 500)

(Fred Chavez) #2

Caught your post in the other thread. I’ll give it a try as well.

Thanks man,

(JJG) #3

A possibly different version of the Fibaro FGK-101 was initially one of the suspects, but actually it was completely innocent : the problem came solely from the SmartThings v2 Hub, which behaves differently from the v1 Hub (it now calls for CRC16 encoded responses from the FGK-101).
And since I did not have a v2 Hub myself, it took me way too long time to converge on the right culprit.
Thanks to nattyb for his patience and help debugging that issue.


I am still using a v1 hub. I do have a v2, but haven’t even opened it yet. I really think it may be the Fibaro itself, but that is totally a stab in the dark. You are much more knowledgeable than I am when it comes to this stuff!

(Fred Chavez) #5

I wanted to report back this code works but there is an odd quirk. Open/close works instantaneously. Temp updates work but they don’t come at regular intervals. The updates are every 4 minutes, but they don’t show up every 4 minutes. It seems they show up every 20 to 30.

This could totally be my system and not the code though. :expressionless:

Happy to keep helping you guys test. Just let me know what you’d like to look at.



Hmm, strange. On mine it does report every 4 minutes, sometimes it does go longer though. I do not know what would cause that. No need to help test, unless you’d really like to. I probably won’t make any changes unless someone finds a way to make it better. I’m a total amateur, I just kind of happened to stumble into creating this and wanted to share with the community if anyone found it helpful…

I seriously couldn’t tell anyone a single thing about coding, I just looked at several other codes and kind of copy and pasted to make this one, and guessed at a few other things and it happened to work out. Dumb luck. :grinning:

(Chris Fichter) #7

I believe if temperature changes it reports every 3 minutes or so. But if there is no temperature change it reports at like 4 hours or 3 hours.

(JJG) #8

The mystery deepens : I thought I had isolated the problem to the v2 Hub different behavior, but if you still have a v1 one…
Between the firmware updates of the Hubs and the possibly surreptitious firmware updates for the non-SmartThings Devices, the only thing which is sure is that upward compatibility is far from being guaranteed for custom Device Handlers.
Too bad we cannot only use SmartThings 100% reliable Handlers … :frowning:


Hello @nattyb. I wanted to see if you ever upgraded to a hub v2, and if so, how does your code work? I was going to give it a try to monitor my Chest Freezer during a brew fermentation. I appreciate the work you have done this far and look forward to your response.


I have had a v2 hub for probably 8 months, but haven’t migrated yet. It’s still sitting in the plastic wrap and I don’t know if I will take the time to do it or not.

I would think it would work without a problem. I would imagine some of the issues with the other codes were due to slight variations on the sensors purchased. Whether it was because they were purchased in other countries, or just different time periods. Total speculation on my part, though.


LOL… I hear you. For what is is worth, my V2 has become fairly stable over the last month, due to all the upgrades.

Hopefully it stays that way, because for the three months prior, it was rough

(EinarS) #12

Looks like a great piece of work :slight_smile:
Tried to read up, but could not find clear signs of using “momentary” switch and sceenes.
Parameter 14.

Did you play around with this?

(Chris Fichter) #13

@einars @geeji should be able to help you with any questions you have. I’m sure he’ll chime in here. ‘Fibaro Z-Wave FGK-101 Temperature & Door/Window Sensor’ Full Support Handler here’s the work that he did on his device handler. It works great.

(JJG) #14

@einars : no, sorry, I did not play with automatic “scenes” activation.
But Fibaro’s “scenes” are equivalent to SmartThings SmartApps, i.e. “macros”, so if you modify my FGK-101 Custom Handler to generate ad-hoc IN Alarm events, with a SmartApp listening and triggered by them, you should be able to achieve what you want.

Beware however that too many things in SmartThings do not precisely behave as (imprecisely) documented, and that the general SmartThings cloud stability is very poor (although somewhat improving recently), especially in relation with SmartApps activation, so you have better be prepared for lengthy debugging and “defensive programming” all the way…
You should be fine as long as you do not aim for any “mission critical” task, and no (major) damage will occur if a SmartApp is not triggered when it should, or is triggered out of sync.
Given the present state of the art, especially for SmartThings, Home Automation should be considered more as a hobby than as a life saver… :slight_smile:

(EinarS) #15

Thanks a lot @geeji and @chris2vic I got som digging to do :slight_smile:


How does this get applied? I copied the code and tried to insert it as a device handler, but it failed to save. I’d really like to have the temp show on my things page like you did, but will need more of a step by step sadly…

Thanks to any who’s willing to help

(JJG) #17

Sorry, saw your post too late.
Just in case you have not already found by yourself your answers, look at this post.
Note however that SmartThings custom Handlers programming is quite quirky, not really fit for programming beginners :frowning:


Thanks everyone, has anyone found a way to integrate the fibaro device handler with the new smartthings app?

In the new app the device simply says “checking status…” and that it cannot connect to the device


I haven’t had a chance to migrate to the new app, so I can’t offer much help. However, I’m afraid that custom handlers may not be fully functioning in the new app…