From 10fef276db10cbfe1c9a7e89dfa0b7573fbde956 Mon Sep 17 00:00:00 2001 From: marstorp Date: Thu, 10 Aug 2017 11:42:05 -0700 Subject: [PATCH 1/3] DVCSMP-2973 CT100/Honeywell Z-wave NullPointerException CT100/Honeywell Z-wave NullPointerException when changing mode Changed name of private method setThermostatMode(data) to setGetThermostatMode(data) and method setThermostatFanMode(data) to setGetThermostatFanMode(data) so that platform calls the exposed methods setThermostatMode(String value) setThermostatFanMode(String value) as these validates the argument against the supported modes and then calls the private methods. Also removed some of the leftshift operators that showed errors in Sumo logs. --- .../ct100-thermostat.groovy | 38 ++++++++----------- .../zwave-thermostat.groovy | 34 ++++++++--------- 2 files changed, 31 insertions(+), 41 deletions(-) diff --git a/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy b/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy index 5a53439..05680ab 100644 --- a/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy +++ b/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy @@ -101,9 +101,8 @@ metadata { def installed() { // Configure device - def cmds = [] - cmds << new physicalgraph.device.HubAction(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()) - cmds << new physicalgraph.device.HubAction(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format()) + def cmds = [new physicalgraph.device.HubAction(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()), + new physicalgraph.device.HubAction(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format())] sendHubCommand(cmds) runIn(3, "initialize", [overwrite: true]) // Allow configure command to be sent and acknowledged before proceeding } @@ -150,7 +149,6 @@ def parse(String description) def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiInstanceCmdEncap cmd) { def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 3]) - log.debug ("multiinstancev1.MultiInstanceCmdEncap: command from instance ${cmd.instance}: ${encapsulatedCommand}") if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) } @@ -341,7 +339,7 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSuppo if(cmd.auxiliaryemergencyHeat) { supportedModes << "emergency heat" } state.supportedModes = supportedModes - sendEvent(name: "supportedThermostatModes", value: supportedModes, isStateChange: true, displayed: false) + sendEvent(name: "supportedThermostatModes", value: supportedModes, displayed: false) } def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeSupportedReport cmd) { @@ -351,7 +349,7 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanMod if(cmd.circulation) { supportedFanModes << "circulate" } state.supportedFanModes = supportedFanModes - sendEvent(name: "supportedThermostatFanModes", value: supportedFanModes, isStateChange: true, displayed: false) + sendEvent(name: "supportedThermostatFanModes", value: supportedFanModes, displayed: false) } def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { @@ -377,7 +375,6 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { } def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { -log.debug "ManufacturerSpecificReport ${cmd}: value:${cmd}" if (cmd.manufacturerName) { updateDataValue("manufacturer", cmd.manufacturerName) } @@ -614,7 +611,7 @@ def updateThermostatSetpoint(setpoint, value) { * */ def ping() { log.debug "ping() called" - // Just get Operating State as it is not reported when it chnages and there's no need to flood more commands + // Just get Operating State as it is not reported when it changes and there's no need to flood more commands sendHubCommand(new physicalgraph.device.HubAction(zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format())) } @@ -624,7 +621,7 @@ def switchMode() { if (supportedModes) { def next = { supportedModes[supportedModes.indexOf(it) + 1] ?: supportedModes[0] } def nextMode = next(currentMode) - runIn(2, "setThermostatMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true]) } else { log.warn "supportedModes not defined" getSupportedModes() @@ -635,7 +632,7 @@ def switchToMode(nextMode) { def supportedModes = state.supportedModes if (supportedModes) { if (supportedModes.contains(nextMode)) { - runIn(2, "setThermostatMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true]) } else { log.debug("ThermostatMode $nextMode is not supported by ${device.displayName}") } @@ -657,7 +654,7 @@ def switchFanMode() { if (supportedFanModes) { def next = { supportedFanModes[supportedFanModes.indexOf(it) + 1] ?: supportedFanModes[0] } def nextMode = next(currentMode) - runIn(2, "setThermostatFanMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true]) } else { log.warn "supportedFanModes not defined" getSupportedFanModes() @@ -668,7 +665,7 @@ def switchToFanMode(nextMode) { def supportedFanModes = state.supportedFanModes if (supportedFanModes) { if (supportedFanModes.contains(nextMode)) { - runIn(2, "setThermostatFanMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true]) } else { log.debug("FanMode $nextMode is not supported by ${device.displayName}") } @@ -679,8 +676,7 @@ def switchToFanMode(nextMode) { } def getSupportedFanModes() { - def cmds = [] - cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format()) + def cmds = [new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format())] sendHubCommand(cmds) } @@ -696,10 +692,9 @@ def setThermostatMode(String value) { switchToMode(value) } -def setThermostatMode(data) { - def cmds = [] - cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[data.nextMode]).format()) - cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format()) +def setGetThermostatMode(data) { + def cmds = [new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[data.nextMode]).format()), + new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format())] sendHubCommand(cmds) } @@ -713,10 +708,9 @@ def setThermostatFanMode(String value) { switchToFanMode(value) } -def setThermostatFanMode(data) { - def cmds = [] - cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[data.nextMode]).format()) - cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format()) +def setGetThermostatFanMode(data) { + def cmds = [new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[data.nextMode]).format()), + new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format())] sendHubCommand(cmds) } diff --git a/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy b/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy index e7205e1..69290db 100644 --- a/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy +++ b/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy @@ -91,7 +91,7 @@ metadata { standardTile("raiseCoolSetpoint", "device.heatingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") { state "heatingSetpoint", action:"raiseCoolSetpoint", icon:"st.thermostat.thermostat-right" } - valueTile("thermostatOperatingState", "device.thermostatOperatingState", width: 2, height:1, decoration: "flat") { + standardTile("thermostatOperatingState", "device.thermostatOperatingState", width: 2, height:1, decoration: "flat") { state "thermostatOperatingState", label:'${currentValue}', backgroundColor:"#ffffff" } standardTile("refresh", "device.thermostatMode", width:2, height:1, inactiveLabel: false, decoration: "flat") { @@ -105,9 +105,8 @@ metadata { def installed() { // Configure device - def cmds = [] - cmds << new physicalgraph.device.HubAction(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()) - cmds << new physicalgraph.device.HubAction(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format()) + def cmds = [new physicalgraph.device.HubAction(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()), + new physicalgraph.device.HubAction(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format())] sendHubCommand(cmds) runIn(3, "initialize", [overwrite: true]) // Allow configure command to be sent and acknowledged before proceeding } @@ -505,7 +504,7 @@ def switchMode() { if (supportedModes) { def next = { supportedModes[supportedModes.indexOf(it) + 1] ?: supportedModes[0] } def nextMode = next(currentMode) - runIn(2, "setThermostatMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true]) } else { log.warn "supportedModes not defined" getSupportedModes() @@ -516,7 +515,7 @@ def switchToMode(nextMode) { def supportedModes = state.supportedModes if (supportedModes) { if (supportedModes.contains(nextMode)) { - runIn(2, "setThermostatMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true]) } else { log.debug("ThermostatMode $nextMode is not supported by ${device.displayName}") } @@ -538,7 +537,7 @@ def switchFanMode() { if (supportedFanModes) { def next = { supportedFanModes[supportedFanModes.indexOf(it) + 1] ?: supportedFanModes[0] } def nextMode = next(currentMode) - runIn(2, "setThermostatFanMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true]) } else { log.warn "supportedFanModes not defined" getSupportedFanModes() @@ -549,7 +548,7 @@ def switchToFanMode(nextMode) { def supportedFanModes = state.supportedFanModes if (supportedFanModes) { if (supportedFanModes.contains(nextMode)) { - runIn(2, "setThermostatFanMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true]) } else { log.debug("FanMode $nextMode is not supported by ${device.displayName}") } @@ -560,8 +559,7 @@ def switchToFanMode(nextMode) { } def getSupportedFanModes() { - def cmds = [] - cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format()) + def cmds = [new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format())] sendHubCommand(cmds) } @@ -577,10 +575,9 @@ def setThermostatMode(String value) { switchToMode(value) } -def setThermostatMode(data) { - def cmds = [] - cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[data.nextMode]).format()) - cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format()) +def setGetThermostatMode(data) { + def cmds = [new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[data.nextMode]).format()), + new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format())] sendHubCommand(cmds) } @@ -594,10 +591,9 @@ def setThermostatFanMode(String value) { switchToFanMode(value) } -def setThermostatFanMode(data) { - def cmds = [] - cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[data.nextMode]).format()) - cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format()) +def setGetThermostatFanMode(data) { + def cmds = [new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[data.nextMode]).format()), + new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format())] sendHubCommand(cmds) } @@ -663,7 +659,7 @@ def getTempInDeviceScale(temp, scale) { if (temp && scale) { def deviceScale = (state.scale == 1) ? "F" : "C" return (deviceScale == scale) ? temp : - (deviceScale == "F" ? celsiusToFahrenheit(temp) : roundC(fahrenheitToCelsius(temp))) + (deviceScale == "F" ? celsiusToFahrenheit(temp).toDouble().round(0).toInteger() : roundC(fahrenheitToCelsius(temp))) } return 0 } From eb9b55e01ceede4096e987f5bbd60ede0f3b709e Mon Sep 17 00:00:00 2001 From: Ingvar Marstorp Date: Thu, 10 Aug 2017 12:19:12 -0700 Subject: [PATCH 2/3] Update ct100-thermostat.groovy --- .../ct100-thermostat.src/ct100-thermostat.groovy | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy b/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy index 05680ab..94ed8a9 100644 --- a/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy +++ b/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy @@ -18,6 +18,7 @@ metadata { command "raiseHeatingSetpoint" command "lowerCoolSetpoint" command "raiseCoolSetpoint" + command "poll" fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60" fingerprint mfr:"0098", prod:"6401", model:"0107", deviceJoinName: "2Gig CT100 Programmable Thermostat" @@ -122,7 +123,7 @@ def initialize() { // Device-Watch simply pings if no device events received for 32min(checkInterval) sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) // Poll device for additional data that will be updated by refresh tile - poll() + pollDevice() } def parse(String description) @@ -386,6 +387,11 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS } } +def poll() { + // Call refresh which will cap the polling to once every 2 minutes + refresh() +} + def refresh() { // Only allow refresh every 2 minutes to prevent flooding the Zwave network def timeNow = now() @@ -394,11 +400,11 @@ def refresh() { // refresh will request battery, prevent multiple request by setting lastbatt now state.lastbatt = timeNow // use runIn with overwrite to prevent multiple DTH instances run before state.refreshTriggeredAt has been saved - runIn(2, "poll", [overwrite: true]) + runIn(2, "pollDevice", [overwrite: true]) } } -def poll() { +def pollDevice() { def cmds = [] cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSupportedGet().format()) cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format()) From 2b09b7c5741a197a046dfbd9e9aec9f51b645cc7 Mon Sep 17 00:00:00 2001 From: Ingvar Marstorp Date: Thu, 10 Aug 2017 12:23:50 -0700 Subject: [PATCH 3/3] Update zwave-thermostat.groovy --- .../zwave-thermostat.src/zwave-thermostat.groovy | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy b/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy index 69290db..c1f2fad 100644 --- a/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy +++ b/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy @@ -28,6 +28,7 @@ metadata { command "raiseHeatingSetpoint" command "lowerCoolSetpoint" command "raiseCoolSetpoint" + command "poll" fingerprint deviceId: "0x08" fingerprint inClusters: "0x43,0x40,0x44,0x31" @@ -128,7 +129,7 @@ def initialize() { if (getDataValue("manufacturer") != "Honeywell") { runEvery5Minutes("poll") // This is not necessary for Honeywell Z-wave, but could be for other Z-wave thermostats } - poll() + pollDevice() } def parse(String description) @@ -318,17 +319,22 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { } // Command Implementations +def poll() { + // Call refresh which will cap the polling to once every 2 minutes + refresh() +} + def refresh() { // Only allow refresh every 2 minutes to prevent flooding the Zwave network def timeNow = now() if (!state.refreshTriggeredAt || (2 * 60 * 1000 < (timeNow - state.refreshTriggeredAt))) { state.refreshTriggeredAt = timeNow // use runIn with overwrite to prevent multiple DTH instances run before state.refreshTriggeredAt has been saved - runIn(2, "poll", [overwrite: true]) + runIn(2, "pollDevice", [overwrite: true]) } } -def poll() { +def pollDevice() { def cmds = [] cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSupportedGet().format()) cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format())