mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-15 13:10:51 +00:00
Compare commits
1 Commits
MSA-1476-1
...
MSA-1474-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
309439a391 |
@@ -0,0 +1,284 @@
|
||||
/**
|
||||
* Copyright 2015 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:
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
//metadata for smartapps
|
||||
metadata {
|
||||
definition (name: "Danfoss LC13 TRV V0.7", namespace: "richdp", author: "RichardP") {
|
||||
capability "Actuator"
|
||||
capability "Temperature Measurement"
|
||||
capability "Relative Humidity Measurement"
|
||||
capability "Thermostat"
|
||||
capability "Configuration"
|
||||
capability "Polling"
|
||||
capability "Sensor"
|
||||
|
||||
attribute "thermostatFanState", "string"
|
||||
|
||||
command "switchMode"
|
||||
command "switchFanMode"
|
||||
command "quickSetCool"
|
||||
command "quickSetHeat"
|
||||
|
||||
fingerprint deviceId: "0x0804"
|
||||
fingerprint inClusters: "0x80, 0x46, 0x81, 0x72, 0x8F, 0x75, 0x43, 0x86, 0x84"
|
||||
|
||||
}
|
||||
|
||||
// simulator metadata
|
||||
simulator {
|
||||
status "off" : "command: 4003, payload: 00"
|
||||
status "heat" : "command: 4003, payload: 01"
|
||||
status "cool" : "command: 4003, payload: 02"
|
||||
status "auto" : "command: 4003, payload: 03"
|
||||
status "emergencyHeat" : "command: 4003, payload: 04"
|
||||
|
||||
status "fanAuto" : "command: 4403, payload: 00"
|
||||
status "fanOn" : "command: 4403, payload: 01"
|
||||
status "fanCirculate" : "command: 4403, payload: 06"
|
||||
|
||||
status "heat 60" : "command: 4303, payload: 01 09 3C"
|
||||
status "heat 68" : "command: 4303, payload: 01 09 44"
|
||||
status "heat 72" : "command: 4303, payload: 01 09 48"
|
||||
|
||||
status "cool 72" : "command: 4303, payload: 02 09 48"
|
||||
status "cool 76" : "command: 4303, payload: 02 09 4C"
|
||||
status "cool 80" : "command: 4303, payload: 02 09 50"
|
||||
|
||||
status "temp 58" : "command: 3105, payload: 01 2A 02 44"
|
||||
status "temp 62" : "command: 3105, payload: 01 2A 02 6C"
|
||||
status "temp 70" : "command: 3105, payload: 01 2A 02 BC"
|
||||
status "temp 74" : "command: 3105, payload: 01 2A 02 E4"
|
||||
status "temp 78" : "command: 3105, payload: 01 2A 03 0C"
|
||||
status "temp 82" : "command: 3105, payload: 01 2A 03 34"
|
||||
|
||||
status "idle" : "command: 4203, payload: 00"
|
||||
status "heating" : "command: 4203, payload: 01"
|
||||
status "cooling" : "command: 4203, payload: 02"
|
||||
status "fan only" : "command: 4203, payload: 03"
|
||||
status "pending heat" : "command: 4203, payload: 04"
|
||||
status "pending cool" : "command: 4203, payload: 05"
|
||||
status "vent economizer": "command: 4203, payload: 06"
|
||||
|
||||
// reply messages
|
||||
reply "2502": "command: 2503, payload: FF"
|
||||
}
|
||||
|
||||
//UI configuration
|
||||
tiles {
|
||||
// Main Tile displays current set point recieved from thermostat.
|
||||
// Background color changes with temp.
|
||||
valueTile("temperature", "device.currentHeatingSetpoint", width: 3, height: 2) {
|
||||
state("device.currentHeatingSetpoint", label:'${currentValue}°',
|
||||
backgroundColors:[
|
||||
[value: 0, color: "#ededed"],
|
||||
[value: 4, color: "#153591"], //blue
|
||||
[value: 16, color: "#178998"],
|
||||
[value: 18, color: "#199f5c"],
|
||||
[value: 20, color: "#2da71c"],//green
|
||||
[value: 21, color: "#5baa1d"],
|
||||
[value: 22, color: "#8aae1e"],
|
||||
[value: 23, color: "#b1a81f"],
|
||||
[value: 24, color: "#b57d20"],
|
||||
[value: 26, color: "#b85122"],
|
||||
[value: 28, color: "#bc2323"] //red
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
// Slider control for controling the set point which is next sent to the thermostat
|
||||
controlTile("heatSliderControl", "device.nextHeatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false, range:"(4..28)" ) {
|
||||
state "setHeatingSetpoint", action: "quickSetHeat", backgroundColor:"#d04e00"
|
||||
}
|
||||
|
||||
// Tile to indicate the set point that will next be sent to the thermostat. Controlled by controlTile above.
|
||||
valueTile("nextHeatingSetpoint", "device.nextHeatingSetpoint", inactiveLabel: false, decoration: "flat") {
|
||||
state "heat", label:'${currentValue}° next', backgroundColor:"#ffffff"
|
||||
}
|
||||
|
||||
// Display battery %
|
||||
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||
tileAttribute ("device.battery", key: "PRIMARY_CONTROL"){
|
||||
state "battery", label:'${currentValue}% battery', unit:""}
|
||||
}
|
||||
|
||||
// Standard Refresh Tile
|
||||
standardTile("refresh", "device.thermostatMode", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||
state "default", action:"polling.poll", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
// Standard Config Tile
|
||||
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
|
||||
}
|
||||
|
||||
// Order of Tiles
|
||||
main "temperature"
|
||||
details(["temperature", "heatSliderControl", "nextHeatingSetpoint", "battery", "refresh", "configure"])
|
||||
}
|
||||
} //end of UI config
|
||||
|
||||
//Parse string to recieve information from device
|
||||
def parse(String description) {
|
||||
state.count = 0
|
||||
def results = []
|
||||
log.debug("RAW command: $description")
|
||||
if (description.startsWith("Err")) {
|
||||
log.debug("An error has occurred")
|
||||
}
|
||||
else {
|
||||
def cmd = zwave.parse(description,[0x80: 1, 0x46: 1, 0x81: 1, 0x72: 2, 0x8F: 1, 0x75: 2, 0x43: 2, 0x86: 1, 0x84: 2])
|
||||
log.debug "Parsed Command: $cmd"
|
||||
if (cmd) {
|
||||
results = zwaveEvent(cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Event Generation
|
||||
// Event - Get Battery Report
|
||||
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
||||
def map = [ name: "battery", unit: "%" ]
|
||||
if (cmd.batteryLevel == 0xFF) { // Special value for low battery alert
|
||||
map.value = 1
|
||||
map.descriptionText = "${device.displayName} has a low battery"
|
||||
map.isStateChange = true
|
||||
} else {
|
||||
map.value = cmd.batteryLevel
|
||||
log.debug ("Battery: $cmd.batteryLevel")
|
||||
}
|
||||
// Store time of last battery update so we don't ask every wakeup, see WakeUpNotification handler
|
||||
state.lastbatt = new Date().time
|
||||
createEvent(map)
|
||||
}
|
||||
|
||||
// Event - Get Override Schedule
|
||||
def zwaveEvent(physicalgraph.zwave.commands.climatecontrolschedulev1.ScheduleOverrideReport cmd){
|
||||
log.debug "--- Schedule Override Report received: $cmd"
|
||||
}
|
||||
|
||||
// Event - Thermostat Report
|
||||
def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd) {
|
||||
log.debug "--- Thermostat Report recieved: $cmd"
|
||||
def cmdScale = cmd.scale == 1 ? "F" : "C"
|
||||
def map = [:]
|
||||
map.value = convertTemperatureIfNeeded(cmd.scaledValue, cmdScale, cmd.precision)
|
||||
map.unit = getTemperatureScale()
|
||||
map.displayed = false
|
||||
map.name = "currentHeatingSetpoint"
|
||||
log.debug ("Parsed Thermostat Set Point: $map")
|
||||
|
||||
// So we can respond with same format
|
||||
state.size = cmd.size
|
||||
state.scale = cmd.scale
|
||||
state.precision = cmd.precision
|
||||
map
|
||||
sendEvent(map)
|
||||
}
|
||||
|
||||
// Event for waking up the battery powered device
|
||||
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
|
||||
def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: true)]
|
||||
|
||||
// Only ask for battery if we haven't had a BatteryReport in a while
|
||||
if (!state.lastbatt || (new Date().time) - state.lastbatt > 24*60*60*1000) {
|
||||
result << response(zwave.batteryV1.batteryGet())
|
||||
result << response("delay 1200") // leave time for device to respond to batteryGet
|
||||
}
|
||||
//Send new set point to TRV on wake up
|
||||
result << response (configureSetPoint())
|
||||
result << response ("delay 2000")
|
||||
|
||||
//Confirm current set point and update UI
|
||||
result << response (updateUI())
|
||||
result << response ("delay 2000")
|
||||
|
||||
// wait and then send no more information confirmation
|
||||
result << response(zwave.wakeUpV1.wakeUpNoMoreInformation())
|
||||
}
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
|
||||
log.debug "Zwave event received: $cmd"
|
||||
}
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
||||
log.warn "Unexpected zwave command $cmd"
|
||||
}
|
||||
|
||||
// Command Implementations
|
||||
def poll() {
|
||||
delayBetween([
|
||||
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format(), //chaged to V1 for testing
|
||||
], standardDelay)
|
||||
}
|
||||
|
||||
def quickSetHeat(degrees) {
|
||||
setHeatingSetpoint(degrees, 1000)
|
||||
}
|
||||
|
||||
def nextHeatingSetpoint(degrees, delay = 3600) {
|
||||
setHeatingSetpoint(degrees.toDouble(), delay)
|
||||
}
|
||||
|
||||
def setHeatingSetpoint(Double degrees, Integer delay = 3600) {
|
||||
log.trace "setNextHeatingSetpoint($degrees, $delay)"
|
||||
def deviceScale = state.scale ?: 2
|
||||
def deviceScaleString = deviceScale == 2 ? "C" : "F"
|
||||
def locationScale = getTemperatureScale()
|
||||
def p = (state.precision == null) ? 1 : state.precision
|
||||
|
||||
def convertedDegrees
|
||||
if (locationScale == "C" && deviceScaleString == "F") {
|
||||
convertedDegrees = celsiusToFahrenheit(degrees)
|
||||
} else if (locationScale == "F" && deviceScaleString == "C") {
|
||||
convertedDegrees = fahrenheitToCelsius(degrees)
|
||||
} else {
|
||||
convertedDegrees = degrees
|
||||
}
|
||||
|
||||
sendEvent(name:"nextHeatingSetpoint", value:convertedDegrees, isStateChange: true)
|
||||
log.debug ("Value to be sent to thermostat on next wakeup: $convertedDegrees")
|
||||
state.nextHeatingSetpoint = convertedDegrees
|
||||
}
|
||||
|
||||
|
||||
//send new set point to thermostat
|
||||
def configureSetPoint(){
|
||||
log.debug "*** sending new setpoint"
|
||||
def sendHeatingSetpoint = state.nextHeatingSetpoint
|
||||
delayBetween([
|
||||
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 1, scale: 0, precision: 2, scaledValue: sendHeatingSetpoint).format(),
|
||||
], 2000)
|
||||
}
|
||||
|
||||
//get the current setpoint and update the UI
|
||||
def updateUI(){
|
||||
delayBetween([
|
||||
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format()
|
||||
], 2000)
|
||||
}
|
||||
|
||||
//configuration
|
||||
def configure() {
|
||||
delayBetween([
|
||||
zwave.configurationV1.configurationSet(parameterNumber:1, size:2, scaledConfigurationValue:100).format(),
|
||||
zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format(),
|
||||
zwave.wakeUpV1.wakeUpIntervalSet(seconds:3600, nodeid:zwaveHubNodeId).format()
|
||||
], standardDelay)
|
||||
}
|
||||
|
||||
//standardDelay
|
||||
private getStandardDelay() {
|
||||
1000
|
||||
}
|
||||
@@ -1,630 +0,0 @@
|
||||
/**
|
||||
* Copyright 2015 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:
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Author: SmartThings
|
||||
* Date: 2013-12-02
|
||||
*/
|
||||
metadata {
|
||||
definition (name: "ZigBee CentraLite Thermostat", namespace: "smartthings", author: "SmartThings") {
|
||||
capability "Actuator"
|
||||
capability "Temperature Measurement"
|
||||
capability "Thermostat"
|
||||
capability "Configuration"
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Polling"
|
||||
capability "Battery"
|
||||
|
||||
|
||||
// Custom commands
|
||||
command "raiseHeatLevel"
|
||||
command "lowHeatLevel"
|
||||
command "raiseCoolLevel"
|
||||
command "lowCoolLevel"
|
||||
command "setTemperature"
|
||||
command "setThermostatHoldMode"
|
||||
command "getPowerSource"
|
||||
|
||||
attribute "temperatureScale", "string"
|
||||
attribute "thermostatHoldMode", "string"
|
||||
attribute "powerSource", "string"
|
||||
|
||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,0201,0202,0204,0B05", outClusters: "000A, 0019"
|
||||
}
|
||||
|
||||
// simulator metadata
|
||||
simulator { }
|
||||
|
||||
tiles(scale: 2) {
|
||||
|
||||
multiAttributeTile(name:"summary", type: "thermostat", width: 6, height: 4) {
|
||||
tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
|
||||
attributeState("temperature", label:'${currentValue}°', unit:"dF",
|
||||
backgroundColors:[
|
||||
// Celsius Color Range
|
||||
[value: 0, color: "#153591"],
|
||||
[value: 7, color: "#1e9cbb"],
|
||||
[value: 15, color: "#90d2a7"],
|
||||
[value: 23, color: "#44b621"],
|
||||
[value: 29, color: "#f1d801"],
|
||||
[value: 33, color: "#d04e00"],
|
||||
[value: 36, color: "#bc2323"],
|
||||
// Fahrenheit Color Range
|
||||
[value: 40, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 65, color: "#99ff33"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 92, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
])
|
||||
}
|
||||
tileAttribute("device.temperature", key: "VALUE_CONTROL") {
|
||||
attributeState("default", action: "setTemperature")
|
||||
}
|
||||
|
||||
tileAttribute("device.powerSource", key: "SECONDARY_CONTROL") {
|
||||
attributeState("default", label:'PowerSrc: ${currentValue}')
|
||||
}
|
||||
|
||||
tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") {
|
||||
attributeState("default", label:'${currentValue}', unit:"dF")
|
||||
}
|
||||
tileAttribute("device.coolingSetpoint", key: "COOLING_SETPOINT") {
|
||||
attributeState("default", label:'${currentValue}', unit:"dF")
|
||||
}
|
||||
}
|
||||
|
||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||
state("temperature", label:'${currentValue}°', unit:"",
|
||||
backgroundColors:[
|
||||
// Celsius Color Range
|
||||
[value: 0, color: "#153591"],
|
||||
[value: 7, color: "#1e9cbb"],
|
||||
[value: 15, color: "#90d2a7"],
|
||||
[value: 23, color: "#44b621"],
|
||||
[value: 29, color: "#f1d801"],
|
||||
[value: 33, color: "#d04e00"],
|
||||
[value: 36, color: "#bc2323"],
|
||||
// Fahrenheit Color Range
|
||||
[value: 40, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 65, color: "#99ff33"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 92, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
standardTile("mode", "device.thermostatMode", height: 2, width: 2, inactiveLabel: false, canChangeIcon: false) {
|
||||
state "off", label:'', action:"thermostat.setThermostatMode", icon: "st.thermostat.heating-cooling-off"
|
||||
state "cool", label:'', action:"thermostat.setThermostatMode", icon: "st.thermostat.cool", backgroundColor: '#99ddff'
|
||||
state "heat", label:'', action:"thermostat.setThermostatMode", icon: "st.thermostat.heat", backgroundColor: '#fd631c'
|
||||
state "emergencyHeat", label:'', action:"thermostat.setThermostatMode", icon: "st.thermostat.emergency-heat", backgroundColor: '#E11102'
|
||||
//state "auto", label:'', action:"thermostat.setThermostatMode", icon: "st.thermostat.auto", backgroundColor: '#ffff00'
|
||||
}
|
||||
|
||||
standardTile("fanMode", "device.thermostatFanMode", height: 2, width: 2, inactiveLabel: false, canChangeIcon: false) {
|
||||
state "fanAuto", label:'', action:"thermostat.setThermostatFanMode", icon: "st.thermostat.fan-auto", backgroundColor: '#ffff00'
|
||||
state "fanOn", label:'', action:"thermostat.setThermostatFanMode", icon: "st.thermostat.fan-on", backgroundColor: '#ffff00'
|
||||
}
|
||||
|
||||
standardTile("holdMode", "device.thermostatHoldMode", height: 2, width: 2, inactiveLabel: false, canChangeIcon: false) {
|
||||
state "holdOff", label:'Hold Off', action:"setThermostatHoldMode", icon: "st.Lighting.light13", backgroundColor:"#ffffff", nextState:"holdOff"
|
||||
state "holdOn", label:'Hold On', action:"setThermostatHoldMode", icon: "st.Lighting.light11", backgroundColor:"#ffb3ff", nextState:"holdOn"
|
||||
}
|
||||
|
||||
standardTile("raiseHeatLevel", "device.heatingSetpoint", canChangeIcon: false, , height: 0.5, width: 0.5, inactiveLabel: false, decoration: "flat") {
|
||||
state "raiseHeatLevel", label:' ', action:"raiseHeatLevel", icon:"st.thermostat.thermostat-up"
|
||||
}
|
||||
valueTile("heatingSetpoint", "device.heatingSetpoint", height: 1, width: 2, inactiveLabel: false, decoration: "flat") {
|
||||
state "heat", label:'${currentValue}° Heat', unit:"", backgroundColor:"#fd631c"
|
||||
}
|
||||
standardTile("lowHeatLevel", "device.heatingSetpoint", canChangeIcon: false, , height: 0.5, width: 0.5, inactiveLabel: false, decoration: "flat") {
|
||||
state "lowHeatLevel", label:' ', action:"lowHeatLevel", icon:"st.thermostat.thermostat-down"
|
||||
}
|
||||
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 4, inactiveLabel: false) {
|
||||
state "setHeatingSetpoint", action:"thermostat.setHeatingSetpoint", backgroundColor:"#d04e00"
|
||||
}
|
||||
|
||||
standardTile("raiseCoolLevel", "device.heatingSetpoint", canChangeIcon: false, , height: 0.5, width: 0.5, inactiveLabel: false, decoration: "flat") {
|
||||
state "raiseCoolLevel", label:' ', action:"raiseCoolLevel", icon:"st.thermostat.thermostat-up"
|
||||
}
|
||||
valueTile("coolingSetpoint", "device.coolingSetpoint", , height: 1, width: 2, inactiveLabel: false, decoration: "flat") {
|
||||
state "cool", label:'${currentValue}° Cool', unit:"", backgroundColor:"#66ccff"
|
||||
}
|
||||
standardTile("lowCoolLevel", "device.heatingSetpoint", canChangeIcon: false, , height: 0.5, width: 0.5, inactiveLabel: false, decoration: "flat") {
|
||||
state "lowCoolLevel", label:' ', action:"lowCoolLevel", icon:"st.thermostat.thermostat-down"
|
||||
}
|
||||
controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 1, width: 4, inactiveLabel: false) {
|
||||
state "setCoolingSetpoint", action:"thermostat.setCoolingSetpoint", backgroundColor: "#003CEC"
|
||||
}
|
||||
|
||||
standardTile("refresh", "device.temperature", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
standardTile("configure", "device.configure", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
||||
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
|
||||
}
|
||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "battery", label:'${currentValue}% Battery', unit:""
|
||||
}
|
||||
main(["temperature", "summary"])
|
||||
details(["summary", "holdMode", "mode", "fanMode", "heatSliderControl", "heatingSetpoint", "coolSliderControl", "coolingSetpoint", "battery", "refresh"])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def setTemperature(setpoint) {
|
||||
log.debug "setTemperature() called with setpoint ${setpoint}. "
|
||||
log.debug "Current temperature: ${device.currentValue("temperature")}. Heat Setpoint: ${device.currentValue("heatingSetpoint")}. Cool Setpoint: ${device.currentValue("coolingSetpoint")}"
|
||||
|
||||
def mode = device.currentValue("thermostatMode")
|
||||
def midpoint
|
||||
def targetvalue
|
||||
|
||||
if (mode == "off") {
|
||||
log.warn "setTemperature(): this mode: $mode does not allow raiseSetpoint"
|
||||
return
|
||||
}
|
||||
|
||||
def currentTemp = device.currentValue("temperature")
|
||||
def deltaTemp = setpoint - currentTemp
|
||||
|
||||
log.debug "deltaTemp = ${deltaTemp}"
|
||||
|
||||
if (mode == "heat") {
|
||||
// Change the heat
|
||||
log.debug "setTemperature(): change the heat temp"
|
||||
if (deltaTemp < 0) {
|
||||
lowHeatLevel()
|
||||
} else if (deltaTemp > 0) {
|
||||
raiseHeatLevel()
|
||||
}
|
||||
} else if (mode == "cool") {
|
||||
// Change the cool
|
||||
log.debug "setTemperature(): change the cool temp"
|
||||
if (deltaTemp < 0) {
|
||||
lowCoolLevel()
|
||||
} else if (deltaTemp > 0) {
|
||||
raiseCoolLevel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def raiseHeatLevel(){
|
||||
|
||||
def mode = device.currentValue("thermostatMode")
|
||||
|
||||
if (mode == "off") {
|
||||
log.warn "raiseHeatLevel(): this mode: $mode does not allow raiseHeatLevel"
|
||||
} else {
|
||||
def locationScale = getTemperatureScale()
|
||||
def maxTemp
|
||||
def minTemp
|
||||
if (locationScale == "C") {
|
||||
maxTemp = 44 // Max Temp in C
|
||||
minTemp = 7 // Min Temp in C
|
||||
log.trace "Location is in Celsius, MaxTemp: $maxTemp, MinTemp: $minTemp"
|
||||
} else {
|
||||
maxTemp = 86 // Max temp in F
|
||||
minTemp = 30 // Max temp in F
|
||||
log.trace "Location is in Farenheit, MaxTemp: $maxTemp, MinTemp: $minTemp"
|
||||
}
|
||||
|
||||
def currentLevel = device.currentValue("heatingSetpoint")
|
||||
int nextLevel = currentLevel.toInteger() + 1
|
||||
|
||||
if( nextLevel > maxTemp){
|
||||
nextLevel = maxTemp
|
||||
}
|
||||
log.debug "Setting heat set point up to: ${nextLevel}"
|
||||
setHeatingSetpoint(nextLevel)
|
||||
}
|
||||
}
|
||||
|
||||
def lowHeatLevel(){
|
||||
if (mode == "off") {
|
||||
log.warn "lowHeatLevel(): this mode: $mode does not allow lowHeatLevel"
|
||||
} else {
|
||||
def locationScale = getTemperatureScale()
|
||||
def maxTemp
|
||||
def minTemp
|
||||
if (locationScale == "C") {
|
||||
maxTemp = 44 // Max Temp in C
|
||||
minTemp = 7 // Min Temp in C
|
||||
log.trace "Location is in Celsius, MaxTemp: $maxTemp, MinTemp: $minTemp"
|
||||
} else {
|
||||
maxTemp = 86 // Max temp in F
|
||||
minTemp = 30 // Max temp in F
|
||||
log.trace "Location is in Farenheit, MaxTemp: $maxTemp, MinTemp: $minTemp"
|
||||
}
|
||||
|
||||
def currentLevel = device.currentValue("heatingSetpoint")
|
||||
int nextLevel = currentLevel.toInteger() - 1
|
||||
|
||||
if( nextLevel < minTemp){
|
||||
nextLevel = minTemp
|
||||
}
|
||||
log.debug "Setting heat set point down to: ${nextLevel}"
|
||||
setHeatingSetpoint(nextLevel)
|
||||
}
|
||||
}
|
||||
|
||||
def raiseCoolLevel(){
|
||||
if (mode == "off") {
|
||||
log.warn "raiseCoolLevel(): this mode: $mode does not allow raiseCoolLevel"
|
||||
} else {
|
||||
def locationScale = getTemperatureScale()
|
||||
def maxTemp
|
||||
def minTemp
|
||||
if (locationScale == "C") {
|
||||
maxTemp = 44 // Max Temp in C
|
||||
minTemp = 7 // Min Temp in C
|
||||
log.trace "Location is in Celsius, MaxTemp: $maxTemp, MinTemp: $minTemp"
|
||||
} else {
|
||||
maxTemp = 86 // Max temp in F
|
||||
minTemp = 30 // Max temp in F
|
||||
log.trace "Location is in Farenheit, MaxTemp: $maxTemp, MinTemp: $minTemp"
|
||||
}
|
||||
|
||||
def currentLevel = device.currentValue("coolingSetpoint")
|
||||
int nextLevel = currentLevel.toInteger() + 1
|
||||
|
||||
if( nextLevel > maxTemp){
|
||||
nextLevel = maxTemp
|
||||
}
|
||||
log.debug "Setting cool set point up to: ${nextLevel}"
|
||||
setCoolingSetpoint(nextLevel)
|
||||
}
|
||||
}
|
||||
|
||||
def lowCoolLevel(){
|
||||
if (mode == "off") {
|
||||
log.warn "lowCoolLevel(): this mode: $mode does not allow lowCoolLevel"
|
||||
} else {
|
||||
def locationScale = getTemperatureScale()
|
||||
def maxTemp
|
||||
def minTemp
|
||||
if (locationScale == "C") {
|
||||
maxTemp = 44 // Max Temp in C
|
||||
minTemp = 7 // Min Temp in C
|
||||
log.trace "Location is in Celsius, MaxTemp: $maxTemp, MinTemp: $minTemp"
|
||||
} else {
|
||||
maxTemp = 86 // Max temp in F
|
||||
minTemp = 30 // Max temp in F
|
||||
log.trace "Location is in Farenheit, MaxTemp: $maxTemp, MinTemp: $minTemp"
|
||||
}
|
||||
|
||||
def currentLevel = device.currentValue("coolingSetpoint")
|
||||
int nextLevel = currentLevel.toInteger() - 1
|
||||
|
||||
if( nextLevel < minTemp){
|
||||
nextLevel = minTemp
|
||||
}
|
||||
log.debug "Setting cool set point down to: ${nextLevel}"
|
||||
setCoolingSetpoint(nextLevel)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// parse events into attributes
|
||||
def parse(String description) {
|
||||
log.debug "Parse description $description"
|
||||
def map = [:]
|
||||
if (description?.startsWith("read attr -")) {
|
||||
def descMap = parseDescriptionAsMap(description)
|
||||
log.debug "Desc Map: $descMap"
|
||||
if (descMap.cluster == "0201" && descMap.attrId == "0000") {
|
||||
log.debug "TEMP"
|
||||
map.name = "temperature"
|
||||
map.value = getTemperature(descMap.value)
|
||||
} else if (descMap.cluster == "0201" && descMap.attrId == "0011") {
|
||||
log.debug "COOLING SETPOINT"
|
||||
map.name = "coolingSetpoint"
|
||||
map.value = getTemperature(descMap.value)
|
||||
} else if (descMap.cluster == "0201" && descMap.attrId == "0012") {
|
||||
log.debug "HEATING SETPOINT"
|
||||
map.name = "heatingSetpoint"
|
||||
map.value = getTemperature(descMap.value)
|
||||
} else if (descMap.cluster == "0201" && descMap.attrId == "001c") {
|
||||
log.debug "MODE"
|
||||
map.name = "thermostatMode"
|
||||
map.value = getModeMap()[descMap.value]
|
||||
} else if (descMap.cluster == "0202" && descMap.attrId == "0000") {
|
||||
log.debug "FAN MODE"
|
||||
map.name = "thermostatFanMode"
|
||||
map.value = getFanModeMap()[descMap.value]
|
||||
} else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
|
||||
log.debug "BATTERY"
|
||||
map.name = "battery"
|
||||
map.value = getBatteryLevel(descMap.value)
|
||||
} else if (descMap.cluster == "0201" && descMap.attrId == "001e") {
|
||||
log.debug "RUN MODE"
|
||||
map.name = "thermostatRunMode"
|
||||
//map.value = getRunModeMap()[descMap.value]
|
||||
map.value = getThermostatRunMode(descMap.value)
|
||||
} else if (descMap.cluster == "0201" && descMap.attrId == "0023") {
|
||||
log.debug "HOLD MODE"
|
||||
map.name = "thermostatHoldMode"
|
||||
map.value = getHoldModeMap()[descMap.value]
|
||||
} else if (descMap.cluster == "0000" && descMap.attrId == "0007") {
|
||||
log.debug "Power Source"
|
||||
map.name = "powerSource"
|
||||
map.value = getPowerSource()[descMap.value]
|
||||
}
|
||||
}
|
||||
|
||||
def result = null
|
||||
if (map) {
|
||||
result = createEvent(map)
|
||||
}
|
||||
log.debug "Parse returned $map"
|
||||
return result
|
||||
}
|
||||
|
||||
def parseDescriptionAsMap(description) {
|
||||
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
||||
def nameAndValue = param.split(":")
|
||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
||||
}
|
||||
}
|
||||
|
||||
def getModeMap() { [
|
||||
"00":"off",
|
||||
//"01":"auto",
|
||||
"03":"cool",
|
||||
"04":"heat",
|
||||
"05":"emergencyHeat"
|
||||
]}
|
||||
|
||||
def getHoldModeMap() { [
|
||||
"00":"holdOff",
|
||||
"01":"holdOn",
|
||||
]}
|
||||
|
||||
def getPowerSource() { [
|
||||
"01":"24VAC",
|
||||
"03":"Battery",
|
||||
]}
|
||||
|
||||
|
||||
def getFanModeMap() { [
|
||||
"04":"fanOn",
|
||||
"05":"fanAuto"
|
||||
]}
|
||||
|
||||
|
||||
def getThermostatRunMode(value) {
|
||||
if (value != null) {
|
||||
def RunModeValue = Integer.parseInt(value, 16)
|
||||
log.debug "Thermostat RunMode: ${RunModeValue} "
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def getTemperature(value) {
|
||||
if (value != null) {
|
||||
def celsius = Integer.parseInt(value, 16) / 100
|
||||
if (getTemperatureScale() == "C") {
|
||||
return celsius
|
||||
} else {
|
||||
return Math.round(celsiusToFahrenheit(celsius))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def setHeatingSetpoint(degrees) {
|
||||
if (degrees != null) {
|
||||
def temperatureScale = getTemperatureScale()
|
||||
|
||||
def degreesInteger = Math.round(degrees)
|
||||
log.debug "setHeatingSetpoint({$degreesInteger} ${temperatureScale})"
|
||||
sendEvent("name": "heatingSetpoint", "value": degreesInteger)
|
||||
|
||||
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius * 100) + "}"
|
||||
}
|
||||
}
|
||||
|
||||
def setCoolingSetpoint(degrees) {
|
||||
if (degrees != null) {
|
||||
def degreesInteger = Math.round(degrees)
|
||||
log.debug "setCoolingSetpoint({$degreesInteger} ${temperatureScale})"
|
||||
sendEvent("name": "coolingSetpoint", "value": degreesInteger)
|
||||
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x11 0x29 {" + hex(celsius * 100) + "}"
|
||||
}
|
||||
}
|
||||
|
||||
def modes() {
|
||||
["off", "cool", "heat", "emergencyHeat"]
|
||||
}
|
||||
|
||||
def setThermostatMode() {
|
||||
log.debug "switching thermostatMode"
|
||||
def currentMode = device.currentState("thermostatMode")?.value
|
||||
def modeOrder = modes()
|
||||
log.debug "modeOrder: ${modeOrder}"
|
||||
def index = modeOrder.indexOf(currentMode)
|
||||
log.debug "index: ${index}"
|
||||
def next = index >= 0 && index < modeOrder.size() - 1 ? modeOrder[index + 1] : modeOrder[0]
|
||||
log.debug "switching mode from $currentMode to $next"
|
||||
"$next"()
|
||||
}
|
||||
|
||||
def setThermostatFanMode() {
|
||||
log.debug "Switching fan mode"
|
||||
def currentFanMode = device.currentState("thermostatFanMode")?.value
|
||||
log.debug "switching fan from current mode: $currentFanMode"
|
||||
def returnCommand
|
||||
|
||||
switch (currentFanMode) {
|
||||
case "fanAuto":
|
||||
returnCommand = fanOn()
|
||||
break
|
||||
case "fanOn":
|
||||
returnCommand = fanAuto()
|
||||
break
|
||||
}
|
||||
if(!currentFanMode) { returnCommand = fanAuto() }
|
||||
returnCommand
|
||||
}
|
||||
|
||||
|
||||
def setThermostatHoldMode() {
|
||||
log.debug "Switching Hold mode"
|
||||
def currentHoldMode = device.currentState("thermostatHoldMode")?.value
|
||||
log.debug "switching thermostat from current mode: $currentHoldMode"
|
||||
def returnCommand
|
||||
|
||||
switch (currentHoldMode) {
|
||||
case "holdOff":
|
||||
returnCommand = holdOn()
|
||||
break
|
||||
case "holdOn":
|
||||
returnCommand = holdOff()
|
||||
break
|
||||
}
|
||||
if(!currentHoldMode) { returnCommand = holdOff() }
|
||||
returnCommand
|
||||
}
|
||||
|
||||
def setThermostatMode(String value) {
|
||||
log.debug "setThermostatMode({$value})"
|
||||
"$value"()
|
||||
}
|
||||
|
||||
def setThermostatFanMode(String value) {
|
||||
log.debug "setThermostatFanMode({$value})"
|
||||
"$value"()
|
||||
}
|
||||
|
||||
def setThermostatHoldMode(String value) {
|
||||
log.debug "setThermostatHoldMode({$value})"
|
||||
"$value"()
|
||||
}
|
||||
|
||||
|
||||
def off() {
|
||||
log.debug "off"
|
||||
sendEvent("name":"thermostatMode", "value":"off")
|
||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {00}"
|
||||
}
|
||||
|
||||
def cool() {
|
||||
log.debug "cool"
|
||||
sendEvent("name":"thermostatMode", "value":"cool")
|
||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {03}"
|
||||
}
|
||||
|
||||
def heat() {
|
||||
log.debug "heat"
|
||||
sendEvent("name":"thermostatMode", "value":"heat")
|
||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {04}"
|
||||
}
|
||||
|
||||
def emergencyHeat() {
|
||||
log.debug "emergencyHeat"
|
||||
sendEvent("name":"thermostatMode", "value":"emergencyHeat")
|
||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x1C 0x30 {05}"
|
||||
}
|
||||
|
||||
def on() {
|
||||
fanOn()
|
||||
}
|
||||
|
||||
def fanOn() {
|
||||
log.debug "fanOn"
|
||||
sendEvent("name":"thermostatFanMode", "value":"fanOn")
|
||||
"st wattr 0x${device.deviceNetworkId} 1 0x202 0 0x30 {04}"
|
||||
}
|
||||
|
||||
def auto() {
|
||||
fanAuto()
|
||||
}
|
||||
|
||||
def fanAuto() {
|
||||
log.debug "fanAuto"
|
||||
sendEvent("name":"thermostatFanMode", "value":"fanAuto")
|
||||
"st wattr 0x${device.deviceNetworkId} 1 0x202 0 0x30 {05}"
|
||||
}
|
||||
|
||||
def holdOn() {
|
||||
log.debug "Set Hold On for thermostat"
|
||||
sendEvent("name":"thermostatHoldMode", "value":"holdOn")
|
||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x23 0x30 {01}"
|
||||
}
|
||||
|
||||
def holdOff() {
|
||||
log.debug "Set Hold Off for thermostat"
|
||||
sendEvent("name":"thermostatHoldMode", "value":"holdOff")
|
||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x23 0x30 {00}"
|
||||
}
|
||||
|
||||
// Commment out below if no C-wire since it will kill the batteries.
|
||||
def poll() {
|
||||
// log.debug "Executing 'poll'"
|
||||
refresh()
|
||||
}
|
||||
|
||||
|
||||
def configure() {
|
||||
|
||||
log.debug "binding to Thermostat and Fan Control cluster"
|
||||
[
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x000 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x201 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x202 {${device.zigbeeId}} {}", "delay 200",
|
||||
|
||||
"zcl global send-me-a-report 1 0x20 0x20 3600 86400 {01}", "delay 100", //battery report request
|
||||
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def refresh()
|
||||
{
|
||||
log.debug "refresh called"
|
||||
[
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x000 0x07", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x201 0", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x11", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x12", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x1C", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x1E", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x201 0x23", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x001 0x20", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x202 0"
|
||||
] + configure()
|
||||
}
|
||||
|
||||
|
||||
private getBatteryLevel(rawValue) {
|
||||
def intValue = Integer.parseInt(rawValue,16)
|
||||
def min = 2.1
|
||||
def max = 3.0
|
||||
def vBatt = intValue / 10
|
||||
return ((vBatt - min) / (max - min) * 100) as int
|
||||
}
|
||||
|
||||
|
||||
private hex(value) {
|
||||
new BigInteger(Math.round(value).toString()).toString(16)
|
||||
}
|
||||
Reference in New Issue
Block a user