-
-
Save tylerlange/61f29f852930a68948e9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Zen Thermostat | |
* | |
* Author: Zen Within | |
* Date: 2015-02-21 | |
*/ | |
metadata { | |
// Automatically generated. Make future change here. | |
definition (name: "Zen Thermostat", namespace: "zenwithin", author: | |
"ZenWithin") { | |
capability "Actuator" | |
//capability "Temperature Measurement" | |
capability "Thermostat" | |
capability "Configuration" | |
capability "Refresh" | |
capability "Sensor" | |
fingerprint profileId: "0104", endpointId: "01", inClusters: | |
"0000,0001,0003,0004,0005,0020,0201,0202,0204,0B05", outClusters: "000A, | |
0019" | |
attribute "temperatureUnit", "number" | |
command "setpointUp" | |
command "setpointDown" | |
command "setCelsius" | |
command "setFahrenheit" | |
} | |
// simulator metadata | |
simulator { } | |
tiles { | |
valueTile("frontTile", "device.temperature", width: 1, height: 1) { | |
state("temperature", label:'${currentValue}=C2=B0', | |
backgroundColor:"#e8e3d8") | |
} | |
valueTile("temperature", "device.temperature", width: 1, height: 1) | |
{ | |
state("temperature", label:'${currentValue}=C2=B0', | |
backgroundColor:"#0A1E2C") | |
} | |
standardTile("fanMode", "device.thermostatFanMode") { | |
state "fanAuto", action:"thermostat.setThermostatFanMode", | |
backgroundColor:"#e8e3d8", icon:"st.thermostat.fan-auto" | |
state "fanOn", action:"thermostat.setThermostatFanMode", | |
backgroundColor:"#e8e3d8", icon:"st.thermostat.fan-on" | |
} | |
standardTile("temperatureUnit", "device.temperatureUnit") { | |
state "C", label: "=C2=B0C", icon: "st.alarm.temperature.normal= | |
", | |
action:"setFahrenheit" | |
state "F", label: "=C2=B0F", icon: "st.alarm.temperature.norma= | |
l", | |
action:"setCelsius" | |
} | |
standardTile("mode", "device.thermostatMode") { | |
state "off", action:"thermostat.setThermostatMode", | |
backgroundColor:"#e8e3d8", icon:"st.thermostat.heating-cooling-off" | |
state "cool", action:"thermostat.setThermostatMode", | |
backgroundColor:"#90d0e8", icon:"st.thermostat.cool" | |
state "heat", action:"thermostat.setThermostatMode", | |
backgroundColor:"#ff6e7e", icon:"st.thermostat.heat" | |
//state "auto", action:"thermostat.setThermostatMode", | |
backgroundColor:"#e8e3d8", icon:"st.thermostat.auto" | |
} | |
valueTile("thermostatSetpoint", "device.thermostatSetpoint", width: | |
2, height: 2) { | |
state "off", label:'${currentValue}=C2=B0', unit: "C", | |
backgroundColor:"#e8e3d8" | |
state "heat", label:'${currentValue}=C2=B0', unit: "C", | |
backgroundColor:"#e8e3d8" | |
state "cool", label:'${currentValue}=C2=B0', unit: "C", | |
backgroundColor:"#e8e3d8" | |
} | |
valueTile("heatingSetpoint", "device.heatingSetpoint", | |
inactiveLabel: false, decoration: "flat") { | |
state "heat", label:'${currentValue}=C2=B0 heat', unit:"F", | |
backgroundColor:"#ffffff" | |
} | |
valueTile("coolingSetpoint", "device.coolingSetpoint", | |
inactiveLabel: false, decoration: "flat") { | |
state "cool", label:'${currentValue}=C2=B0 cool', unit:"F", | |
backgroundColor:"#ffffff" | |
} | |
standardTile("setpointUp", "device.thermostatSetpoint") { | |
state "setpointUp", action:"setpointUp", | |
icon:"st.thermostat.thermostat-up" | |
} | |
standardTile("setpointDown", "device.thermostatSetpoint") { | |
state "setpointDown", action:"setpointDown", | |
icon:"st.thermostat.thermostat-down" | |
} | |
standardTile("refresh", "device.temperature") { | |
state "default", action:"refresh.refresh", | |
icon:"st.secondary.refresh" | |
} | |
standardTile("configure", "device.configure") { | |
state "configure", label:'', action:"configuration.configure", | |
icon:"st.secondary.configure" | |
} | |
main "frontTile" | |
details(["temperature", "fanMode", "mode", "thermostatSetpoint", | |
"setpointUp", "setpointDown", "temperatureUnit", "refresh", "configure"]) | |
} | |
} | |
// parse events into attributes | |
def parse(String description) { | |
log.debug "Parse description $description" | |
def map =3D [:] | |
def activeSetpoint =3D null | |
if (description?.startsWith("read attr -")) | |
{ | |
def descMap =3D parseDescriptionAsMap(description) | |
// Thermostat Cluster Attribute Read Response | |
if (descMap.cluster =3D=3D "0201" && descMap.attrId =3D=3D "0000") | |
{ | |
map.name =3D "temperature" | |
map.value =3D getTemperature(descMap.value) | |
} | |
else if (descMap.cluster =3D=3D "0201" && descMap.attrId =3D=3D "00= | |
1c") | |
{ | |
map.name =3D "thermostatMode" | |
map.value =3D getModeMap()[descMap.value] | |
if (map.value =3D=3D "cool") { | |
activeSetpoint =3D device.currentValue("coolingSetpoint") | |
} else if (map.value =3D=3D "heat") { | |
activeSetpoint =3D device.currentValue("heatingSetpoint") | |
} | |
sendEvent("name":"thermostatSetpoint", "value":activeSetpoint) | |
} | |
else if (descMap.cluster =3D=3D "0201" && descMap.attrId =3D=3D "00= | |
11") | |
{ | |
log.debug "COOL SET POINT" | |
map.name =3D "coolingSetpoint" | |
map.value =3D getTemperature(descMap.value) | |
if (device.currentState("thermostatMode")?.value =3D=3D "cool")= | |
{ | |
activeSetpoint =3D map.value | |
log.debug "Active set point value: $activeSetpoint" | |
sendEvent("name":"thermostatSetpoint", "value":activeSetpoint) | |
} | |
} | |
else if (descMap.cluster =3D=3D "0201" && descMap.attrId =3D=3D "00= | |
12") | |
{ | |
log.debug "HEAT SET POINT" | |
map.name =3D "heatingSetpoint" | |
map.value =3D getTemperature(descMap.value) | |
if (device.currentState("thermostatMode")?.value =3D=3D "heat")= | |
{ | |
activeSetpoint =3D map.value | |
sendEvent("name":"thermostatSetpoint", "value":activeSetpoint) | |
} | |
} | |
// Fan Controll Cluster Attribute Read Response | |
else if (descMap.cluster =3D=3D "0202" && descMap.attrId =3D=3D "00= | |
00") | |
{ | |
map.name =3D "thermostatFanMode" | |
map.value =3D getFanModeMap()[descMap.value] | |
} | |
else if (descMap.cluster =3D=3D "0204" && descMap.attrId =3D=3D "00= | |
00") | |
{ | |
map.name =3D "temperatureUnit" | |
map.value =3D getTemperatureDisplayModeMap()[descMap.value] | |
} | |
}// End of Read Attribute Response | |
def result =3D null | |
if (map) { | |
result =3D createEvent(map) | |
} | |
log.debug "Parse returned $map" | |
return result | |
} | |
// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Help Functions - Don't use= | |
log.debug in all these | |
functins =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D | |
def parseDescriptionAsMap(description) { | |
(description - "read attr - ").split(",").inject([:]) { map, param -> | |
def nameAndValue =3D param.split(":") | |
map +=3D [(nameAndValue[0].trim()):nameAndValue[1].trim()] | |
} | |
} | |
def getModeMap() { [ | |
"00":"off", | |
"03":"cool", | |
"04":"heat", | |
]} | |
def getFanModeMap() { [ | |
"04":"fanOn", | |
"05":"fanAuto" | |
]} | |
def getTemperatureDisplayModeMap() { [ | |
"00":"C", | |
"01":"F" | |
]} | |
def getTemperature(value) | |
{ | |
def celsius =3D Integer.parseInt(value, 16) / 100 | |
def returnValue =3D celsius | |
if(getTemperatureScale() =3D=3D "F"){ | |
returnValue =3D Math.round(celsiusToFahrenheit(celsius)) | |
} | |
return returnValue | |
} | |
def getTemperatureScale(){ | |
return device.currentState("temperatureUnit")?.value | |
} | |
// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Setpoints =3D=3D=3D=3D=3D= | |
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D | |
def setpointUp() | |
{ | |
def currentMode =3D device.currentState("thermostatMode")?.value | |
def currentUnit =3D getTemperatureScale() | |
// check if heating or cooling setpoint needs to be changed | |
int nextLevel =3D device.currentValue("thermostatSetpoint") + 1 | |
log.debug "Next level: $nextLevel" | |
// check the limits | |
if(currentUnit =3D=3D "C") | |
{ | |
if (currentMode =3D=3D "cool") | |
{ | |
if(nextLevel > 36) | |
{ | |
nextLevel =3D 36 | |
} | |
} else if (currentMode =3D=3D "heat") | |
{ | |
if(nextLevel > 32) | |
{ | |
nextLevel =3D 32 | |
} | |
} | |
} | |
else //in degF unit | |
{ | |
if (currentMode =3D=3D "cool") | |
{ | |
if(nextLevel > 96) | |
{ | |
nextLevel =3D 96 | |
} | |
} else if (currentMode =3D=3D "heat") | |
{ | |
if(nextLevel > 89) | |
{ | |
nextLevel =3D 89 | |
} | |
} | |
} | |
log.debug "setpointUp() - mode: ${currentMode} unit: ${currentUnit} | |
value: ${nextLevel}" | |
setSetpoint(nextLevel) | |
} | |
def setpointDown() | |
{ | |
def currentMode =3D device.currentState("thermostatMode")?.value | |
def currentUnit =3D getTemperatureScale() | |
// check if heating or cooling setpoint needs to be changed | |
int nextLevel =3D device.currentValue("thermostatSetpoint") - 1 | |
// check the limits | |
if (currentUnit =3D=3D "C") | |
{ | |
if (currentMode =3D=3D "cool") | |
{ | |
if(nextLevel < 8) | |
{ | |
nextLevel =3D 8 | |
} | |
} else if (currentMode =3D=3D "heat") | |
{ | |
if(nextLevel < 10) | |
{ | |
nextLevel =3D 10 | |
} | |
} | |
} | |
else //in degF unit | |
{ | |
if (currentMode =3D=3D "cool") | |
{ | |
if (nextLevel < 47) | |
{ | |
nextLevel =3D 47 | |
} | |
} else if (currentMode =3D=3D "heat") | |
{ | |
if (nextLevel < 50) | |
{ | |
nextLevel =3D 50 | |
} | |
} | |
} | |
log.debug "setpointDown() - mode: ${currentMode} unit: ${currentUnit} | |
value: ${nextLevel}" | |
setSetpoint(nextLevel) | |
} | |
def setSetpoint(degrees) | |
{ | |
def temperatureScale =3D getTemperatureScale() | |
def currentMode =3D device.currentState("thermostatMode")?.value | |
def degreesInteger =3D degrees as Integer | |
sendEvent("name":"thermostatSetpoint", "value":degreesInteger) | |
def celsius =3D (getTemperatureScale() =3D=3D "C") ? degreesInteger : | |
(fahrenheitToCelsius(degreesInteger) as Double).round(2) | |
if (currentMode =3D=3D "cool") { | |
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x11 0x29 {" + | |
hex(celsius*100) + "}" | |
} | |
else if (currentMode =3D=3D "heat") { | |
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + | |
hex(celsius*100) + "}" | |
} | |
} | |
// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Thermostat Mode =3D=3D=3D= | |
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D | |
def modes() { | |
["off", "heat", "cool"] | |
} | |
def setThermostatMode() | |
{ | |
def currentMode =3D device.currentState("thermostatMode")?.value | |
def modeOrder =3D modes() | |
def index =3D modeOrder.indexOf(currentMode) | |
def next =3D index >=3D 0 && index < modeOrder.size() - 1 ? modeOrder[i= | |
ndex | |
+ 1] : modeOrder[0] | |
log.debug "setThermostatMode - switching from $currentMode to $next" | |
"$next"() | |
} | |
def setThermostatMode(String value) { | |
"$value"() | |
} | |
def off() { | |
sendEvent("name":"thermostatMode", "value":"off") | |
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {00}" | |
} | |
def cool() { | |
def coolingSetpoint =3D device.currentValue("coolingSetpoint") | |
log.debug "Cool set point: $coolingSetpoint" | |
sendEvent("name":"thermostatMode", "value":"cool") | |
sendEvent("name":"thermostatSetpoint","value":coolingSetpoint) | |
[ | |
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {03}", "delay | |
800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x11" | |
] | |
} | |
def heat() { | |
def heatingSetpoint =3D device.currentValue("heatingSetpoint") | |
log.debug "Heat set point: $heatingSetpoint" | |
sendEvent("name":"thermostatMode","value":"heat") | |
sendEvent("name":"thermostatSetpoint","value":heatingSetpoint) | |
[ | |
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {04}", "delay | |
800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x12" | |
] | |
} | |
// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Fan Mode =3D=3D=3D=3D=3D= | |
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D | |
def setThermostatFanMode() | |
{ | |
def currentFanMode =3D device.currentState("thermostatFanMode")?.value | |
def returnCommand | |
switch (currentFanMode) { | |
case "fanAuto": | |
returnCommand =3D fanOn() | |
break | |
case "fanOn": | |
returnCommand =3D fanAuto() | |
break | |
} | |
if(!currentFanMode) { | |
returnCommand =3D fanAuto() | |
} | |
log.debug "setThermostatFanMode - switching from $currentFanMode to | |
$returnCommand" | |
returnCommand | |
} | |
def setThermostatFanMode(String value) { | |
"$value"() | |
} | |
def on() { | |
fanOn() | |
} | |
def fanOn() { | |
sendEvent("name":"thermostatFanMode", "value":"fanOn") | |
"st wattr 0x${device.deviceNetworkId} 1 0x202 0 0x30 {04}" | |
} | |
def auto() { | |
fanAuto() | |
} | |
def fanAuto() { | |
sendEvent("name":"thermostatFanMode", "value":"fanAuto") | |
"st wattr 0x${device.deviceNetworkId} 1 0x202 0 0x30 {05}" | |
} | |
// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Display Unit - degF or deg= | |
C =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D | |
def setFahrenheit() | |
{ | |
// Update Display Unit | |
sendEvent("name":"temperatureUnit", "value":"F") | |
// send zigbee command | |
[ | |
"raw 0x0020 {11 00 02 02 00 00 00}", "delay 100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500", | |
"st wattr 0x${device.deviceNetworkId} 1 0x204 0 0x30 {01}", "delay | |
800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0", "delay 800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x11", "delay 800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x12", "delay 800", | |
"raw 0x0020 {11 00 02 02 00 00 00}", "delay 100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500" | |
] | |
} | |
def setCelsius() | |
{ | |
// Update Display Unit | |
sendEvent("name":"temperatureUnit", "value":"C") | |
// send zigbee command | |
[ | |
"raw 0x0020 {11 00 02 02 00 00 00}", "delay 100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500", | |
"st wattr 0x${device.deviceNetworkId} 1 0x204 0 0x30 {00}", "delay | |
800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0", "delay 800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x11", "delay 800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x12", "delay 800", | |
"raw 0x0020 {11 00 02 1C 00 00 00}", "delay 100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500" | |
] | |
} | |
// =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D SmartThings Default Fucnti= | |
ons: refresh, configure, poll | |
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D | |
def refresh() | |
{ | |
log.debug "refresh() - update attributes " | |
[ | |
//Set long poll interval to 2 qs | |
"raw 0x0020 {11 00 02 02 00 00 00}", "delay 100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500", | |
//This is sent in this specific order to ensure that the | |
temperature values are received after the unit/mode | |
"st rattr 0x${device.deviceNetworkId} 1 0x204 0", "delay 800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x1C", "delay 800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0", "delay 800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x11", "delay 800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x12", "delay 800", | |
"st rattr 0x${device.deviceNetworkId} 1 0x202 0", "delay 800", | |
//Set long poll interval to 28 qs (7 seconds) | |
"raw 0x0020 {11 00 02 1C 00 00 00}", "delay 100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500" | |
] | |
} | |
def configure() | |
{ | |
log.debug "configure() - binding & attribute report" | |
[ | |
//Set long poll interval to 2 qs | |
"raw 0x0020 {11 00 02 02 00 00 00}", "delay 100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500", | |
//Bindings for Thermostat and Fan Control | |
"zdo bind 0x${device.deviceNetworkId} 1 1 0x201 | |
{${device.zigbeeId}} {}", "delay 500", | |
"zdo bind 0x${device.deviceNetworkId} 1 1 0x202 | |
{${device.zigbeeId}} {}", "delay 500", | |
"zdo bind 0x${device.deviceNetworkId} 1 1 0x204 | |
{${device.zigbeeId}} {}", "delay 500", | |
//Thermostat - Configure Report | |
"zcl global send-me-a-report 0x201 0 0x29 1 300 {6400}", "delay | |
100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500", | |
"zcl global send-me-a-report 0x201 0x0011 0x29 1 300 {6400}", | |
"delay 100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500", | |
"zcl global send-me-a-report 0x201 0x0012 0x29 1 300 {6400}", | |
"delay 100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500", | |
"zcl global send-me-a-report 0x201 0x001C 0x30 1 300 {}", "delay | |
100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500", | |
//Fan Control - Configure Report | |
"zcl global send-me-a-report 0x202 0 0x30 1 300 {}", "delay 100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500", | |
//Thermostat UI - Read Attribute Report (attribute not reportable= | |
) | |
"st rattr 0x${device.deviceNetworkId} 1 0x204 0", "delay 800", | |
//Set long poll interval to 28 qs (7 seconds) | |
"raw 0x0020 {11 00 02 1C 00 00 00}", "delay 100", | |
"send 0x${device.deviceNetworkId} 1 1", "delay 500" | |
] | |
} | |
//def poll() | |
//{ | |
// // leave it out because it will kill the battery | |
//} | |
private hex(value) { | |
new BigInteger(Math.round(value).toString()).toString(16) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment