/** * Sensibo Device Type Handler * * Copyright 2019 Bryan Li * * 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: * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. * * Date Comments * 2019-04-27 Based on work by Eric Gosselin - Modified for Hubitat * 2019-07-23 Merge robert1's logging changes * */ preferences { //Logging Message Config input name: "infoLogging", type: "bool", title: "Enable info message logging", description: "" input name: "debugLogging", type: "bool", title: "Enable debug message logging", description: "" input name: "traceLogging", type: "bool", title: "Enable trace message logging", description: "" } metadata { definition (name: "SensiboPod", namespace: "joyfulhouse", author: "Bryan Li", oauth: false) { capability "Relative Humidity Measurement" capability "Temperature Measurement" capability "Polling" capability "Refresh" capability "Switch" capability "Thermostat" capability "Battery" capability "Actuator" capability "Sensor" capability "Health Check" capability "Power Source" capability "Voltage Measurement" attribute "swing", "String" attribute "temperatureUnit","String" attribute "productModel","String" attribute "firmwareVersion","String" attribute "Climate","String" attribute "targetTemperature","Double" attribute "statusText","String" attribute "currentmode","String" attribute "fanLevel","String" attribute "on","String" // Added by request of NateG command "setAll" command "switchFanLevel" command "switchMode" command "raiseCoolSetpoint" command "lowerCoolSetpoint" command "raiseHeatSetpoint" command "lowerHeatSetpoint" command "voltage" command "raiseTemperature" command "lowerTemperature" command "switchSwing" command "modeSwing", [ [ name:"Swing Mode", type: "ENUM", description: "Pick an option", constraints: [ "fixedTop", "fixedMiddleTop", "fixedMiddle", "fixedMiddleBottom", "fixedBottom", "rangeTop", "rangeMiddle", "rangeBottom", "rangeFull", "horizontal", "both", "stopped" ] ] ] command "setThermostatMode" command "modeHeat" command "modeCool" command "modeDry" command "modeFan" command "modeAuto" command "lowfan" command "mediumlowfan" command "mediumfan" command "mediumhighfan" command "highfan" command "quietfan" command "strongfan" command "autofan" command "fullswing" command "setAirConditionerMode" command "toggleClimateReact" command "setClimateReact" command "configureClimateReact" } simulator { } tiles(scale: 2) { multiAttributeTile(name:"thermostatMulti", type:"thermostat",, width:6, height:4,canChangeIcon: false) { tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { attributeState ("default", label:'${currentValue}°')//, //backgroundColors:[ // [value: 15, color: "#153591"], // [value: 18, color: "#1e9cbb"], // [value: 21, color: "#90d2a7"], // [value: 24, color: "#44b621"], // [value: 27, color: "#f1d801"], // [value: 30, color: "#d04e00"], // [value: 33, color: "#bc2323"], // [value: 59, color: "#153591"], // [value: 64, color: "#1e9cbb"], // [value: 70, color: "#90d2a7"], // [value: 75, color: "#44b621"], // [value: 81, color: "#f1d801"], // [value: 86, color: "#d04e00"], // [value: 91, color: "#bc2323"] //]) } tileAttribute("device.targetTemperature", key: "VALUE_CONTROL") { attributeState("VALUE_UP", action: "raiseTemperature") attributeState("VALUE_DOWN", action: "lowerTemperature") } tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { attributeState("default", label:'${currentValue}%', unit:"%") } tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { attributeState("idle", backgroundColor:"#a9a9a9") attributeState("heating", backgroundColor:"#e86d13") attributeState("cooling", backgroundColor:"#00a0dc") attributeState("fan only", backgroundColor:"#44b621") attributeState("Dry", backgroundColor:"#A1E5E5") } tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") { attributeState("off", label:'${name}') attributeState("heat", label:'${name}') attributeState("cool", label:'${name}') attributeState("fan", label:'${name}') attributeState("dry", label:'${name}') attributeState("auto", label:'${name}') } tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { attributeState("default", label:'${currentValue}') } tileAttribute("device.coolingSetpoint", key: "COOLING_SETPOINT") { attributeState("default", label:'${currentValue}') } } valueTile("temperature", "device.temperature", width: 2, height: 2) { state("temperature", label:'Temp: ${currentValue}',backgroundColors:[]) } valueTile("humidity", "device.humidity", width: 2, height: 2) { state("humidity", label:'Humidity: ${currentValue} %', backgroundColors:[ ] ) } valueTile("voltage", "device.voltage", width: 1, height: 1) { state("voltage", label:'${currentValue}', backgroundColors:[ [value: 2700, color: "#CC0000"], [value: 2800, color: "#FFFF00"], [value: 2900, color: "#00FF00"] ] ) } valueTile("firmwareVersion", "device.firmwareVersion", width: 1, height: 1) { state("version", label:'Firmware: ${currentValue}',backgroundColors:[]) } valueTile("productModel", "device.productModel", width: 1, height: 1) { state("mains", label:'Model: ${currentValue}',backgroundColors:[]) } valueTile("powerSource", "device.powerSource", width: 1, height: 1) { state("mains", icon:"https://image.ibb.co/inKcN5/cable_power_cord_plug_circle_512.png", label:'Source: ${currentValue}',backgroundColors:[]) state("battery", icon:"https://image.ibb.co/gFUNpk/battery.jpg", label:'Source: ${currentValue}',backgroundColors:[]) } standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc" state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff" } standardTile("fanLevel", "device.fanLevel", width: 2, height: 2) { state "low", action:"switchFanLevel", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/gZxHpk/fan_low_2.png", nextState:"medium" state "medium", action:"switchFanLevel", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/cUa3Uk/fan_medium_2.png", nextState:"high" state "high", action:"switchFanLevel", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/fcfFaQ/fan_high_2.png", nextState:"auto" state "auto", action:"switchFanLevel", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/m8oq9k/fan_auto_2.png" , nextState:"quiet" state "quiet", action:"switchFanLevel", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/mC74wb/fan_quiet2.png" , nextState:"medium_high" state "medium_high", action:"switchFanLevel", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/j62DXR/fan_medium_3.png" , nextState:"medium_low" state "medium_low", action:"switchFanLevel", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/etX296/fan_low_3.png" , nextState:"strong" state "strong", action:"switchFanLevel", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/eaLeUw/fan_strong2.png" , nextState:"low" } standardTile("currentmode", "device.thermostatMode", width: 2, height: 2) { state "heat", action:"switchMode", backgroundColor:"#e86d13", icon:"https://image.ibb.co/c7Grh5/sun.png", nextState:"cool" state "cool", action:"switchMode", backgroundColor:"#00a0dc", icon:"https://image.ibb.co/bZ56FQ/cold.png", nextState:"fan" state "fan", action:"switchMode", backgroundColor:"#e8e3d8", icon:"https://image.ibb.co/n1dhpk/status_message_fan.png", nextState:"dry" state "dry", action:"switchMode", backgroundColor:"#e8e3d8", icon:"https://image.ibb.co/k2ZNpk/dry_mode.png", nextState:"auto" state "auto", action:"switchMode", backgroundColor:"#e8e3d8", icon:"https://image.ibb.co/dwaRh5/auto_mode.png", nextState:"heat" } standardTile("upCoolButtonControl", "device.targetTemperature", inactiveLabel: false, decoration: "flat", width: 1, height: 2) { state "setpoint", action:"raiseCoolSetpoint", icon:"st.thermostat.thermostat-up",label :"Up" } standardTile("downCoolButtonControl", "device.targetTemperature", inactiveLabel: false, decoration: "flat", width: 1, height: 2) { state "setpoint", action:"lowerCoolSetpoint", icon:"st.thermostat.thermostat-down", label :"Down" } standardTile("swing", "device.swing", width: 2, height: 2) { state "stopped", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/iWhvaQ/stopped.png", nextState:"fixedTop" state "fixedTop", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/nbV3Uk/fixedTop.png", nextState:"fixedMiddleTop" state "fixedMiddleTop", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/chbcpk/fixed_Middle_Top.png", nextState:"fixedMiddle" state "fixedMiddle", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/dxDe25/fixed_Middle.png", nextState:"fixedMiddleBottom" state "fixedMiddleBottom", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/ebZmh5/fixed_Middle_Bottom.png", nextState:"fixedBottom" state "fixedBottom", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/n2tCN5/fixed_Bottom.png", nextState:"rangeTop" state "rangeTop", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/gYQsN5/rangeTop.png", nextState:"rangeMiddle" state "rangeMiddle", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/dC1XN5/range_Middle.png", nextState:"rangeBottom" state "rangeBottom", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/csTOUk/range_Bottom.png", nextState:"rangeFull" state "rangeFull", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/hHK8vQ/range_Full.png", nextState:"horizontal" state "horizontal", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/cAGQ2G/range_Horizontal2.png", nextState:"both" state "both", action:"switchSwing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/dLUOpw/range_Both2.png", nextState:"stopped" } standardTile("Climate", "device.Climate", width: 2, height: 2) { state "on", label:'${name}', action:"toggleClimateReact", icon:"https://i.ibb.co/Z8ZzcHR/auto-fix-2.png", backgroundColor:"#00a0dc" state "off", label:'${name}', action:"toggleClimateReact", icon:"https://i.ibb.co/Z8ZzcHR/auto-fix-2.png", backgroundColor:"#ffffff" state "notdefined", label:'N/A', action:"toggleClimateReact", icon:"https://i.ibb.co/Z8ZzcHR/auto-fix-2.png", backgroundColor:"#e86d13" } standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label:"Refresh", action:"refresh.refresh", icon:"st.secondary.refresh" } standardTile("coolmode", "device.thermostatMode", width: 1, height: 1) { state "cool", action:"modeCool", backgroundColor:"#00a0dc", icon:"https://image.ibb.co/bZ56FQ/cold.png" } standardTile("heatmode", "device.thermostatMode", width: 1, height: 1) { state "heat", action:"modeHeat", backgroundColor:"#e86d13", icon:"https://image.ibb.co/c7Grh5/sun.png" } standardTile("drymode", "device.thermostatMode", width: 1, height: 1) { state "dry", action:"modeDry", backgroundColor:"#e8e3d8", icon:"https://image.ibb.co/k2ZNpk/dry_mode.png" } standardTile("fanmode", "device.thermostatMode", width: 1, height: 1) { state "fan", action:"modeFan", backgroundColor:"#e8e3d8", icon:"https://image.ibb.co/n1dhpk/status_message_fan.png" } standardTile("highfan", "device.fanLevel", width: 1, height: 1) { state "high", action:"highfan", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/fcfFaQ/fan_high_2.png" } standardTile("autofan", "device.fanLevel", width: 1, height: 1) { state "auto", action:"autofan", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/m8oq9k/fan_auto_2.png" } standardTile("fullswing", "device.swing", width: 1, height: 1) { state "rangeFull", action:"fullswing", backgroundColor:"#8C8C8D", icon:"https://image.ibb.co/hHK8vQ/range_Full.png" } main (["switch"]) details (["thermostatMulti","switch","fanLevel","currentmode","swing","Climate","refresh","coolmode","heatmode","fanmode","drymode","highfan","autofan","fullswing","firmwareVersion","productModel","powerSource","voltage"]) } } private def displayDebugLog(message) { if (debugLogging) log.debug "${device.displayName}: ${message}" } private def displayTraceLog(message) { if (traceLogging) log.trace "${device.displayName}: ${message}" } private def displayInfoLog(message) { if (infoLogging || state.prefsSetCount != 1) log.info "${device.displayName}: ${message}" } def setAll(newMode,temp,fan) { displayTraceLog( "setAll() called with " + newMode + "," + temp + "," + fan ) def Setpoint = temp.toInteger() def LevelBefore = fan def capabilities = parent.getCapabilities(device.deviceNetworkId,newMode) def Level = LevelBefore if (capabilities.remoteCapabilities != null) { def fanLevels = capabilities.remoteCapabilities.fanLevels displayDebugLog("Fan levels capabilities : " + capabilities.remoteCapabilities.fanLevels) Level = GetNextFanLevel(LevelBefore,capabilities.remoteCapabilities.fanLevels) displayDebugLog("Fan : " + Level) def result = parent.setACStates(this, device.deviceNetworkId, "on", newMode, Setpoint, Level, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { if (LevelBefore != Level) { generatefanLevelEvent(Level) } sendEvent(name: 'thermostatMode', value: newMode, displayed: false,isStateChange: true) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } generateModeEvent(newMode) generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } else { } } def lowfan() { displayTraceLog( "lowfan() called") dfanLevel("low") } def mediumlowfan() { displayTraceLog( "mediumlowfan() called") dfanLevel("medium_low") } def mediumfan() { displayTraceLog( "mediumfan() called") dfanLevel("medium") } def mediumhighfan() { displayTraceLog( "mediumhighfan() called") dfanLevel("medium_high") } def highfan() { displayTraceLog( "highfan() called") dfanLevel("high") } def quietfan() { displayTraceLog( "quietfan() called") dfanLevel("quiet") } def strongfan() { displayTraceLog( "strongfan() called") dfanLevel("strong") } def autofan() { displayTraceLog( "autofan() called") dfanLevel("auto") } def fullswing() { displayTraceLog( "fullswing() called") modeSwing("rangeFull") } def temperatureDown(temp) { displayTraceLog( "temperatureDown() called with "+ temp) def sunit = device.currentValue("temperatureUnit") def capabilities = parent.getCapabilities(device.deviceNetworkId, device.currentState("currentmode").value) def values if (sunit == "F") { if (capabilities.remoteCapabilities.temperatures.F == null) { return -1 } values = capabilities.remoteCapabilities.temperatures.F.values } else { if (capabilities.remoteCapabilities.temperatures.C == null) { return -1 } values = capabilities.remoteCapabilities.temperatures.C.values } def found = values.findAll{number -> number < temp} displayDebugLog("Values retrieved : " + found) if (found == null || found.empty) found = values.first() else found = found.last() displayDebugLog("Temp before : " + temp ) displayDebugLog("Temp after : " + found) temp = found return temp } def temperatureUp(temp) { displayTraceLog( "temperatureUp() called with "+ temp) def sunit = device.currentValue("temperatureUnit") def capabilities = parent.getCapabilities(device.deviceNetworkId, device.currentState("currentmode").value) def values if (sunit == "F") { if (capabilities.remoteCapabilities.temperatures.F == null) { return -1 } values = capabilities.remoteCapabilities.temperatures.F.values } else { if (capabilities.remoteCapabilities.temperatures.C == null) { return -1 } values = capabilities.remoteCapabilities.temperatures.C.values } def found = values.findAll{number -> number > temp} displayDebugLog("Values retrieved : " + found) if (found == null || found.empty) found = values.last() else found = found.first() displayDebugLog("Temp before : " + temp ) displayDebugLog("Temp after : " + found) temp = found return temp } void raiseTemperature() { displayTraceLog( "raiseTemperature() called" ) def operMode = device.currentState("currentmode").value def Setpoint = device.currentValue("targetTemperature").toInteger() def theTemp = device.currentValue("temperatureUnit") displayDebugLog("Current target temperature = ${Setpoint}") Setpoint = temperatureUp(Setpoint) if (Setpoint == -1) { return } switch (operMode) { case "heat": setHeatingSetpoint(Setpoint) break; case "cool": setCoolingSetpoint(Setpoint) break; case "fan": setFanSetpoint(Setpoint) break; case "dry": setDrySetpoint(Setpoint) break; case "auto": setHeatingSetpoint(Setpoint) setCoolingSetpoint(Setpoint) break; default: break; } } void lowerTemperature() { displayTraceLog( "lowerTemperature() called") def operMode = device.currentState("currentmode").value def Setpoint = device.currentValue("targetTemperature").toInteger() def theTemp = device.currentValue("temperatureUnit") displayDebugLog("Current target temperature = ${Setpoint}") Setpoint = temperatureDown(Setpoint) if (Setpoint == -1) { return } switch (operMode) { case "heat": setHeatingSetpoint(Setpoint) break; case "cool": setCoolingSetpoint(Setpoint) break; case "fan": setFanSetpoint(Setpoint) break; case "dry": setDrySetpoint(Setpoint) break; case "auto": setHeatingSetpoint(Setpoint) setCoolingSetpoint(Setpoint) break; default: break; } } void lowerCoolSetpoint() { displayTraceLog( "lowerCoolSetpoint() called") def Setpoint = device.currentValue("targetTemperature").toInteger() def theTemp = device.currentValue("temperatureUnit") displayDebugLog("Current target temperature = ${Setpoint}") Setpoint = temperatureDown(Setpoint) def result = parent.setACStates(this, device.deviceNetworkId , "on", device.currentState("currentmode").value, Setpoint, device.currentState("fanLevel").value, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "Cooling temperature changed to " + Setpoint + " for " + device.deviceNetworkId) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } sendEvent(name: 'coolingSetpoint', value: Setpoint, displayed: false) sendEvent(name: 'thermostatSetpoint', value: Setpoint, displayed: false) generateSetTempEvent(Setpoint) displayDebugLog("New target Temperature = ${Setpoint}") generateStatusEvent() refresh() } else { displayDebugLog("error") generateErrorEvent() generateStatusEvent() } } void setThermostatMode(modes) { displayTraceLog( "setThermostatMode() called") def currentMode = device.currentState("currentmode").value displayDebugLog("switching AC mode from current mode: $currentMode") switch (modes) { case "cool": modeCool() break //case "fan": // returnCommand = modeFan() // break //case "dry": // returnCommand = modeDry() // break case "auto": modeAuto() break case "heat": modeHeat() break case "off": off() break } } void setAirConditionerMode(modes) { displayTraceLog( "setAirConditionerMode() called") def currentMode = device.currentState("currentmode").value displayDebugLog("switching AC mode from current mode: $currentMode") switch (modes) { case "cool": modeCool() break case "fanOnly": case "fan": modeFan() break case "dry": modeDry() break case "auto": modeAuto() break case "heat": modeHeat() break } } void raiseCoolSetpoint() { displayTraceLog( "raiseCoolSetpoint() called") def Setpoint = device.currentValue("targetTemperature").toInteger() def theTemp = device.currentValue("temperatureUnit") displayDebugLog("Current target temperature = ${Setpoint}") Setpoint = temperatureUp(Setpoint) def result = parent.setACStates(this, device.deviceNetworkId , "on", device.currentState("currentmode").value, Setpoint, device.currentState("fanLevel").value, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "Cooling temperature changed to " + Setpoint + " for " + device.deviceNetworkId) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } sendEvent(name: 'coolingSetpoint', value: Setpoint, displayed: false) sendEvent(name: 'thermostatSetpoint', value: Setpoint, displayed: false) generateSetTempEvent(Setpoint) displayDebugLog("New target Temperature = ${Setpoint}") generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } void raiseHeatSetpoint() { displayTraceLog( "raiseHeatSetpoint() called") def Setpoint = device.currentValue("targetTemperature").toInteger() def theTemp = device.currentValue("temperatureUnit") displayDebugLog("Current target temperature = ${Setpoint}") Setpoint = temperatureUp(Setpoint) def result = parent.setACStates(this, device.deviceNetworkId , "on", device.currentState("currentmode").value, Setpoint, device.currentState("fanLevel").value, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "Heating temperature changed to " + Setpoint + " for " + device.deviceNetworkId) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } sendEvent(name: 'heatingSetpoint', value: Setpoint, displayed: false) sendEvent(name: 'thermostatSetpoint', value: Setpoint, displayed: false) generateSetTempEvent(Setpoint) displayDebugLog("New target Temperature = ${Setpoint}") generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } void lowerHeatSetpoint() { displayTraceLog( "lowerHeatSetpoint() called") def Setpoint = device.currentValue("targetTemperature").toInteger() def theTemp = device.currentValue("temperatureUnit") displayDebugLog("Current target temperature = ${Setpoint}") Setpoint = temperatureDown(Setpoint) def result = parent.setACStates(this, device.deviceNetworkId , "on", device.currentState("currentmode").value, Setpoint, device.currentState("fanLevel").value, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "Heating temperature changed to " + Setpoint + " for " + device.deviceNetworkId) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } sendEvent(name: 'heatingSetpoint', value: Setpoint, displayed: false) sendEvent(name: 'thermostatSetpoint', value: Setpoint, displayed: false) generateSetTempEvent(Setpoint) displayDebugLog("New target Temperature = ${Setpoint}") generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } def refresh() { displayTraceLog( "refresh() called") poll() displayTraceLog( "refresh() ended") } // Set Temperature def setFanSetpoint(temp) { displayTraceLog( "setFanSetpoint() called") temp = temp.toInteger() displayDebugLog("setTemperature : " + temp ) def result = parent.setACStates(this, device.deviceNetworkId , "on", "fan", temp, device.currentState("fanLevel").value, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "Fan temperature changed to " + temp + " for " + device.deviceNetworkId) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } generateModeEvent("fan") sendEvent(name: 'thermostatSetpoint', value: temp, displayed: false) generateSetTempEvent(temp) generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } // Set Temperature def setDrySetpoint(temp) { displayTraceLog( "setDrySetpoint() called") temp = temp.toInteger() displayDebugLog("setTemperature : " + temp ) def result = parent.setACStates(this, device.deviceNetworkId , "on", "dry", temp, device.currentState("fanLevel").value, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "Dry temperature changed to " + temp + " for " + device.deviceNetworkId) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } generateModeEvent("dry") sendEvent(name: 'thermostatSetpoint', value: temp, displayed: false) generateSetTempEvent(temp) generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } // Set Temperature def setCoolingSetpoint(temp) { displayTraceLog( "setCoolingSetpoint() called") temp = temp.toInteger() displayDebugLog("setTemperature : " + temp ) def result = parent.setACStates(this, device.deviceNetworkId , "on", "cool", temp, device.currentState("fanLevel").value, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "Cooling temperature changed to " + temp + " for " + device.deviceNetworkId) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } generateModeEvent("cool") sendEvent(name: 'coolingSetpoint', value: temp, displayed: false) sendEvent(name: 'thermostatSetpoint', value: temp, displayed: false) //sendEvent(name: 'heatingSetpoint', value: temp, displayed: false) generateSetTempEvent(temp) generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } def setHeatingSetpoint(temp) { displayTraceLog( "setHeatingSetpoint() called") temp = temp.toInteger() displayDebugLog("setTemperature : " + temp) def result = parent.setACStates(this, device.deviceNetworkId , "on", "heat", temp, device.currentState("fanLevel").value, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "Heating temperature changed to " + temp + " for " + device.deviceNetworkId) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } generateModeEvent("heat") //sendEvent(name: 'coolingSetpoint', value: temp, displayed: false) sendEvent(name: 'heatingSetpoint', value: temp, displayed: false) sendEvent(name: 'thermostatSetpoint', value: temp, displayed: false) generateSetTempEvent(temp) generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } def generateSetTempEvent(temp) { sendEvent(name: "targetTemperature", value: temp, descriptionText: "$device.displayName set temperature is now ${temp}", displayed: true, isStateChange: true) } // Turn off or Turn on the AC def on() { displayTraceLog( "on called") def Setpoint = device.currentValue("targetTemperature").toInteger() displayDebugLog("Temp Unit : " + device.currentState("temperatureUnit").value) def result = parent.setACStates(this, device.deviceNetworkId, "on", device.currentState("currentmode").value, Setpoint, device.currentState("fanLevel").value, device.currentState("swing").value, device.currentState("temperatureUnit").value) displayDebugLog("Result : " + result) if (result) { displayInfoLog( "AC turned ON for " + device.deviceNetworkId) sendEvent(name: 'thermostatMode', value: device.currentState("currentmode").value, displayed: false,isStateChange: true) //sendEvent(name: 'thermostatOperatingState', value: "idle",isStateChange: true) generateSwitchEvent("on") generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } def off() { displayTraceLog( "off called") def Setpoint = device.currentValue("targetTemperature").toInteger() displayDebugLog("Temp Unit : " + device.currentState("temperatureUnit").value) def result = parent.setACStates(this, device.deviceNetworkId, "off", device.currentState("currentmode").value, Setpoint, device.currentState("fanLevel").value, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "AC turned OFF for " + device.deviceNetworkId) sendEvent(name: 'thermostatMode', value: "off", displayed: false,isStateChange: true) //sendEvent(name: 'thermostatOperatingState', value: "idle",isStateChange: true) generateSwitchEvent("off") generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } def generateSwitchEvent(mode) { sendEvent(name: "on", value: mode, descriptionText: "$device.displayName is now ${mode}", displayed: false, isStateChange: true) sendEvent(name: "switch", value: mode, descriptionText: "$device.displayName is now ${mode}", displayed: true, isStateChange: true) //refresh() } def dfanLevel(String newLevel){ displayTraceLog( "dfanLevel called with fan = " + newLevel) def Setpoint = device.currentValue("targetTemperature").toInteger() def capabilities = parent.getCapabilities(device.deviceNetworkId, device.currentState("currentmode").value) def Level = LevelBefore if (capabilities.remoteCapabilities != null) { def fanLevels = capabilities.remoteCapabilities.fanLevels displayDebugLog("Fan levels capabilities : " + capabilities.remoteCapabilities.fanLevels) Level = GetNextFanLevel(newLevel,capabilities.remoteCapabilities.fanLevels) //displayDebugLog("Fan : " + Level) def result = parent.setACStates(this, device.deviceNetworkId,"on", device.currentState("currentmode").value, Setpoint, Level, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "Fan level changed to " + Level + " for " + device.deviceNetworkId) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } if (Level == "low") { sendEvent(name: 'thermostatFanMode', value: "circulate", displayed: false) } else { sendEvent(name: 'thermostatFanMode', value: "on", displayed: false) } generatefanLevelEvent(Level) generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } else { //TODO when the mode do not exist } } def generatefanLevelEvent(mode) { sendEvent(name: "fanLevel", value: mode, descriptionText: "$device.displayName fan level is now ${mode}", displayed: true, isStateChange: true) } // toggle Climate React def toggleClimateReact() { displayTraceLog( "toggleClimateReact() called") def currentClimateMode = device.currentState("Climate")?.value def returnCommand switch (currentClimateMode) { case "off": returnCommand = setClimateReact("on") break case "on": returnCommand = setClimateReact("off") break } if (!returnCommand) { returnCommand } } // Set Climate React def setClimateReact(ClimateState) { /////////////////////////////////////////////// /// Parameter ClimateState : "on" or "off" /////////////////////////////////////////////// displayTraceLog( "setClimateReact() called") displayDebugLog("Climate : " + ClimateState ) def result = parent.setClimateReact(this, device.deviceNetworkId, ClimateState) if (result) { displayInfoLog( "Climate React changed to " + ClimateState + " for " + device.deviceNetworkId) sendEvent(name: 'Climate', value: ClimateState, displayed: false) //generateSetTempEvent(temp) generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } def configureClimateReact(lowThres, highThres,stype,lowState,highState, on_off, ThresUnit) { /////////////////////////////////////////////// // lowThres and highThres - Integer parameters // stype : possible values are "temperature", "humidity" or "feelsLike" // lowState and highState : // on, fanLevel, temperatureUnit, targetTemperature, mode // // like "[true,'auto','C',21,'heat']" // to turn off AC,first parameters = false : "[false,'auto','C',21,'heat']" // one_off : boolean value to enable/disable the Climate React // unit : Passing F for Farenheit or C for Celcius // // Some examples: // // Range 19-24 Celcius, start to heat to 22 at auto fan if the temp is lower than 19 and stop the AC when higher than 24 // configureClimateReact(19, 24, ‘temperature’, ‘[true, ‘auto’, ‘C’, 22, ‘heat’]’, ‘[false, ‘auto’, ‘C’, 22, ‘heat’]’, true, ‘C’); // // Range 67-68 Farenheit, start to heat to 68 at auto fan if the temp is lower than 67 and stop the AC when higher than 68 // configureClimateReact(67, 68, ‘temperature’, ‘[true, ‘auto’, ‘F’, 68, ‘heat’]’, ‘[false, ‘auto’, ‘F’, 68, ‘heat’]’, true, ‘F’); // /////////////////////////////////////////////// displayTraceLog( "configureClimateReact() called") if (ThresUnit.toUpperCase() == "F") { lowThres = fToc(lowThres).round(1) highThres = fToc(highThres).round(1) } def json = new groovy.json.JsonBuilder() def lowStateMap = evaluate(lowState) def highStateMap = evaluate(highState) def lowStateJson def highStateJson if (lowStateMap) { lowStateJson = json { on lowStateMap[0] fanLevel lowStateMap[1] temperatureUnit lowStateMap[2] targetTemperature lowStateMap[3] mode lowStateMap[4] } } else { lowStateJson = null } if (highStateMap) { highStateJson = json { on highStateMap[0] fanLevel highStateMap[1] temperatureUnit highStateMap[2] targetTemperature highStateMap[3] mode highStateMap[4] } } else { highStateJson = null } def root = json { deviceUid device.deviceNetworkId highTemperatureWebhook null highTemperatureThreshold highThres lowTemperatureWebhook null type stype lowTemperatureState lowStateJson enabled on_off highTemperatureState highStateJson lowTemperatureThreshold lowThres } displayDebugLog("CLIMATE REACT STRING : " + JsonOutput.prettyPrint(json.toString())) def result = parent.configureClimateReact(this, device.deviceNetworkId, json.toString()) if (result) { displayInfoLog( "Climate React settings changed for " + device.deviceNetworkId) sendEvent(name: 'Climate', value: on_off, displayed: false) generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } def switchFanLevel() { displayTraceLog( "switchFanLevel() called") def currentFanMode = device.currentState("fanLevel")?.value displayDebugLog("switching fan level from current mode: $currentFanMode") def returnCommand switch (currentFanMode) { case "low": returnCommand = dfanLevel("medium") break case "medium": returnCommand = dfanLevel("high") break case "high": returnCommand = dfanLevel("auto") break case "auto": returnCommand = dfanLevel("quiet") break case "quiet": returnCommand = dfanLevel("medium_high") break case "medium_high": returnCommand = dfanLevel("medium_low") break case "medium_low": returnCommand = dfanLevel("strong") break case "strong": returnCommand = dfanLevel("low") break } returnCommand } def modeHeat() { displayTraceLog( "modeHeat() called") modeMode("heat") } def modeCool() { displayTraceLog( "modeCool() called") modeMode("cool") } def modeDry() { displayTraceLog( "modeDry() called") modeMode("dry") } def modeFan() { displayTraceLog( "modeFan() called") modeMode("fan") } def modeAuto() { displayTraceLog( "modeAuto() called") modeMode("auto") } // To change the AC mode def switchMode() { displayTraceLog( "switchMode() called") def currentMode = device.currentState("currentmode")?.value displayDebugLog("switching AC mode from current mode: $currentMode") def returnCommand switch (currentMode) { case "heat": returnCommand = modeMode("cool") break case "cool": returnCommand = modeMode("fan") break case "fan": returnCommand = modeMode("dry") break case "dry": returnCommand = modeMode("auto") break case "auto": returnCommand = modeMode("heat") break } returnCommand } def modeMode(String newMode){ displayTraceLog( "modeMode() called with " + newMode) def Setpoint = device.currentValue("targetTemperature").toInteger() def LevelBefore = device.currentState("fanLevel").value def capabilities = parent.getCapabilities(device.deviceNetworkId,newMode) def Level = LevelBefore if (capabilities.remoteCapabilities != null) { def fanLevels = capabilities.remoteCapabilities.fanLevels displayDebugLog("Fan levels capabilities : " + capabilities.remoteCapabilities.fanLevels) Level = GetNextFanLevel(LevelBefore,capabilities.remoteCapabilities.fanLevels) //displayDebugLog("Fan : " + Level) def result = parent.setACStates(this, device.deviceNetworkId, "on", newMode, Setpoint, Level, device.currentState("swing").value, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "Mode changed to " + newMode + " for " + device.deviceNetworkId) if (LevelBefore != Level) { generatefanLevelEvent(Level) } sendEvent(name: 'thermostatMode', value: newMode, displayed: false,isStateChange: true) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } generateModeEvent(newMode) generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } else { def themodes = parent.getCapabilities(device.deviceNetworkId,"modes") def sMode = GetNextMode(newMode,themodes) NextMode(sMode) } } def generateModeEvent(mode) { sendEvent(name: "thermostatMode", value: mode, descriptionText: "$device.displayName Thermostat mode is now ${mode}", displayed: true, isStateChange: true) } def returnNext(liste1, liste2, val) throws Exception { try { def index = liste2.indexOf(val) if (index == -1) throw new Exception() else return liste2[liste2.indexOf(val)] } catch(Exception e) { if (liste1.indexOf(val)+ 1 == liste1.size()) { val = liste1[0] } else { val = liste1[liste1.indexOf(val) + 1] } returnNext(liste1, liste2, val) } } def GetNextFanLevel(fanLevel, fanLevels) { displayTraceLog( "GetNextFanLevel called with " + fanLevel) if (fanLevels == null || fanLevels == "null") { return null } def listFanLevel = ['low','medium','high','auto','quiet','medium_high','medium_low','strong'] def newFanLevel = returnNext(listFanLevel, fanLevels,fanLevel) displayDebugLog("Next fanLevel = " + newFanLevel) return newFanLevel } def GetNextMode(mode, modes) { displayTraceLog( "GetNextMode called with " + mode) def listMode = ['heat','cool','fan','dry','auto'] def newMode = returnNext(listMode, modes,mode) displayDebugLog("Next Mode = " + newMode) return newMode } def NextMode(sMode) { displayTraceLog( "NextMode called()") if (sMode != null) { switch (sMode) { case "heat": modeHeat() break case "cool": modeCool() break case "fan": modeFan() break case "dry": modeDry() break case "auto": modeAuto() break } } else { return null } } def GetNextSwingMode(swingMode, swingModes){ displayTraceLog( "GetNextSwingMode() called with " + swingMode) if (swingModes == null || swingModes == "null") { return null } def listSwingMode = ['stopped','fixedTop','fixedMiddleTop','fixedMiddle','fixedMiddleBottom','fixedBottom','rangeTop','rangeMiddle','rangeBottom','rangeFull','horizontal','both'] def newSwingMode = returnNext(listSwingMode, swingModes,swingMode) displayDebugLog("Next Swing Mode = " + newSwingMode) return newSwingMode } def switchSwing() { displayTraceLog( "switchSwing() called") def currentMode = device.currentState("swing")?.value displayDebugLog("switching Swing mode from current mode: $currentMode") def returnCommand switch (currentMode) { case "stopped": returnCommand = modeSwing("fixedTop") break case "fixedTop": returnCommand = modeSwing("fixedMiddleTop") break case "fixedMiddleTop": returnCommand = modeSwing("fixedMiddle") break case "fixedMiddle": returnCommand = modeSwing("fixedMiddleBottom") break case "fixedMiddleBottom": returnCommand = modeSwing("fixedBottom") break case "fixedBottom": returnCommand = modeSwing("rangeTop") break case "rangeTop": returnCommand = modeSwing("rangeMiddle") break case "rangeMiddle": returnCommand = modeSwing("rangeBottom") break case "rangeBottom": returnCommand = modeSwing("rangeFull") break case "rangeFull": returnCommand = modeSwing("horizontal") break case "horizontal": returnCommand = modeSwing("both") break case "both": returnCommand = modeSwing("stopped") break } returnCommand } def modeSwing(String newSwing) { displayTraceLog( "modeSwing() called with " + newSwing) def Setpoint = device.currentValue("targetTemperature").toInteger() def SwingBefore = device.currentState("swing").value def capabilities = parent.getCapabilities(device.deviceNetworkId, device.currentState("currentmode").value) def Swing = SwingBefore if (capabilities.remoteCapabilities != null) { def Swings = capabilities.remoteCapabilities.swing displayDebugLog("Swing capabilities : " + capabilities.remoteCapabilities.swing) Swing = GetNextSwingMode(newSwing,capabilities.remoteCapabilities.swing) //displayDebugLog("Swing : " + Swing) def result = parent.setACStates(this, device.deviceNetworkId, "on", device.currentState("currentmode").value, Setpoint, device.currentState("fanLevel").value, Swing, device.currentState("temperatureUnit").value) if (result) { displayInfoLog( "Swing mode changed to " + Swing + " for " + device.deviceNetworkId) sendEvent(name: 'swing', value: Swing, displayed: false,isStateChange: true) if (device.currentState("on").value == "off") { generateSwitchEvent("on") } sendEvent(name: 'thermostatFanMode', value: "on", displayed: false) generateSwingModeEvent(Swing) generateStatusEvent() refresh() } else { generateErrorEvent() generateStatusEvent() } } else { //TODO } } def generateSwingModeEvent(mode) { sendEvent(name: "swing", value: mode, descriptionText: "$device.displayName swing mode is now ${mode}", displayed: true, isStateChange: true) } def generateErrorEvent() { displayDebugLog("$device.displayName FAILED to set the AC State") sendEvent(name: "Error", value: "Error", descriptionText: "$device.displayName FAILED to set or get the AC State", displayed: true, isStateChange: true) } void poll() { displayTraceLog( "Executing 'poll' using parent SmartApp") def results = parent.pollChild(this) def linkText = getLinkText(device) parseTempUnitEventData(results) parseEventData(results) } def parseTempUnitEventData(Map results) { displayDebugLog("parsing data $results") if(results) { results.each { name, value -> if (name=="temperatureUnit") { def linkText = getLinkText(device) def isChange = true def isDisplayed = false sendEvent( name: name, value: value, //unit: value, linkText: linkText, descriptionText: "${name} = ${value}", handlerName: "temperatureUnit", isStateChange: isChange, displayed: isDisplayed) } } } } def parseEventData(Map results) { displayDebugLog("parsing Event data $results") if(results) { results.each { name, value -> displayDebugLog("name :" + name + " value :" + value) def linkText = getLinkText(device) def isChange = false def isDisplayed = true if (name=="voltage") { isChange = true //isTemperatureStateChange(device, name, value.toString()) isDisplayed = false sendEvent( name: name, value: value, unit: "mA", linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } else if (name== "battery") { isChange = true //isTemperatureStateChange(device, name, value.toString()) isDisplayed = false sendEvent( name: name, value: value, //unit: "V", linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } else if (name== "powerSource") { isChange = true //isTemperatureStateChange(device, name, value.toString()) isDisplayed = false sendEvent( name: name, value: value, linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } else if (name== "Climate") { isChange = true isDisplayed = false sendEvent( name: name, value: value, linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } else if (name=="on") { isChange = true isDisplayed = false sendEvent( name: name, value: value, linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) sendEvent(name: "switch", value: value) } else if (name=="thermostatMode") { isChange = true //isTemperatureStateChange(device, name, value.toString()) isDisplayed = false if (value=="cool") { sendEvent(name: 'airConditionerMode', value: "cool", isStateChange: isChange, displayed: isDisplayed) sendEvent(name: 'thermostatOperatingState', value: "cooling", isStateChange: isChange, displayed: isDisplayed) } else if (value=="heat") { sendEvent(name: 'airConditionerMode', value: "heat", isStateChange: isChange, displayed: isDisplayed) sendEvent(name: 'thermostatOperatingState', value: "heating", isStateChange: isChange, displayed: isDisplayed) } else if (value=="fan") { sendEvent(name: 'airConditionerMode', value: "fanOnly", isStateChange: isChange, displayed: isDisplayed) sendEvent(name: 'thermostatOperatingState', value: "fan only", isStateChange: isChange, displayed: isDisplayed) } else if (value=="dry") { sendEvent(name: 'airConditionerMode', value: "dry", isStateChange: isChange, displayed: isDisplayed) sendEvent(name: 'thermostatOperatingState', value: "dry", isStateChange: isChange, displayed: isDisplayed) } else if (value=="auto") { sendEvent(name: 'airConditionerMode', value: "auto", isStateChange: isChange, displayed: isDisplayed) sendEvent(name: 'thermostatOperatingState', value: "auto", isStateChange: isChange, displayed: isDisplayed) } else { sendEvent(name: 'thermostatOperatingState', value: "idle", isStateChange: isChange, displayed: isDisplayed) } sendEvent( name: name, value: value, linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } else if (name=="coolingSetpoint" || name== "heatingSetpoint" || name == "thermostatSetpoint") { isChange = true //isTemperatureStateChange(device, name, value.toString()) isDisplayed = false sendEvent( name: name, value: value, //unit : device.currentValue("temperatureUnit"), linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } else if (name=="temperatureUnit") { isChange = true isDisplayed = false sendEvent( name: name, value: value, //unit: value, linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } else if (name=="thermostatFanMode") { def mode = (value.toString() == "high" || value.toString() == "medium") ? "on" : value.toString() mode = (mode == "low") ? "circulate" : mode isChange = true //isTemperatureStateChange(device, name, value.toString()) isDisplayed = false sendEvent( name: name, value: value, linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } else if (name=="swing") { isChange = true //isTemperatureStateChange(device, name, value.toString()) isDisplayed = false sendEvent( name: name, value: value, linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } else if (name=="temperature" || name== "lastTemperaturePush" || name== "lastHumidityPush") { isChange = true //isTemperatureStateChange(device, name, value.toString()) isDisplayed = false sendEvent( name: name, value: value, //unit: device.currentValue("temperatureUnit"), linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } else if (name=="humidity") { isChange = true //isTemperatureStateChange(device, name, value.toString()) isDisplayed = false sendEvent( name: name, value: value, linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } else { isChange = true//isStateChange(device, name, value.toString()) isDisplayed = false//isChange sendEvent( name: name, value: value.toString(), linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText), handlerName: name, isStateChange: isChange, displayed: isDisplayed) } } generateStatusEvent () } } private getThermostatDescriptionText(name, value, linkText) { if(name == "temperature") { return "$name was $value " + device.currentState("temperatureUnit").value } else if(name == "humidity") { return "$name was $value %" } else if(name == "targetTemperature") { return "latest temperature setpoint was $value " + device.currentState("temperatureUnit").value } else if(name == "fanLevel") { return "latest fan level was $value" } else if(name == "on") { return "latest switch was $value" } else if (name == "mode") { return "thermostat mode was ${value}" } else if (name == "currentmode") { return "thermostat mode was ${value}" } else if (name == "powerSource") { return "power source mode was ${value}" } else if (name == "Climate") { return "Climate React was ${value}" } else if (name == "thermostatMode") { return "thermostat mode was ${value}" } else if (name == "temperatureUnit") { return "thermostat unit was ${value}" } else if (name == "voltage") { return "Battery voltage was ${value}" } else if (name == "battery") { return "Battery was ${value}" } else if (name == "voltage" || name== "battery") { return "Battery voltage was ${value}" } else if (name == "swing") { return "Swing mode was ${value}" } else if (name == "Error") { def str = (value == "Failed") ? "failed" : "success" return "Last setACState was ${str}" } else { return "${name} = ${value}" } } // parse events into attributes def parse(String description) { displayDebugLog("Parsing '${description}'") def name = null def value = null def statusTextmsg = "" def msg = parseLanMessage(description) def headersAsString = msg.header // => headers as a string def headerMap = msg.headers // => headers as a Map def body = msg.body // => request body as a string def status = msg.status // => http status code of the response def json = msg.json // => any JSON included in response body, as a data structure of lists and maps def xml = msg.xml // => any XML included in response body, as a document tree structure def data = msg.data // => either JSON or XML in response body (whichever is specified by content-type header in response) if (description?.startsWith("on/off:")) { displayDebugLog("Switch command") name = "switch" value = description?.endsWith(" 1") ? "on" : "off" } else if (description?.startsWith("temperature")) { displayDebugLog("Temperature") name = "temperature" value = device.currentValue("temperature") } else if (description?.startsWith("humidity")) { displayDebugLog("Humidity") name = "humidity" value = device.currentValue("humidity") } else if (description?.startsWith("targetTemperature")) { displayDebugLog("targetTemperature") name = "targetTemperature" value = device.currentValue("targetTemperature") } else if (description?.startsWith("fanLevel")) { displayDebugLog("fanLevel") name = "fanLevel" value = device.currentValue("fanLevel") } else if (description?.startsWith("currentmode")) { displayDebugLog("mode") name = "currentmode" value = device.currentValue("currentmode") } else if (description?.startsWith("on")) { displayDebugLog("on") name = "on" value = device.currentValue("on") } else if (description?.startsWith("switch")) { displayDebugLog("switch") name = "switch" value = device.currentValue("on") } else if (description?.startsWith("temperatureUnit")) { displayDebugLog("temperatureUnit") name = "temperatureUnit" value = device.currentValue("temperatureUnit") } else if (description?.startsWith("Error")) { displayDebugLog("Error") name = "Error" value = device.currentValue("Error") } else if (description?.startsWith("voltage")) { displayDebugLog("voltage") name = "voltage" value = device.currentValue("voltage") } else if (description?.startsWith("battery")) { displayDebugLog("battery") name = "battery" value = device.currentValue("battery") } else if (description?.startsWith("swing")) { displayDebugLog("swing") name = "swing" value = device.currentValue("swing") } def result = createEvent(name: name, value: value) displayDebugLog("Parse returned ${result?.descriptionText}") return result } def generateStatusEvent() { def temperature = device.currentValue("temperature").toDouble() def humidity = device.currentValue("humidity").toDouble() def targetTemperature = device.currentValue("targetTemperature").split(' ')[0].toDouble() def fanLevel = device.currentValue("fanLevel") def mode = device.currentValue("currentmode") def on = device.currentValue("on") def swing = device.currentValue("swing") def ClimateReact = device.currentValue("Climate") def error = device.currentValue("Error") def statusTextmsg = "" def sUnit = device.currentValue("temperatureUnit") statusTextmsg = "${humidity}%" sendEvent("name":"statusText", "value":statusTextmsg, "description":"", displayed: false, isStateChange: true) } def fToc(temp) { return ((temp - 32) / 1.8).toDouble() } def ping(){ displayTraceLog( "calling parent ping()") return parent.ping() }