Compare commits

..

1 Commits

2 changed files with 200 additions and 752 deletions

View File

@@ -1,752 +0,0 @@
/* lgk larry kahn kahn-st@lgk.com custom ct100 .. changes to stock device type
1. add some icons and colors heat color, cool color,
2. add operating mode tile ie idle heating etc
3. add color for humididity as well
4. get rid of sliders that worked like crap and added up down arrows for both heating and cooling,
and color based on temp for both.
5. add color for battery status.
v 2. some returns between indicators to move things down a line as recommended
v 3 reintegrate changes smarthigns made in setheatingsetpoint and setcoolingsetpoint functions apparently to get around bugs.
these changes were made in the stock ct100 device type.
*/
metadata {
// Automatically generated. Make future change here.
definition (name: "My CT100 Thermostat", namespace: "smartthings", author: "LGK Customized") {
capability "Actuator"
capability "Temperature Measurement"
capability "Relative Humidity Measurement"
capability "Thermostat"
capability "Battery"
capability "Configuration"
capability "Refresh"
capability "Sensor"
command "heatLevelUp"
command "heatLevelDown"
command "coolLevelUp"
command "coolLevelDown"
attribute "thermostatFanState", "string"
command "switchMode"
command "switchFanMode"
command "quickSetCool"
command "quickSetHeat"
fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60"
}
// 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 72" : "command: 4303, payload: 01 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 78" : "command: 3105, payload: 01 2A 03 0C"
status "temp 86" : "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"
// reply messages
reply "2502": "command: 2503, payload: FF"
}
tiles {
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label:'${currentValue}°',
icon: "http://cdn.device-icons.smartthings.com/Weather/weather2-icn@2x.png",
backgroundColors:[
[value: 32, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 92, color: "#d04e00"],
[value: 98, color: "#bc2323"]
]
)
}
standardTile("mode", "device.thermostatMode", inactiveLabel: false) {
state "off", label:'${name}', action:"switchMode", icon: "st.Outdoor.outdoor19" ,nextState:"to_heat"
state "heat", label:'${name}', action:"switchMode", icon: "st.Weather.weather14", backgroundColor: '#E14902', nextState:"to_cool"
state "cool", label:'${name}', action:"switchMode", icon: "st.Weather.weather7", backgroundColor: '#1e9cbb', nextState:"..."
state "auto", label:'${name}', action:"switchMode", icon: "st.Weather.weather3", backgroundColor: '#44b621', nextState:"..."
state "emergency heat", label:'${name}', action:"switchMode", nextState:"..."
state "to_heat", label: "heat", action:"switchMode", nextState:"to_cool"
state "to_cool", label: "cool", action:"switchMode", nextState:"..."
state "...", label: "...", action:"off", nextState:"off"
}
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false) {
state "fanAuto", label:'${name}', action:"switchFanMode", icon: "st.Appliances.appliances11", backgroundColor: '#44b621'
state "fanOn", label:'${name}', action:"switchFanMode", icon: "st.Appliances.appliances11", backgroundColor: '#44b621'
state "fanCirculate", label:'${name}', action:"switchFanMode", icon: "st.Appliances.appliances11", backgroundColor: '#44b621'
}
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false)
{
state "default", label:'Cool\n${currentValue}°F', unit:"F",
backgroundColors:
[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false)
{
state "default", label:'Heat\n${currentValue}°F', unit:"F",
backgroundColors:
[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
standardTile("heatLevelUp", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false) {
state "heatLevelUp", label:' ', action:"heatLevelUp", icon:"st.thermostat.thermostat-up"
}
standardTile("heatLevelDown", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false) {
state "heatLevelDown", label:' ', action:"heatLevelDown", icon:"st.thermostat.thermostat-down"
}
standardTile("coolLevelUp", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false) {
state "coolLevelUp", label:' ', action:"coolLevelUp", icon:"st.thermostat.thermostat-up"
}
standardTile("coolLevelDown", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false) {
state "coolLevelDown", label:' ', action:"coolLevelDown", icon:"st.thermostat.thermostat-down"
}
/*
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
state "setHeatingSetpoint", action:"quickSetHeat", backgroundColor:"#d04e00"
}
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false, decoration: "flat") {
state "heat", label:'${currentValue}° heat', backgroundColor:"#ffffff"
}
controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
state "setCoolingSetpoint", action:"quickSetCool", backgroundColor: "#1e9cbb"
}
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
state "cool", label:'${currentValue}° cool', backgroundColor:"#ffffff"
}
*/
valueTile("humidity", "device.humidity", inactiveLabel: false) {
state "humidity", label:'Humidity\n${currentValue}%', unit:"",
icon: "http://cdn.device-icons.smartthings.com/Weather/weather12-icn@2x.png",
backgroundColors : [
[value: 01, color: "#724529"],
[value: 11, color: "#724529"],
[value: 21, color: "#724529"],
[value: 35, color: "#44b621"],
[value: 49, color: "#44b621"],
[value: 50, color: "#1e9cbb"]
]
}
valueTile("battery", "device.battery", inactiveLabel: false) {
state "battery", label:'Battery\n${currentValue}%', unit:"",
backgroundColors : [
[value: 20, color: "#720000"],
[value: 40, color: "#724529"],
[value: 60, color: "#00cccc"],
[value: 80, color: "#00b621"],
[value: 90, color: "#009c00"],
[value: 100, color: "#00ff00"]
]h
}
valueTile("thermostatOperatingState", "device.thermostatOperatingState", inactiveLabel: false, decoration: "flat") {
state "thermostatOperatingState", label:'${currentValue}', unit:""
}
standardTile("refresh", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
}
main "temperature"
details(["temperature", "mode", "fanMode",
"heatLevelUp", "heatingSetpoint" , "heatLevelDown", "coolLevelUp",
"coolingSetpoint", "coolLevelDown",
"humidity", "battery","thermostatOperatingState","refresh"])
/*main "temperature"
details(["temperature", "mode", "fanMode",
"heatSliderControl", "heatingSetpoint", "coolSliderControl", "coolingSetpoint",
"humidity", "battery","thermostatOperatingState","refresh"])*/
}
}
def parse(String description)
{
def result = []
if (description == "updated") {
} else {
def zwcmd = zwave.parse(description, [0x42:2, 0x43:2, 0x31: 2, 0x60: 3])
if (zwcmd) {
result += zwaveEvent(zwcmd)
} else {
log.debug "$device.displayName couldn't parse $description"
}
}
if (!result) {
return null
}
if (result.size() == 1 && (!state.lastbatt || now() - state.lastbatt > 48*60*60*1000)) {
result << response(zwave.batteryV1.batteryGet().format())
}
//log.debug "$device.displayName parsed '$description' to $result"
result
}
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
def result = null
def encapsulatedCommand = cmd.encapsulatedCommand([0x42:2, 0x43:2, 0x31: 2])
log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")
if (encapsulatedCommand) {
result = zwaveEvent(encapsulatedCommand)
if (cmd.sourceEndPoint == 1) { // indicates a response to refresh() vs an unrequested update
def event = ([] + result)[0] // in case zwaveEvent returns a list
def resp = nextRefreshQuery(event?.name)
if (resp) {
log.debug("sending next refresh query: $resp")
result = [] + result + response(["delay 200", resp])
}
}
}
result
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd)
{
def cmdScale = cmd.scale == 1 ? "F" : "C"
def temp = convertTemperatureIfNeeded(cmd.scaledValue, cmdScale, cmd.precision)
def unit = getTemperatureScale()
def map1 = [ value: temp, unit: unit, displayed: false ]
switch (cmd.setpointType) {
case 1:
map1.name = "heatingSetpoint"
break;
case 2:
map1.name = "coolingSetpoint"
break;
default:
log.debug "unknown setpointType $cmd.setpointType"
return
}
// So we can respond with same format
state.size = cmd.size
state.scale = cmd.scale
state.precision = cmd.precision
def mode = device.latestValue("thermostatMode")
if (mode && map1.name.startsWith(mode) || (mode == "emergency heat" && map1.name == "heatingSetpoint")) {
def map2 = [ name: "thermostatSetpoint", value: temp, unit: unit ]
[ createEvent(map1), createEvent(map2) ]
} else {
createEvent(map1)
}
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd)
{
def map = [:]
if (cmd.sensorType == 1) {
map.name = "temperature"
map.unit = getTemperatureScale()
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmd.scale == 1 ? "F" : "C", cmd.precision)
} else if (cmd.sensorType == 5) {
map.name = "humidity"
map.unit = "%"
map.value = cmd.scaledSensorValue
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport cmd)
{
def map = [name: "thermostatOperatingState" ]
switch (cmd.operatingState) {
case physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport.OPERATING_STATE_IDLE:
map.value = "idle"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport.OPERATING_STATE_HEATING:
map.value = "heating"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport.OPERATING_STATE_COOLING:
map.value = "cooling"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport.OPERATING_STATE_FAN_ONLY:
map.value = "fan only"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport.OPERATING_STATE_PENDING_HEAT:
map.value = "pending heat"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport.OPERATING_STATE_PENDING_COOL:
map.value = "pending cool"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport.OPERATING_STATE_VENT_ECONOMIZER:
map.value = "vent economizer"
break
}
def result = createEvent(map)
if (result.isStateChange && device.latestValue("thermostatMode") == "auto" && (result.value == "heating" || result.value == "cooling")) {
def thermostatSetpoint = device.latestValue("${result.value}Setpoint")
result = [result, createEvent(name: "thermostatSetpoint", value: thermostatSetpoint, unit: getTemperatureScale())]
}
result
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanstatev1.ThermostatFanStateReport cmd) {
def map = [name: "thermostatFanState", unit: ""]
switch (cmd.fanOperatingState) {
case 0:
map.value = "idle"
break
case 1:
map.value = "running"
break
case 2:
map.value = "running high"
break
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) {
def map = [name: "thermostatMode"]
def thermostatSetpoint = null
switch (cmd.mode) {
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_OFF:
map.value = "off"
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_HEAT:
map.value = "heat"
thermostatSetpoint = device.latestValue("heatingSetpoint")
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUXILIARY_HEAT:
map.value = "emergency heat"
thermostatSetpoint = device.latestValue("heatingSetpoint")
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_COOL:
map.value = "cool"
thermostatSetpoint = device.latestValue("coolingSetpoint")
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUTO:
map.value = "auto"
def temp = device.latestValue("temperature")
def heatingSetpoint = device.latestValue("heatingSetpoint")
def coolingSetpoint = device.latestValue("coolingSetpoint")
if (temp && heatingSetpoint && coolingSetpoint) {
if (temp < (heatingSetpoint + coolingSetpoint) / 2.0) {
thermostatSetpoint = heatingSetpoint
} else {
thermostatSetpoint = coolingSetpoint
}
}
break
}
state.lastTriedMode = map.value
if (thermostatSetpoint) {
[ createEvent(map), createEvent(name: "thermostatSetpoint", value: thermostatSetpoint, unit: getTemperatureScale()) ]
} else {
createEvent(map)
}
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport cmd) {
def map = [name: "thermostatFanMode", displayed: false]
switch (cmd.fanMode) {
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_AUTO_LOW:
map.value = "fanAuto"
break
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_LOW:
map.value = "fanOn"
break
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_CIRCULATION:
map.value = "fanCirculate"
break
}
state.lastTriedFanMode = map.value
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSupportedReport cmd) {
def supportedModes = ""
if(cmd.off) { supportedModes += "off " }
if(cmd.heat) { supportedModes += "heat " }
if(cmd.auxiliaryemergencyHeat) { supportedModes += "emergency heat " }
if(cmd.cool) { supportedModes += "cool " }
if(cmd.auto) { supportedModes += "auto " }
state.supportedModes = supportedModes
[ createEvent(name:"supportedModes", value: supportedModes, displayed: false),
response(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet()) ]
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeSupportedReport cmd) {
def supportedFanModes = ""
if(cmd.auto) { supportedFanModes += "fanAuto " }
if(cmd.low) { supportedFanModes += "fanOn " }
if(cmd.circulation) { supportedFanModes += "fanCirculate " }
state.supportedFanModes = supportedFanModes
[ createEvent(name:"supportedFanModes", value: supportedModes, displayed: false),
response(refresh()) ]
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
log.debug "Zwave event received: $cmd"
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} battery is low"
map.isStateChange = true
} else {
map.value = cmd.batteryLevel
}
state.lastbatt = now()
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.warn "Unexpected zwave command $cmd"
}
def refresh() {
// Use encapsulation to differentiate refresh cmds from what the thermostat sends proactively on change
def cmd = zwave.sensorMultilevelV2.sensorMultilevelGet()
zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:1).encapsulate(cmd).format()
}
def nextRefreshQuery(name) {
def cmd = null
switch (name) {
case "temperature":
cmd = zwave.thermostatModeV2.thermostatModeGet()
break
case "thermostatMode":
cmd = zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1)
break
case "heatingSetpoint":
cmd = zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2)
break
case "coolingSetpoint":
cmd = zwave.thermostatFanModeV3.thermostatFanModeGet()
break
case "thermostatFanMode":
cmd = zwave.thermostatOperatingStateV2.thermostatOperatingStateGet()
break
case "thermostatOperatingState":
// get humidity, multilevel sensor get to endpoint 2
cmd = zwave.sensorMultilevelV2.sensorMultilevelGet()
return zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:2).encapsulate(cmd).format()
default: return null
}
zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:1).encapsulate(cmd).format()
}
def quickSetHeat(degrees) {
setHeatingSetpoint(degrees, 1000)
}
def setHeatingSetpoint(degrees, delay = 30000) {
setHeatingSetpoint(degrees.toDouble(), delay)
}
def setHeatingSetpoint(Double degrees, Integer delay = 30000) {
log.trace "setHeatingSetpoint($degrees, $delay)"
def deviceScale = state.scale ?: 1
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
}
delayBetween([
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 1, scale: deviceScale, precision: p, scaledValue: convertedDegrees).format(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format()
], delay)
}
def quickSetCool(degrees) {
setCoolingSetpoint(degrees, 1000)
}
def setCoolingSetpoint(degrees, delay = 30000) {
setCoolingSetpoint(degrees.toDouble(), delay)
}
def setCoolingSetpoint(Double degrees, Integer delay = 30000) {
log.trace "setCoolingSetpoint($degrees, $delay)"
def deviceScale = state.scale ?: 1
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
}
delayBetween([
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 2, scale: deviceScale, precision: p, scaledValue: convertedDegrees).format(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format()
], delay)
}
def configure() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
], 2300)
}
def modes() {
["off", "heat", "cool", "auto", "emergency heat"]
}
def switchMode() {
def currentMode = device.currentState("thermostatMode")?.value
def lastTriedMode = state.lastTriedMode ?: currentMode ?: "off"
def supportedModes = getDataByName("supportedModes")
def modeOrder = modes()
def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] }
def nextMode = next(lastTriedMode)
if (supportedModes?.contains(currentMode)) {
while (!supportedModes.contains(nextMode) && nextMode != "off") {
nextMode = next(nextMode)
}
}
state.lastTriedMode = nextMode
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[nextMode]).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
], 1000)
}
def switchToMode(nextMode) {
def supportedModes = getDataByName("supportedModes")
if(supportedModes && !supportedModes.contains(nextMode)) log.warn "thermostat mode '$nextMode' is not supported"
if (nextMode in modes()) {
state.lastTriedMode = nextMode
"$nextMode"()
} else {
log.debug("no mode method '$nextMode'")
}
}
def switchFanMode() {
def currentMode = device.currentState("thermostatFanMode")?.value
def lastTriedMode = state.lastTriedFanMode ?: currentMode ?: "off"
def supportedModes = getDataByName("supportedFanModes") ?: "fanAuto fanOn"
def modeOrder = ["fanAuto", "fanCirculate", "fanOn"]
def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] }
def nextMode = next(lastTriedMode)
while (!supportedModes?.contains(nextMode) && nextMode != "fanAuto") {
nextMode = next(nextMode)
}
switchToFanMode(nextMode)
}
def switchToFanMode(nextMode) {
def supportedFanModes = getDataByName("supportedFanModes")
if(supportedFanModes && !supportedFanModes.contains(nextMode)) log.warn "thermostat mode '$nextMode' is not supported"
def returnCommand
if (nextMode == "fanAuto") {
returnCommand = fanAuto()
} else if (nextMode == "fanOn") {
returnCommand = fanOn()
} else if (nextMode == "fanCirculate") {
returnCommand = fanCirculate()
} else {
log.debug("no fan mode '$nextMode'")
}
if(returnCommand) state.lastTriedFanMode = nextMode
returnCommand
}
def getDataByName(String name) {
state[name] ?: device.getDataValue(name)
}
def getModeMap() { [
"off": 0,
"heat": 1,
"cool": 2,
"auto": 3,
"emergency heat": 4
]}
def setThermostatMode(String value) {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[value]).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
], standardDelay)
}
def getFanModeMap() { [
"auto": 0,
"on": 1,
"circulate": 6
]}
def setThermostatFanMode(String value) {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[value]).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
], standardDelay)
}
def off() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: 0).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
], standardDelay)
}
def heat() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: 1).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
], standardDelay)
}
def emergencyHeat() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: 4).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
], standardDelay)
}
def cool() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: 2).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
], standardDelay)
}
def auto() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: 3).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
], standardDelay)
}
def fanOn() {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 1).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
], standardDelay)
}
def fanAuto() {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 0).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
], standardDelay)
}
def fanCirculate() {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 6).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
], standardDelay)
}
private getStandardDelay() {
1000
}
def coolLevelUp(){
int nextLevel = device.currentValue("coolingSetpoint") + 1
if( nextLevel > 99){
nextLevel = 99
}
log.debug "Setting cool set point up to: ${nextLevel}"
setCoolingSetpoint(nextLevel)
}
def coolLevelDown(){
int nextLevel = device.currentValue("coolingSetpoint") - 1
if( nextLevel < 50){
nextLevel = 50
}
log.debug "Setting cool set point down to: ${nextLevel}"
setCoolingSetpoint(nextLevel)
}
def heatLevelUp(){
int nextLevel = device.currentValue("heatingSetpoint") + 1
if( nextLevel > 90){
nextLevel = 90
}
log.debug "Setting heat set point up to: ${nextLevel}"
setHeatingSetpoint(nextLevel)
}
def heatLevelDown(){
int nextLevel = device.currentValue("heatingSetpoint") - 1
if( nextLevel < 40){
nextLevel = 40
}
log.debug "Setting heat set point down to: ${nextLevel}"
setHeatingSetpoint(nextLevel)
}

View File

@@ -0,0 +1,200 @@
/**
* 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.
*
* lg kahn smart app to turn device on when temp is between two values
* and off otherwise. Also has to be between 2 date ranges.
* also give alerts when turning on off.
* I use for a roof heater wire/coil.
*
* Author: LGKahn kahn-st@lgk.com
*/
definition(
name: "Roof Coil Controller",
namespace: "smartthings",
author: "lgkahn",
description: "Control a roof coil or othe device(s) when temperature is between two values turns on and also has to be within a date range. Automatically turns off if one of the conditions is not met. Alerting option also.",
category: "Green Living",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Meta/temp_thermo-switch.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Meta/temp_thermo-switch@2x.png"
)
preferences {
section("Choose a temperature sensor... "){
input "sensor", "capability.temperatureMeasurement", title: "Sensor"
}
section("Select the outlet(s)... "){
input "outlets", "capability.switch", title: "Outlets", multiple: true
}
section("Turn on when temp is above ..."){
input "onSetPoint", "decimal", title: "Set On Temp"
}
section("Turn off when temp is above ..."){
input "offSetPoint", "decimal", title: "Set Off Temp"
}
section("Start after Date format (yyyymmdd)..."){
input "startDate", "number", title: "Date?"
}
section("End after Date format (yyyymmdd)..."){
input "endDate", "number", title: "Date?"
}
section("Time Zone Offset ie -5 etc...."){
input "tzOffset", "number", title: "Offset?", range: "-12..12"
}
section( "Notifications" ) {
input("recipients", "contact", title: "Send notifications to") {
input "sendPushMessage", "enum", title: "Send a push notification?", options: ["Yes", "No"], required: false
input "phone1", "phone", title: "Send a Text Message?", required: false
}
}
}
def installed()
{
log.debug "in coil controller installed ... currenttemp = $sensor.currentTemperature"
subscribe(sensor, "temperature", temperatureHandler)
}
def updated()
{
log.debug "in coil controller updated ... currenttemp = $sensor.currentTemperature"
unsubscribe()
subscribe(sensor, "temperature", temperatureHandler)
// for debugging and testing uncomment temperatureHandlerTest()
}
def temperatureHandler(evt)
{
def currenttemp = sensor.currentTemperature
/*
log.debug "in temp handler"
log.debug "current temp = $currenttemp"
log.debug "onSetPoint = $onSetPoint"
log.debug "offSetPoint = $offSetPoint"
log.debug "set offset = $tzOffset"
*/
def today = new Date();
def ltf = new java.text.SimpleDateFormat("yyyyMMdd")
ltf.setTimeZone(TimeZone.getTimeZone("GMT${tzOffset}"))
String date1 = ltf.format(today);
int intdate = Integer.parseInt(date1)
// log.debug "int date = $intdate"
//log.debug "enddate = $endDate"
// log.debug "startdate = $startDate"
def currSwitches = outlets.currentSwitch
def onOutlets = currSwitches.findAll { switchVal ->
switchVal == "on" ? true : false }
if (((intdate >= startDate) && (intdate <= endDate))
&& ((currenttemp > onSetPoint) && (currenttemp < offSetPoint)))
{
// dont do anything if already on
if (onOutlets.size() != outlets.size())
{
log.debug "turning outlets On as $sensor.displayName is reporting $currenttemp which is between $onSetPoint and $offSetPoint, and we are within the date range ($startDate - $endDate)!"
mysend("Turning device(s) On as $sensor.displayName is reporting a temperature of $currenttemp which is between $onSetPoint and $offSetPoint, and we are within the date range ($startDate - $endDate)!")
outlets.on()
}
else log.debug "Not turning on again, all already on!"
}
else
{
// dont do anything if already off
if (onOutlets.size() != 0)
{
log.debug "turning outlets Off! as $sensor.displayName is reporting $currenttemp which is Not between $onSetPoint and $offSetPoint, or we are no longer within the date range ($startDate - $endDate)!"
mysend("Turning device(s) Off as $sensor.displayName is reporting a temperature of $currenttemp which is not between $onSetPoint and $offSetPoint, or we are no longer within the date range ($startDate - $endDate)!")
outlets.off()
}
else log.debug "All outlets already off!"
}
}
def temperatureHandlerTest()
{
//log.trace "temperature: $evt.value, $evt"
// this routine is only for testing and debugging. to test or make changes uncomment the call in update.
// this is so we dont have to wait 15 minutes till a half an hour for the event to fire for testing.
def currenttemp = sensor.currentTemperature
log.debug "in temp handler test"
log.debug "current temp = $currenttemp"
log.debug "onSetPoint = $onSetPoint"
log.debug "offSetPoint = $offSetPoint"
log.debug "set offset = $tzOffset"
def today = new Date();
def ltf = new java.text.SimpleDateFormat("yyyyMMdd")
ltf.setTimeZone(TimeZone.getTimeZone("GMT${tzOffset}"))
String date1 = ltf.format(today);
int intdate = Integer.parseInt(date1)
log.debug "int date = $intdate"
log.debug "enddate = $endDate"
log.debug "startdate = $startDate"
def currSwitches = outlets.currentSwitch
def onOutlets = currSwitches.findAll { switchVal ->
switchVal == "on" ? true : false }
log.debug "how many on = ${onOutlets.size()} "
if (((intdate >= startDate) && (intdate <= endDate))
&& ((currenttemp > onSetPoint) && (currenttemp < offSetPoint)))
{
// dont do anything if already on
if (onOutlets.size() != outlets.size())
{
log.debug "turning outlets On as $sensor.displayName is reporting $currenttemp which is between $onSetPoint and $offSetPoint, and we are within the date range ($startDate - $endDate)!"
//mysend("Turning device(s) On as $sensor.displayName is reporting a temperature of $currenttemp which is between $onSetPoint and $offSetPoint, and we are within the date range ($startDate - $endDate)!")
outlets.on()
}
else log.debug "Not turning on again, all already on!"
}
else
{
// dont do anything if already off
if (onOutlets.size() != 0)
{
log.debug "turning outlets Off! as $sensor.displayName is reporting $currenttemp which is Not between $onSetPoint and $offSetPoint, or we are no longer within the date range ($startDate - $endDate)!"
//mysend("Turning device(s) Off as $sensor.displayName is reporting a temperature of $currenttemp which is not between $onSetPoint and $offSetPoint, or we are no longer within the date range ($startDate - $endDate)!")
outlets.off()
}
else log.debug "All outlets already off!"
}
}
private mysend(msg) {
if (location.contactBookEnabled) {
log.debug("sending notifications to: ${recipients?.size()}")
sendNotificationToContacts(msg, recipients)
}
else {
if (sendPushMessage != "No") {
log.debug("sending push message")
sendPush(msg)
}
if (phone1) {
log.debug("sending text message")
sendSms(phone1, msg)
}
}
log.debug msg
}