mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-15 21:03:23 +00:00
Compare commits
33 Commits
master_old
...
MSA-736-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f1f5fee2f | ||
|
|
30844676b6 | ||
|
|
94aa114ccb | ||
|
|
a9e68d086c | ||
|
|
d427ab8709 | ||
|
|
a205a94d78 | ||
|
|
e775752496 | ||
|
|
9318e9a311 | ||
|
|
e1c52454c6 | ||
|
|
145fce2062 | ||
|
|
e9996b9fd7 | ||
|
|
8be585e544 | ||
|
|
e114fafd56 | ||
|
|
e6367a7832 | ||
|
|
c5da3fe4a0 | ||
|
|
1b9d2fe9ce | ||
|
|
90dee51255 | ||
|
|
7b7fdd43cd | ||
|
|
9059718818 | ||
|
|
9d7c66c7af | ||
|
|
8e81967227 | ||
|
|
290e8e4129 | ||
|
|
8c6c68f102 | ||
|
|
661f8b3bc0 | ||
|
|
a62d825f69 | ||
|
|
1890147221 | ||
|
|
2fb5f8c78c | ||
|
|
b44356248c | ||
|
|
c30af84d70 | ||
|
|
5cf72c644c | ||
|
|
8ae9b06022 | ||
|
|
71fc8e7f5f | ||
|
|
30dedde0df |
@@ -15,6 +15,7 @@
|
|||||||
* Author: SmartThings
|
* Author: SmartThings
|
||||||
* Date: 2013-12-04
|
* Date: 2013-12-04
|
||||||
*/
|
*/
|
||||||
|
//DEPRECATED - Using the generic DTH for this device. Users need to be moved before deleting this DTH
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "CentraLite Dimmer", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "CentraLite Dimmer", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Switch Level"
|
capability "Switch Level"
|
||||||
@@ -25,7 +26,6 @@ metadata {
|
|||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B04,0B05", outClusters: "0019"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulator metadata
|
// simulator metadata
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* Ecobee Sensor
|
||||||
|
*
|
||||||
|
* Copyright 2015 Juan Risso
|
||||||
|
*
|
||||||
|
* 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 {
|
||||||
|
definition (name: "Ecobee Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||||
|
capability "Sensor"
|
||||||
|
capability "Temperature Measurement"
|
||||||
|
capability "Motion Sensor"
|
||||||
|
capability "Refresh"
|
||||||
|
capability "Polling"
|
||||||
|
}
|
||||||
|
|
||||||
|
simulator {
|
||||||
|
// TODO: define status and reply messages here
|
||||||
|
}
|
||||||
|
|
||||||
|
tiles {
|
||||||
|
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
|
state("temperature", label:'${currentValue}°', 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("motion", "device.motion") {
|
||||||
|
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
|
||||||
|
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
|
||||||
|
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
}
|
||||||
|
|
||||||
|
main (["temperature","motion"])
|
||||||
|
details(["temperature","motion","refresh"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def refresh() {
|
||||||
|
log.debug "refresh..."
|
||||||
|
poll()
|
||||||
|
}
|
||||||
|
|
||||||
|
void poll() {
|
||||||
|
log.debug "Executing 'poll' using parent SmartApp"
|
||||||
|
parent.pollChildren(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
//generate custom mobile activity feeds event
|
||||||
|
def generateActivityFeedsEvent(notificationMessage) {
|
||||||
|
sendEvent(name: "notificationMessage", value: "$device.displayName $notificationMessage", descriptionText: "$device.displayName $notificationMessage", displayed: true)
|
||||||
|
}
|
||||||
@@ -35,18 +35,18 @@ metadata {
|
|||||||
|
|
||||||
simulator { }
|
simulator { }
|
||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
state("temperature", label:'${currentValue}°', unit:"F",
|
state("temperature", label:'${currentValue}°', unit:"F",
|
||||||
backgroundColors:[
|
backgroundColors:[
|
||||||
[value: 31, color: "#153591"],
|
[value: 31, color: "#153591"],
|
||||||
[value: 44, color: "#1e9cbb"],
|
[value: 44, color: "#1e9cbb"],
|
||||||
[value: 59, color: "#90d2a7"],
|
[value: 59, color: "#90d2a7"],
|
||||||
[value: 74, color: "#44b621"],
|
[value: 74, color: "#44b621"],
|
||||||
[value: 84, color: "#f1d801"],
|
[value: 84, color: "#f1d801"],
|
||||||
[value: 95, color: "#d04e00"],
|
[value: 95, color: "#d04e00"],
|
||||||
[value: 96, color: "#bc2323"]
|
[value: 96, color: "#bc2323"]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
standardTile("mode", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
|
standardTile("mode", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
|
||||||
@@ -55,7 +55,7 @@ metadata {
|
|||||||
state "cool", action:"switchMode", nextState: "updating", icon: "st.thermostat.cool"
|
state "cool", action:"switchMode", nextState: "updating", icon: "st.thermostat.cool"
|
||||||
state "auto", action:"switchMode", nextState: "updating", icon: "st.thermostat.auto"
|
state "auto", action:"switchMode", nextState: "updating", icon: "st.thermostat.auto"
|
||||||
state "auxHeatOnly", action:"switchMode", icon: "st.thermostat.emergency-heat"
|
state "auxHeatOnly", action:"switchMode", icon: "st.thermostat.emergency-heat"
|
||||||
state "updating", label:"Working", icon: "st.secondary.secondary"
|
state "updating", label:"Working", icon: "st.secondary.secondary"
|
||||||
}
|
}
|
||||||
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
|
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
|
||||||
state "auto", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "on"
|
state "auto", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "on"
|
||||||
@@ -63,17 +63,17 @@ metadata {
|
|||||||
state "off", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "circulate"
|
state "off", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "circulate"
|
||||||
state "circulate", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "auto"
|
state "circulate", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "auto"
|
||||||
}
|
}
|
||||||
standardTile("upButtonControl", "device.thermostatSetpoint", inactiveLabel: false, decoration: "flat") {
|
standardTile("upButtonControl", "device.thermostatSetpoint", inactiveLabel: false, decoration: "flat") {
|
||||||
state "setpoint", action:"raiseSetpoint", backgroundColor:"#d04e00", icon:"st.thermostat.thermostat-up"
|
state "setpoint", action:"raiseSetpoint", icon:"st.thermostat.thermostat-up"
|
||||||
}
|
}
|
||||||
valueTile("thermostatSetpoint", "device.thermostatSetpoint", width: 1, height: 1, decoration: "flat") {
|
valueTile("thermostatSetpoint", "device.thermostatSetpoint", width: 1, height: 1, decoration: "flat") {
|
||||||
state "thermostatSetpoint", label:'${currentValue}'
|
state "thermostatSetpoint", label:'${currentValue}°'
|
||||||
}
|
}
|
||||||
valueTile("currentStatus", "device.thermostatStatus", height: 1, width: 2, decoration: "flat") {
|
valueTile("currentStatus", "device.thermostatStatus", height: 1, width: 2, decoration: "flat") {
|
||||||
state "thermostatStatus", label:'${currentValue}', backgroundColor:"#ffffff"
|
state "thermostatStatus", label:'${currentValue}', backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
standardTile("downButtonControl", "device.thermostatSetpoint", inactiveLabel: false, decoration: "flat") {
|
standardTile("downButtonControl", "device.thermostatSetpoint", inactiveLabel: false, decoration: "flat") {
|
||||||
state "setpoint", action:"lowerSetpoint", backgroundColor:"#d04e00", icon:"st.thermostat.thermostat-down"
|
state "setpoint", action:"lowerSetpoint", icon:"st.thermostat.thermostat-down"
|
||||||
}
|
}
|
||||||
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
||||||
state "setHeatingSetpoint", action:"thermostat.setHeatingSetpoint", backgroundColor:"#d04e00"
|
state "setHeatingSetpoint", action:"thermostat.setHeatingSetpoint", backgroundColor:"#d04e00"
|
||||||
@@ -91,25 +91,19 @@ metadata {
|
|||||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
standardTile("resumeProgram", "device.resumeProgram", inactiveLabel: false, decoration: "flat") {
|
standardTile("resumeProgram", "device.resumeProgram", inactiveLabel: false, decoration: "flat") {
|
||||||
state "resume", label:'Resume Program', action:"device.resumeProgram", icon:"st.sonos.play-icon"
|
state "resume", action:"resumeProgram", nextState: "updating", label:'Resume Schedule', icon:"st.samsung.da.oven_ic_send"
|
||||||
|
state "updating", label:"Working", icon: "st.secondary.secondary"
|
||||||
}
|
}
|
||||||
main "temperature"
|
main "temperature"
|
||||||
details(["temperature", "upButtonControl", "thermostatSetpoint", "currentStatus", "downButtonControl", "mode", "resumeProgram", "refresh"])
|
details(["temperature", "upButtonControl", "thermostatSetpoint", "currentStatus", "downButtonControl", "mode", "resumeProgram", "refresh"])
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
input "holdType", "enum", title: "Hold Type", description: "When changing temperature, use Temporary or Permanent hold (default)", required: false, options:["Temporary", "Permanent"]
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
preferences {
|
|
||||||
input "highTemperature", "number", title: "Auto Mode High Temperature:", defaultValue: 80
|
|
||||||
input "lowTemperature", "number", title: "Auto Mode Low Temperature:", defaultValue: 70
|
|
||||||
input name: "holdType", type: "enum", title: "Hold Type", description: "When changing temperature, use Temporary or Permanent hold", required: true, options:["Temporary", "Permanent"]
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.debug "Parsing '${description}'"
|
log.debug "Parsing '${description}'"
|
||||||
@@ -117,192 +111,176 @@ def parse(String description) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh()
|
def refresh() {
|
||||||
{
|
log.debug "refresh called"
|
||||||
log.debug "refresh called"
|
poll()
|
||||||
poll()
|
log.debug "refresh ended"
|
||||||
log.debug "refresh ended"
|
|
||||||
}
|
|
||||||
|
|
||||||
def go()
|
|
||||||
{
|
|
||||||
log.debug "before:go tile tapped"
|
|
||||||
poll()
|
|
||||||
log.debug "after"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void poll() {
|
void poll() {
|
||||||
log.debug "Executing 'poll' using parent SmartApp"
|
log.debug "Executing 'poll' using parent SmartApp"
|
||||||
|
|
||||||
def results = parent.pollChild(this)
|
def results = parent.pollChild(this)
|
||||||
parseEventData(results)
|
generateEvent(results) //parse received message from parent
|
||||||
generateStatusEvent()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def parseEventData(Map results)
|
def generateEvent(Map results) {
|
||||||
{
|
|
||||||
log.debug "parsing data $results"
|
log.debug "parsing data $results"
|
||||||
if(results)
|
if(results) {
|
||||||
{
|
|
||||||
results.each { name, value ->
|
results.each { name, value ->
|
||||||
|
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
def isChange = false
|
def isChange = false
|
||||||
def isDisplayed = true
|
def isDisplayed = true
|
||||||
|
def event = [name: name, linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText),
|
||||||
|
handlerName: name]
|
||||||
|
|
||||||
if (name=="temperature" || name=="heatingSetpoint" || name=="coolingSetpoint") {
|
if (name=="temperature" || name=="heatingSetpoint" || name=="coolingSetpoint") {
|
||||||
|
def sendValue = value? convertTemperatureIfNeeded(value.toDouble(), "F", 1): value //API return temperature value in F
|
||||||
isChange = isTemperatureStateChange(device, name, value.toString())
|
isChange = isTemperatureStateChange(device, name, value.toString())
|
||||||
isDisplayed = isChange
|
isDisplayed = isChange
|
||||||
|
event << [value: sendValue, isStateChange: isChange, displayed: isDisplayed]
|
||||||
sendEvent(
|
} else if (name=="heatMode" || name=="coolMode" || name=="autoMode" || name=="auxHeatMode"){
|
||||||
name: name,
|
isChange = isStateChange(device, name, value.toString())
|
||||||
value: value,
|
event << [value: value.toString(), isStateChange: isChange, displayed: false]
|
||||||
unit: "F",
|
} else {
|
||||||
linkText: linkText,
|
isChange = isStateChange(device, name, value.toString())
|
||||||
descriptionText: getThermostatDescriptionText(name, value, linkText),
|
isDisplayed = isChange
|
||||||
handlerName: name,
|
event << [value: value.toString(), isStateChange: isChange, displayed: isDisplayed]
|
||||||
isStateChange: isChange,
|
}
|
||||||
displayed: isDisplayed)
|
sendEvent(event)
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
isChange = isStateChange(device, name, value.toString())
|
|
||||||
isDisplayed = isChange
|
|
||||||
|
|
||||||
sendEvent(
|
|
||||||
name: name,
|
|
||||||
value: value.toString(),
|
|
||||||
linkText: linkText,
|
|
||||||
descriptionText: getThermostatDescriptionText(name, value, linkText),
|
|
||||||
handlerName: name,
|
|
||||||
isStateChange: isChange,
|
|
||||||
displayed: isDisplayed)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
generateSetpointEvent ()
|
generateSetpointEvent ()
|
||||||
generateStatusEvent ()
|
generateStatusEvent ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void generateEvent(Map results)
|
//return descriptionText to be shown on mobile activity feed
|
||||||
{
|
private getThermostatDescriptionText(name, value, linkText) {
|
||||||
log.debug "parsing data $results"
|
if(name == "temperature") {
|
||||||
if(results)
|
return "$linkText temperature is $value°F"
|
||||||
{
|
|
||||||
results.each { name, value ->
|
|
||||||
|
|
||||||
def linkText = getLinkText(device)
|
} else if(name == "heatingSetpoint") {
|
||||||
def isChange = false
|
return "heating setpoint is $value°F"
|
||||||
def isDisplayed = true
|
|
||||||
|
|
||||||
if (name=="temperature" || name=="heatingSetpoint" || name=="coolingSetpoint") {
|
} else if(name == "coolingSetpoint"){
|
||||||
isChange = isTemperatureStateChange(device, name, value.toString())
|
return "cooling setpoint is $value°F"
|
||||||
isDisplayed = isChange
|
|
||||||
|
|
||||||
sendEvent(
|
} else if (name == "thermostatMode") {
|
||||||
name: name,
|
return "thermostat mode is ${value}"
|
||||||
value: value,
|
|
||||||
unit: "F",
|
|
||||||
linkText: linkText,
|
|
||||||
descriptionText: getThermostatDescriptionText(name, value, linkText),
|
|
||||||
handlerName: name,
|
|
||||||
isStateChange: isChange,
|
|
||||||
displayed: isDisplayed)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
isChange = isStateChange(device, name, value.toString())
|
|
||||||
isDisplayed = isChange
|
|
||||||
|
|
||||||
sendEvent(
|
} else if (name == "thermostatFanMode") {
|
||||||
name: name,
|
return "thermostat fan mode is ${value}"
|
||||||
value: value.toString(),
|
|
||||||
linkText: linkText,
|
|
||||||
descriptionText: getThermostatDescriptionText(name, value, linkText),
|
|
||||||
handlerName: name,
|
|
||||||
isStateChange: isChange,
|
|
||||||
displayed: isDisplayed)
|
|
||||||
|
|
||||||
}
|
} else {
|
||||||
}
|
return "${name} = ${value}"
|
||||||
generateSetpointEvent ()
|
|
||||||
generateStatusEvent()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getThermostatDescriptionText(name, value, linkText)
|
void setHeatingSetpoint(setpoint) {
|
||||||
{
|
setHeatingSetpoint(setpoint.toDouble())
|
||||||
if(name == "temperature")
|
}
|
||||||
{
|
|
||||||
return "$linkText was $value°F"
|
void setHeatingSetpoint(Double setpoint) {
|
||||||
|
// def mode = device.currentValue("thermostatMode")
|
||||||
|
def heatingSetpoint = setpoint
|
||||||
|
def coolingSetpoint = device.currentValue("coolingSetpoint").toDouble()
|
||||||
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
|
|
||||||
|
//enforce limits of heatingSetpoint
|
||||||
|
if (heatingSetpoint > 79) {
|
||||||
|
heatingSetpoint = 79
|
||||||
|
} else if (heatingSetpoint < 45) {
|
||||||
|
heatingSetpoint = 45
|
||||||
}
|
}
|
||||||
else if(name == "heatingSetpoint")
|
|
||||||
{
|
//enforce limits of heatingSetpoint vs coolingSetpoint
|
||||||
return "latest heating setpoint was $value°F"
|
if (heatingSetpoint >= coolingSetpoint) {
|
||||||
|
coolingSetpoint = heatingSetpoint
|
||||||
}
|
}
|
||||||
else if(name == "coolingSetpoint")
|
|
||||||
{
|
log.debug "Sending setHeatingSetpoint> coolingSetpoint: ${coolingSetpoint}, heatingSetpoint: ${heatingSetpoint}"
|
||||||
return "latest cooling setpoint was $value°F"
|
|
||||||
|
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
|
||||||
|
if (parent.setHold (this, heatingSetpoint, coolingSetpoint, deviceId, sendHoldType)) {
|
||||||
|
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint)
|
||||||
|
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint)
|
||||||
|
log.debug "Done setHeatingSetpoint> coolingSetpoint: ${coolingSetpoint}, heatingSetpoint: ${heatingSetpoint}"
|
||||||
|
generateSetpointEvent()
|
||||||
|
generateStatusEvent()
|
||||||
|
} else {
|
||||||
|
log.error "Error setHeatingSetpoint(setpoint)" //This error is handled by the connect app
|
||||||
}
|
}
|
||||||
else if (name == "thermostatMode")
|
|
||||||
{
|
|
||||||
return "thermostat mode is ${value}"
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return "${name} = ${value}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setCoolingSetpoint(setpoint) {
|
||||||
void setHeatingSetpoint(degreesF) {
|
setCoolingSetpoint(setpoint.toDouble())
|
||||||
setHeatingSetpoint(degreesF.toDouble())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHeatingSetpoint(Double degreesF) {
|
void setCoolingSetpoint(Double setpoint) {
|
||||||
log.debug "setHeatingSetpoint({$degreesF})"
|
// def mode = device.currentValue("thermostatMode")
|
||||||
sendEvent("name":"heatingSetpoint", "value":degreesF)
|
def heatingSetpoint = device.currentValue("heatingSetpoint").toDouble()
|
||||||
Double coolingSetpoint = device.currentValue("coolingSetpoint")
|
def coolingSetpoint = setpoint
|
||||||
log.debug "coolingSetpoint: $coolingSetpoint"
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
parent.setHold(this, degreesF, coolingSetpoint)
|
|
||||||
|
if (coolingSetpoint > 92) {
|
||||||
|
coolingSetpoint = 92
|
||||||
|
} else if (coolingSetpoint < 65) {
|
||||||
|
coolingSetpoint = 65
|
||||||
|
}
|
||||||
|
|
||||||
|
//enforce limits of heatingSetpoint vs coolingSetpoint
|
||||||
|
if (heatingSetpoint >= coolingSetpoint) {
|
||||||
|
heatingSetpoint = coolingSetpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug "Sending setCoolingSetpoint> coolingSetpoint: ${coolingSetpoint}, heatingSetpoint: ${heatingSetpoint}"
|
||||||
|
|
||||||
|
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
|
||||||
|
if (parent.setHold (this, heatingSetpoint, coolingSetpoint, deviceId, sendHoldType)) {
|
||||||
|
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint)
|
||||||
|
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint)
|
||||||
|
log.debug "Done setCoolingSetpoint>> coolingSetpoint = ${coolingSetpoint}, heatingSetpoint = ${heatingSetpoint}"
|
||||||
|
generateSetpointEvent()
|
||||||
|
generateStatusEvent()
|
||||||
|
} else {
|
||||||
|
log.error "Error setCoolingSetpoint(setpoint)" //This error is handled by the connect app
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCoolingSetpoint(degreesF) {
|
void resumeProgram() {
|
||||||
setCoolingSetpoint(degreesF.toDouble())
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCoolingSetpoint(Double degreesF) {
|
log.debug "resumeProgram() is called"
|
||||||
log.debug "setCoolingSetpoint({$degreesF})"
|
sendEvent("name":"thermostatStatus", "value":"resuming schedule", "description":statusText, displayed: false)
|
||||||
sendEvent("name":"coolingSetpoint", "value":degreesF)
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
Double heatingSetpoint = device.currentValue("heatingSetpoint")
|
if (parent.resumeProgram(this, deviceId)) {
|
||||||
parent.setHold(this, heatingSetpoint, degreesF)
|
sendEvent("name":"thermostatStatus", "value":"setpoint is updating", "description":statusText, displayed: false)
|
||||||
}
|
runIn(5, "poll")
|
||||||
|
log.debug "resumeProgram() is done"
|
||||||
|
sendEvent("name":"resumeProgram", "value":"resume", descriptionText: "resumeProgram is done", displayed: false, isStateChange: true)
|
||||||
|
} else {
|
||||||
|
sendEvent("name":"thermostatStatus", "value":"failed resume click refresh", "description":statusText, displayed: false)
|
||||||
|
log.error "Error resumeProgram() check parent.resumeProgram(this, deviceId)"
|
||||||
|
}
|
||||||
|
|
||||||
def configure() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def resumeProgram() {
|
|
||||||
parent.resumeProgram(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def modes() {
|
def modes() {
|
||||||
if (state.modes) {
|
if (state.modes) {
|
||||||
log.debug "Modes = ${state.modes}"
|
log.debug "Modes = ${state.modes}"
|
||||||
return state.modes
|
return state.modes
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
state.modes = parent.availableModes(this)
|
state.modes = parent.availableModes(this)
|
||||||
log.debug "Modes = ${state.modes}"
|
log.debug "Modes = ${state.modes}"
|
||||||
return state.modes
|
return state.modes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def fanModes() {
|
def fanModes() {
|
||||||
["off", "on", "auto", "circulate"]
|
["off", "on", "auto", "circulate"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def switchMode() {
|
def switchMode() {
|
||||||
log.debug "in switchMode"
|
log.debug "in switchMode"
|
||||||
def currentMode = device.currentState("thermostatMode")?.value
|
def currentMode = device.currentState("thermostatMode")?.value
|
||||||
@@ -314,7 +292,7 @@ def switchMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def switchToMode(nextMode) {
|
def switchToMode(nextMode) {
|
||||||
log.debug "In switchToMode = ${nextMode}"
|
log.debug "In switchToMode = ${nextMode}"
|
||||||
if (nextMode in modes()) {
|
if (nextMode in modes()) {
|
||||||
state.lastTriedMode = nextMode
|
state.lastTriedMode = nextMode
|
||||||
"$nextMode"()
|
"$nextMode"()
|
||||||
@@ -386,290 +364,316 @@ def setThermostatFanMode(String value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generateModeEvent(mode) {
|
def generateModeEvent(mode) {
|
||||||
|
sendEvent(name: "thermostatMode", value: mode, descriptionText: "$device.displayName is in ${mode} mode", displayed: true)
|
||||||
sendEvent(name: "thermostatMode", value: mode, descriptionText: "$device.displayName is in ${mode} mode", displayed: true, isStateChange: true)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateFanModeEvent(fanMode) {
|
def generateFanModeEvent(fanMode) {
|
||||||
|
sendEvent(name: "thermostatFanMode", value: fanMode, descriptionText: "$device.displayName fan is in ${mode} mode", displayed: true)
|
||||||
sendEvent(name: "thermostatFanMode", value: fanMode, descriptionText: "$device.displayName fan is in ${mode} mode", displayed: true, isStateChange: true)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateOperatingStateEvent(operatingState) {
|
def generateOperatingStateEvent(operatingState) {
|
||||||
|
sendEvent(name: "thermostatOperatingState", value: operatingState, descriptionText: "$device.displayName is ${operatingState}", displayed: true)
|
||||||
sendEvent(name: "thermostatOperatingState", value: operatingState, descriptionText: "$device.displayName is ${operatingState}", displayed: true, isStateChange: true)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
log.debug "off"
|
log.debug "off"
|
||||||
generateModeEvent("off")
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
if (parent.setMode (this,"off"))
|
if (parent.setMode (this,"off", deviceId))
|
||||||
generateModeEvent("off")
|
generateModeEvent("off")
|
||||||
else {
|
else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
def currentMode = device.currentState("thermostatMode")?.value
|
def currentMode = device.currentState("thermostatMode")?.value
|
||||||
generateModeEvent(currentMode) // reset the tile back
|
generateModeEvent(currentMode) // reset the tile back
|
||||||
}
|
}
|
||||||
generateSetpointEvent()
|
generateSetpointEvent()
|
||||||
generateStatusEvent()
|
generateStatusEvent()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def heat() {
|
def heat() {
|
||||||
log.debug "heat"
|
log.debug "heat"
|
||||||
generateModeEvent("heat")
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
if (parent.setMode (this,"heat"))
|
if (parent.setMode (this,"heat", deviceId))
|
||||||
generateModeEvent("heat")
|
generateModeEvent("heat")
|
||||||
else {
|
else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
def currentMode = device.currentState("thermostatMode")?.value
|
def currentMode = device.currentState("thermostatMode")?.value
|
||||||
generateModeEvent(currentMode) // reset the tile back
|
generateModeEvent(currentMode) // reset the tile back
|
||||||
}
|
}
|
||||||
generateSetpointEvent()
|
generateSetpointEvent()
|
||||||
generateStatusEvent()
|
generateStatusEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
def auxHeatOnly() {
|
def auxHeatOnly() {
|
||||||
log.debug "auxHeatOnly"
|
log.debug "auxHeatOnly"
|
||||||
generateModeEvent("auxHeatOnly")
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
if (parent.setMode (this,"auxHeatOnly"))
|
if (parent.setMode (this,"auxHeatOnly", deviceId))
|
||||||
generateModeEvent("auxHeatOnly")
|
generateModeEvent("auxHeatOnly")
|
||||||
else {
|
else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
def currentMode = device.currentState("thermostatMode")?.value
|
def currentMode = device.currentState("thermostatMode")?.value
|
||||||
generateModeEvent(currentMode) // reset the tile back
|
generateModeEvent(currentMode) // reset the tile back
|
||||||
}
|
}
|
||||||
generateSetpointEvent()
|
generateSetpointEvent()
|
||||||
generateStatusEvent()
|
generateStatusEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
def cool() {
|
def cool() {
|
||||||
log.debug "cool"
|
log.debug "cool"
|
||||||
generateModeEvent("cool")
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
if (parent.setMode (this,"cool"))
|
if (parent.setMode (this,"cool", deviceId))
|
||||||
generateModeEvent("cool")
|
generateModeEvent("cool")
|
||||||
else {
|
else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
def currentMode = device.currentState("thermostatMode")?.value
|
def currentMode = device.currentState("thermostatMode")?.value
|
||||||
generateModeEvent(currentMode) // reset the tile back
|
generateModeEvent(currentMode) // reset the tile back
|
||||||
}
|
}
|
||||||
generateSetpointEvent()
|
generateSetpointEvent()
|
||||||
generateStatusEvent()
|
generateStatusEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
def auto() {
|
def auto() {
|
||||||
log.debug "auto"
|
log.debug "auto"
|
||||||
generateModeEvent("auto")
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
if (parent.setMode (this,"auto"))
|
if (parent.setMode (this,"auto", deviceId))
|
||||||
generateModeEvent("auto")
|
generateModeEvent("auto")
|
||||||
else {
|
else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
def currentMode = device.currentState("thermostatMode")?.value
|
def currentMode = device.currentState("thermostatMode")?.value
|
||||||
generateModeEvent(currentMode) // reset the tile back
|
generateModeEvent(currentMode) // reset the tile back
|
||||||
}
|
}
|
||||||
generateSetpointEvent()
|
generateSetpointEvent()
|
||||||
generateStatusEvent()
|
generateStatusEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
def fanOn() {
|
def fanOn() {
|
||||||
log.debug "fanOn"
|
log.debug "fanOn"
|
||||||
parent.setFanMode (this,"on")
|
// parent.setFanMode (this,"on")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def fanAuto() {
|
def fanAuto() {
|
||||||
log.debug "fanAuto"
|
log.debug "fanAuto"
|
||||||
parent.setFanMode (this,"auto")
|
// parent.setFanMode (this,"auto")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def fanCirculate() {
|
def fanCirculate() {
|
||||||
log.debug "fanCirculate"
|
log.debug "fanCirculate"
|
||||||
parent.setFanMode (this,"circulate")
|
// parent.setFanMode (this,"circulate")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def fanOff() {
|
def fanOff() {
|
||||||
log.debug "fanOff"
|
log.debug "fanOff"
|
||||||
parent.setFanMode (this,"off")
|
// parent.setFanMode (this,"off")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateSetpointEvent() {
|
def generateSetpointEvent() {
|
||||||
|
|
||||||
log.debug "Generate SetPoint Event"
|
log.debug "Generate SetPoint Event"
|
||||||
|
|
||||||
def mode = device.currentValue("thermostatMode")
|
def mode = device.currentValue("thermostatMode")
|
||||||
log.debug "Current Mode = ${mode}"
|
log.debug "Current Mode = ${mode}"
|
||||||
|
|
||||||
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
|
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
|
||||||
log.debug "Heating Setpoint = ${heatingSetpoint}"
|
log.debug "Heating Setpoint = ${heatingSetpoint}"
|
||||||
|
|
||||||
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
|
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
|
||||||
log.debug "Cooling Setpoint = ${coolingSetpoint}"
|
log.debug "Cooling Setpoint = ${coolingSetpoint}"
|
||||||
|
|
||||||
if (mode == "heat") {
|
if (mode == "heat") {
|
||||||
|
|
||||||
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint.toString()+"°")
|
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint.toString())
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (mode == "cool") {
|
else if (mode == "cool") {
|
||||||
|
|
||||||
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint.toString()+"°")
|
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint.toString())
|
||||||
|
|
||||||
} else if (mode == "auto") {
|
} else if (mode == "auto") {
|
||||||
|
|
||||||
sendEvent("name":"thermostatSetpoint", "value":"Auto")
|
sendEvent("name":"thermostatSetpoint", "value":"Auto")
|
||||||
|
|
||||||
} else if (mode == "off") {
|
} else if (mode == "off") {
|
||||||
|
|
||||||
sendEvent("name":"thermostatSetpoint", "value":"Off")
|
sendEvent("name":"thermostatSetpoint", "value":"Off")
|
||||||
|
|
||||||
} else if (mode == "emergencyHeat") {
|
} else if (mode == "emergencyHeat") {
|
||||||
|
|
||||||
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint.toString()+"°")
|
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint.toString())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void raiseSetpoint() {
|
void raiseSetpoint() {
|
||||||
|
|
||||||
log.debug "Raise SetPoint"
|
|
||||||
|
|
||||||
def mode = device.currentValue("thermostatMode")
|
def mode = device.currentValue("thermostatMode")
|
||||||
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
|
def targetvalue
|
||||||
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
|
|
||||||
|
|
||||||
log.debug "Current Mode = ${mode}"
|
if (mode == "off" || mode == "auto") {
|
||||||
|
log.warn "this mode: $mode does not allow raiseSetpoint"
|
||||||
|
} else {
|
||||||
|
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
|
||||||
|
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
|
||||||
|
def thermostatSetpoint = device.currentValue("thermostatSetpoint").toInteger()
|
||||||
|
log.debug "raiseSetpoint() mode = ${mode}, heatingSetpoint: ${heatingSetpoint}, coolingSetpoint:${coolingSetpoint}, thermostatSetpoint:${thermostatSetpoint}"
|
||||||
|
|
||||||
if (mode == "heat") {
|
if (device.latestState('thermostatSetpoint')) {
|
||||||
|
targetvalue = device.latestState('thermostatSetpoint').value as Integer
|
||||||
|
} else {
|
||||||
|
targetvalue = 0
|
||||||
|
}
|
||||||
|
targetvalue = targetvalue + 1
|
||||||
|
|
||||||
heatingSetpoint++
|
if (mode == "heat" && targetvalue > 79) {
|
||||||
|
targetvalue = 79
|
||||||
|
} else if (mode == "cool" && targetvalue > 92) {
|
||||||
|
targetvalue = 92
|
||||||
|
}
|
||||||
|
|
||||||
if (heatingSetpoint > 99)
|
sendEvent("name":"thermostatSetpoint", "value":targetvalue, displayed: false)
|
||||||
heatingSetpoint = 99
|
log.info "In mode $mode raiseSetpoint() to $targetvalue"
|
||||||
|
|
||||||
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint.toString()+"°")
|
|
||||||
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint)
|
|
||||||
|
|
||||||
parent.setHold (this, heatingSetpoint, coolingSetpoint)
|
|
||||||
|
|
||||||
log.debug "New Heating Setpoint = ${heatingSetpoint}"
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (mode == "cool") {
|
|
||||||
|
|
||||||
coolingSetpoint++
|
|
||||||
|
|
||||||
if (coolingSetpoint > 99)
|
|
||||||
coolingSetpoint = 99
|
|
||||||
|
|
||||||
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint.toString()+"°")
|
|
||||||
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint)
|
|
||||||
|
|
||||||
parent.setHold (this, heatingSetpoint, coolingSetpoint)
|
|
||||||
|
|
||||||
log.debug "New Cooling Setpoint = ${coolingSetpoint}"
|
|
||||||
|
|
||||||
}
|
|
||||||
generateStatusEvent()
|
|
||||||
|
|
||||||
|
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//called by tile when user hit raise temperature button on UI
|
||||||
void lowerSetpoint() {
|
void lowerSetpoint() {
|
||||||
log.debug "Lower SetPoint"
|
def mode = device.currentValue("thermostatMode")
|
||||||
|
def targetvalue
|
||||||
|
|
||||||
|
if (mode == "off" || mode == "auto") {
|
||||||
|
log.warn "this mode: $mode does not allow lowerSetpoint"
|
||||||
|
} else {
|
||||||
|
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
|
||||||
|
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
|
||||||
|
def thermostatSetpoint = device.currentValue("thermostatSetpoint").toInteger()
|
||||||
|
log.debug "lowerSetpoint() mode = ${mode}, heatingSetpoint: ${heatingSetpoint}, coolingSetpoint:${coolingSetpoint}, thermostatSetpoint:${thermostatSetpoint}"
|
||||||
|
if (device.latestState('thermostatSetpoint')) {
|
||||||
|
targetvalue = device.latestState('thermostatSetpoint').value as Integer
|
||||||
|
} else {
|
||||||
|
targetvalue = 0
|
||||||
|
}
|
||||||
|
targetvalue = targetvalue - 1
|
||||||
|
|
||||||
|
if (mode == "heat" && targetvalue.toInteger() < 45) {
|
||||||
|
targetvalue = 45
|
||||||
|
} else if (mode == "cool" && targetvalue.toInteger() < 65) {
|
||||||
|
targetvalue = 65
|
||||||
|
}
|
||||||
|
|
||||||
|
sendEvent("name":"thermostatSetpoint", "value":targetvalue, displayed: false)
|
||||||
|
log.info "In mode $mode lowerSetpoint() to $targetvalue"
|
||||||
|
|
||||||
|
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//called by raiseSetpoint() and lowerSetpoint()
|
||||||
|
void alterSetpoint(temp) {
|
||||||
|
|
||||||
def mode = device.currentValue("thermostatMode")
|
def mode = device.currentValue("thermostatMode")
|
||||||
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
|
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
|
||||||
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
|
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
|
||||||
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
|
|
||||||
log.debug "Current Mode = ${mode}, Current Heating Setpoint = ${heatingSetpoint}, Current Cooling Setpoint = ${coolingSetpoint}"
|
def targetHeatingSetpoint
|
||||||
|
def targetCoolingSetpoint
|
||||||
|
|
||||||
if (mode == "heat" || mode == "emergencyHeat") {
|
//step1: check thermostatMode, enforce limits before sending request to cloud
|
||||||
|
if (mode == "heat"){
|
||||||
|
if (temp.value > coolingSetpoint){
|
||||||
|
targetHeatingSetpoint = temp.value
|
||||||
|
targetCoolingSetpoint = temp.value
|
||||||
|
} else {
|
||||||
|
targetHeatingSetpoint = temp.value
|
||||||
|
targetCoolingSetpoint = coolingSetpoint
|
||||||
|
}
|
||||||
|
} else if (mode == "cool") {
|
||||||
|
//enforce limits before sending request to cloud
|
||||||
|
if (temp.value < heatingSetpoint){
|
||||||
|
targetHeatingSetpoint = temp.value
|
||||||
|
targetCoolingSetpoint = temp.value
|
||||||
|
} else {
|
||||||
|
targetHeatingSetpoint = heatingSetpoint
|
||||||
|
targetCoolingSetpoint = temp.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
heatingSetpoint--
|
log.debug "alterSetpoint >> in mode ${mode} trying to change heatingSetpoint to ${targetHeatingSetpoint} " +
|
||||||
|
"coolingSetpoint to ${targetCoolingSetpoint} with holdType : ${holdType}"
|
||||||
|
|
||||||
if (heatingSetpoint < 32)
|
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
|
||||||
heatingSetpoint = 32
|
//step2: call parent.setHold to send http request to 3rd party cloud
|
||||||
|
if (parent.setHold(this, targetHeatingSetpoint, targetCoolingSetpoint, deviceId, sendHoldType)) {
|
||||||
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint.toString()+"°")
|
sendEvent("name": "thermostatSetpoint", "value": temp.value.toString(), displayed: false)
|
||||||
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint)
|
sendEvent("name": "heatingSetpoint", "value": targetHeatingSetpoint)
|
||||||
|
sendEvent("name": "coolingSetpoint", "value": targetCoolingSetpoint)
|
||||||
parent.setHold (this, heatingSetpoint, coolingSetpoint)
|
log.debug "alterSetpoint in mode $mode succeed change setpoint to= ${temp.value}"
|
||||||
|
} else {
|
||||||
log.debug "New Heating Setpoint = ${heatingSetpoint}"
|
log.error "Error alterSetpoint()"
|
||||||
|
if (mode == "heat"){
|
||||||
}
|
sendEvent("name": "thermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
|
||||||
else if (mode == "cool") {
|
} else if (mode == "cool") {
|
||||||
|
sendEvent("name": "thermostatSetpoint", "value": coolingSetpoint.toString(), displayed: false)
|
||||||
coolingSetpoint--
|
}
|
||||||
|
}
|
||||||
if (coolingSetpoint < 32)
|
generateStatusEvent()
|
||||||
coolingSetpoint = 32
|
|
||||||
|
|
||||||
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint.toString()+"°")
|
|
||||||
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint)
|
|
||||||
|
|
||||||
parent.setHold (this, heatingSetpoint, coolingSetpoint)
|
|
||||||
|
|
||||||
log.debug "New Cooling Setpoint = ${coolingSetpoint}"
|
|
||||||
|
|
||||||
}
|
|
||||||
generateStatusEvent()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateStatusEvent() {
|
def generateStatusEvent() {
|
||||||
|
|
||||||
def mode = device.currentValue("thermostatMode")
|
def mode = device.currentValue("thermostatMode")
|
||||||
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
|
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
|
||||||
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
|
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
|
||||||
def temperature = device.currentValue("temperature").toInteger()
|
def temperature = device.currentValue("temperature").toInteger()
|
||||||
|
|
||||||
def statusText
|
def statusText
|
||||||
|
|
||||||
log.debug "Generate Status Event for Mode = ${mode}"
|
log.debug "Generate Status Event for Mode = ${mode}"
|
||||||
log.debug "Temperature = ${temperature}"
|
log.debug "Temperature = ${temperature}"
|
||||||
log.debug "Heating set point = ${heatingSetpoint}"
|
log.debug "Heating set point = ${heatingSetpoint}"
|
||||||
log.debug "Cooling set point = ${coolingSetpoint}"
|
log.debug "Cooling set point = ${coolingSetpoint}"
|
||||||
log.debug "HVAC Mode = ${mode}"
|
log.debug "HVAC Mode = ${mode}"
|
||||||
|
|
||||||
if (mode == "heat") {
|
if (mode == "heat") {
|
||||||
|
|
||||||
if (temperature >= heatingSetpoint)
|
if (temperature >= heatingSetpoint)
|
||||||
statusText = "Right Now: Idle"
|
statusText = "Right Now: Idle"
|
||||||
else
|
else
|
||||||
statusText = "Heating to ${heatingSetpoint}° F"
|
statusText = "Heating to ${heatingSetpoint}° F"
|
||||||
|
|
||||||
} else if (mode == "cool") {
|
} else if (mode == "cool") {
|
||||||
|
|
||||||
if (temperature <= coolingSetpoint)
|
if (temperature <= coolingSetpoint)
|
||||||
statusText = "Right Now: Idle"
|
statusText = "Right Now: Idle"
|
||||||
else
|
else
|
||||||
statusText = "Cooling to ${coolingSetpoint}° F"
|
statusText = "Cooling to ${coolingSetpoint}° F"
|
||||||
|
|
||||||
} else if (mode == "auto") {
|
} else if (mode == "auto") {
|
||||||
|
|
||||||
statusText = "Right Now: Auto"
|
statusText = "Right Now: Auto"
|
||||||
|
|
||||||
} else if (mode == "off") {
|
} else if (mode == "off") {
|
||||||
|
|
||||||
statusText = "Right Now: Off"
|
statusText = "Right Now: Off"
|
||||||
|
|
||||||
} else if (mode == "emergencyHeat") {
|
} else if (mode == "emergencyHeat") {
|
||||||
|
|
||||||
statusText = "Emergency Heat"
|
statusText = "Emergency Heat"
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
statusText = "?"
|
statusText = "?"
|
||||||
|
|
||||||
}
|
}
|
||||||
log.debug "Generate Status Event = ${statusText}"
|
log.debug "Generate Status Event = ${statusText}"
|
||||||
sendEvent("name":"thermostatStatus", "value":statusText, "description":statusText, displayed: true, isStateChange: true)
|
sendEvent("name":"thermostatStatus", "value":statusText, "description":statusText, displayed: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//generate custom mobile activity feeds event
|
||||||
|
def generateActivityFeedsEvent(notificationMessage) {
|
||||||
|
sendEvent(name: "notificationMessage", value: "$device.displayName $notificationMessage", descriptionText: "$device.displayName $notificationMessage", displayed: true)
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Logitech Harmony Activity", namespace: "smartthings", author: "Juan Risso") {
|
definition (name: "Harmony Activity", namespace: "smartthings", author: "Juan Risso") {
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,8 +88,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ metadata {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
section {
|
section {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ metadata {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
section {
|
section {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
|
|||||||
@@ -61,8 +61,8 @@
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
section {
|
section {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
section {
|
section {
|
||||||
input("garageSensor", "enum", title: "Do you want to use this sensor on a garage door?", options: ["Yes", "No"], defaultValue: "No", required: false, displayDuringSetup: false)
|
input("garageSensor", "enum", title: "Do you want to use this sensor on a garage door?", options: ["Yes", "No"], defaultValue: "No", required: false, displayDuringSetup: false)
|
||||||
@@ -115,31 +115,30 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
|
Map map = [:]
|
||||||
Map map = [:]
|
if (description?.startsWith('catchall:')) {
|
||||||
if (description?.startsWith('catchall:')) {
|
map = parseCatchAllMessage(description)
|
||||||
map = parseCatchAllMessage(description)
|
}
|
||||||
}
|
|
||||||
else if (description?.startsWith('read attr -')) {
|
|
||||||
map = parseReportAttributeMessage(description)
|
|
||||||
}
|
|
||||||
else if (description?.startsWith('temperature: ')) {
|
else if (description?.startsWith('temperature: ')) {
|
||||||
map = parseCustomMessage(description)
|
map = parseCustomMessage(description)
|
||||||
}
|
}
|
||||||
else if (description?.startsWith('zone status')) {
|
else if (description?.startsWith('zone status')) {
|
||||||
map = parseIasMessage(description)
|
map = parseIasMessage(description)
|
||||||
}
|
}
|
||||||
|
|
||||||
def result = map ? createEvent(map) : null
|
def result = map ? createEvent(map) : null
|
||||||
|
|
||||||
if (description?.startsWith('enroll request')) {
|
if (description?.startsWith('enroll request')) {
|
||||||
List cmds = enrollResponse()
|
List cmds = enrollResponse()
|
||||||
log.debug "enroll response: ${cmds}"
|
log.debug "enroll response: ${cmds}"
|
||||||
result = cmds?.collect { new physicalgraph.device.HubAction(it) }
|
result = cmds?.collect { new physicalgraph.device.HubAction(it) }
|
||||||
}
|
}
|
||||||
return result
|
else if (description?.startsWith('read attr -')) {
|
||||||
}
|
result = parseReportAttributeMessage(description).each { createEvent(it) }
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
private Map parseCatchAllMessage(String description) {
|
private Map parseCatchAllMessage(String description) {
|
||||||
Map resultMap = [:]
|
Map resultMap = [:]
|
||||||
@@ -178,28 +177,40 @@ private boolean shouldProcessMessage(cluster) {
|
|||||||
return !ignoredMessage
|
return !ignoredMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map parseReportAttributeMessage(String description) {
|
private List parseReportAttributeMessage(String description) {
|
||||||
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
||||||
def nameAndValue = param.split(":")
|
def nameAndValue = param.split(":")
|
||||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
||||||
}
|
}
|
||||||
|
|
||||||
Map resultMap = [:]
|
List result = []
|
||||||
if (descMap.cluster == "0402" && descMap.attrId == "0000") {
|
if (descMap.cluster == "0402" && descMap.attrId == "0000") {
|
||||||
def value = getTemperature(descMap.value)
|
def value = getTemperature(descMap.value)
|
||||||
resultMap = getTemperatureResult(value)
|
result << getTemperatureResult(value)
|
||||||
}
|
}
|
||||||
else if (descMap.cluster == "FC02" && descMap.attrId == "0010") {
|
else if (descMap.cluster == "FC02" && descMap.attrId == "0010") {
|
||||||
resultMap = getAccelerationResult(descMap.value)
|
if (descMap.value.size() == 32) {
|
||||||
|
// value will look like 00ae29001403e2290013001629001201
|
||||||
|
// breaking this apart and swapping byte order where appropriate, this breaks down to:
|
||||||
|
// X (0x0012) = 0x0016
|
||||||
|
// Y (0x0013) = 0x03E2
|
||||||
|
// Z (0x0014) = 0x00AE
|
||||||
|
// note that there is a known bug in that the x,y,z attributes are interpreted in the wrong order
|
||||||
|
// this will be fixed in a future update
|
||||||
|
def threeAxisAttributes = descMap.value[0..-9]
|
||||||
|
result << parseAxis(threeAxisAttributes)
|
||||||
|
descMap.value = descMap.value[-2..-1]
|
||||||
|
}
|
||||||
|
result << getAccelerationResult(descMap.value)
|
||||||
}
|
}
|
||||||
else if (descMap.cluster == "FC02" && descMap.attrId == "0012") {
|
else if (descMap.cluster == "FC02" && descMap.attrId == "0012") {
|
||||||
resultMap = parseAxis(descMap.value)
|
result << parseAxis(descMap.value)
|
||||||
}
|
}
|
||||||
else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
|
else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
|
||||||
resultMap = getBatteryResult(Integer.parseInt(descMap.value, 16))
|
result << getBatteryResult(Integer.parseInt(descMap.value, 16))
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultMap
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map parseCustomMessage(String description) {
|
private Map parseCustomMessage(String description) {
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
|
|||||||
@@ -32,8 +32,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
|
|||||||
@@ -33,14 +33,14 @@ metadata {
|
|||||||
state "power", label: '${currentValue} W'
|
state "power", label: '${currentValue} W'
|
||||||
}
|
}
|
||||||
|
|
||||||
tile(name: "powerChart", attribute: "powerContent", type: "HTML", url: '${currentValue}', width: 3, height: 2) { }
|
htmlTile(name: "powerContent", attribute: "powerContent", type: "HTML", whitelist: "www.wattvision.com" , url: '${currentValue}', width: 3, height: 2)
|
||||||
|
|
||||||
standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", label: '', action: "refresh.refresh", icon: "st.secondary.refresh"
|
state "default", label: '', action: "refresh.refresh", icon: "st.secondary.refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
main "power"
|
main "power"
|
||||||
details(["powerChart", "power", "refresh"])
|
details(["powerContent", "power", "refresh"])
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,10 +74,10 @@ public addWattvisionData(json) {
|
|||||||
|
|
||||||
log.trace "Adding data from Wattvision"
|
log.trace "Adding data from Wattvision"
|
||||||
|
|
||||||
def data = json.data
|
def data = parseJson(json.data.toString())
|
||||||
def units = json.units ?: "watts"
|
def units = json.units ?: "watts"
|
||||||
|
|
||||||
if (data) {
|
if (data.size() > 0) {
|
||||||
def latestData = data[-1]
|
def latestData = data[-1]
|
||||||
data.each {
|
data.each {
|
||||||
sendPowerEvent(it.t, it.v, units, (latestData == it))
|
sendPowerEvent(it.t, it.v, units, (latestData == it))
|
||||||
@@ -103,3 +103,7 @@ private sendPowerEvent(time, value, units, isLatest = false) {
|
|||||||
sendEvent(eventData)
|
sendEvent(eventData)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def parseJson(String s) {
|
||||||
|
new groovy.json.JsonSlurper().parseText(s)
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ metadata {
|
|||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04"
|
||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702"
|
||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-CIA19NAE26", deviceJoinName: "Sengled Element touch"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-CIA19NAE26", deviceJoinName: "Sengled Element touch"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B05,0702", outClusters: "000A,0019", manufacturer: "Jasco Products", model: "45852", deviceJoinName: "GE Zigbee Plug-In Dimmer"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45852", deviceJoinName: "GE Zigbee Plug-In Dimmer"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B05,0702", outClusters: "000A,0019", manufacturer: "Jasco Products", model: "45857", deviceJoinName: "GE Zigbee In-Wall Dimmer"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45857", deviceJoinName: "GE Zigbee In-Wall Dimmer"
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
|
|||||||
@@ -17,15 +17,15 @@ metadata {
|
|||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Switch Level"
|
capability "Switch Level"
|
||||||
|
|
||||||
|
|
||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008"
|
||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM", deviceJoinName: "OSRAM LIGHTIFY LED Smart Connected Light"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM", deviceJoinName: "OSRAM LIGHTIFY LED Smart Connected Light"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,FF00", outClusters: "0019", manufacturer: "MRVL", model: "MZ100", deviceJoinName: "Wemo Bulb"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FF00", outClusters: "0019", manufacturer: "MRVL", model: "MZ100", deviceJoinName: "Wemo Bulb"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B05", outClusters: "0019", manufacturer: "OSRAM SYLVANIA", model: "iQBR30", deviceJoinName: "Sylvania Ultra iQ"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05", outClusters: "0019", manufacturer: "OSRAM SYLVANIA", model: "iQBR30", deviceJoinName: "Sylvania Ultra iQ"
|
||||||
|
fingerprint profileId: "0104", inClusters: "0001, 0006, 0008, 000E", outClusters: "0019", manufacturer: "Nanoleaf", model: "IvyBulbs", deviceJoinName: "Nanoleaf Smart Bulbs"
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ metadata {
|
|||||||
|
|
||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04"
|
||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B05,0702", outClusters: "0003, 000A,0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE ZigBee Plug-In Switch"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "0003, 000A, 0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE ZigBee Plug-In Switch"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B05,0702", outClusters: "000A,0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE ZigBee In-Wall Switch"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE ZigBee In-Wall Switch"
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ metadata {
|
|||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
|
|
||||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006"
|
||||||
|
|||||||
@@ -23,18 +23,18 @@ metadata {
|
|||||||
capability "Color Temperature"
|
capability "Color Temperature"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Switch Level"
|
capability "Switch Level"
|
||||||
|
|
||||||
attribute "colorName", "string"
|
attribute "colorName", "string"
|
||||||
command "setGenericName"
|
command "setGenericName"
|
||||||
|
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04", outClusters: "0019"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Flood BR30 Tunable White"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04", outClusters: "0019"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Recessed Kit RT 5/6 Tunable White"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Flood BR30 Tunable White"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 TW", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Recessed Kit RT 5/6 Tunable White"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 TW", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W"
|
||||||
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W"
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI tile definitions
|
// UI tile definitions
|
||||||
|
|||||||
@@ -66,9 +66,20 @@ metadata {
|
|||||||
import physicalgraph.zwave.commands.doorlockv1.*
|
import physicalgraph.zwave.commands.doorlockv1.*
|
||||||
import physicalgraph.zwave.commands.usercodev1.*
|
import physicalgraph.zwave.commands.usercodev1.*
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
try {
|
||||||
|
if (!state.init) {
|
||||||
|
state.init = true
|
||||||
|
response(secureSequence([zwave.doorLockV1.doorLockOperationGet(), zwave.batteryV1.batteryGet()]))
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log.warn "updated() threw $e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
def result = null
|
def result = null
|
||||||
if (description.startsWith("Err")) {
|
if (description.startsWith("Err 106")) {
|
||||||
if (state.sec) {
|
if (state.sec) {
|
||||||
result = createEvent(descriptionText:description, displayed:false)
|
result = createEvent(descriptionText:description, displayed:false)
|
||||||
} else {
|
} else {
|
||||||
@@ -80,6 +91,8 @@ def parse(String description) {
|
|||||||
displayed: true,
|
displayed: true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else if (description == "updated") {
|
||||||
|
return null
|
||||||
} else {
|
} else {
|
||||||
def cmd = zwave.parse(description, [ 0x98: 1, 0x72: 2, 0x85: 2, 0x86: 1 ])
|
def cmd = zwave.parse(description, [ 0x98: 1, 0x72: 2, 0x85: 2, 0x86: 1 ])
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
@@ -286,7 +299,7 @@ def zwaveEvent(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd) {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 167:
|
case 167:
|
||||||
if (!state.lastbatt || (new Date().time) - state.lastbatt > 12*60*60*1000) {
|
if (!state.lastbatt || now() - state.lastbatt > 12*60*60*1000) {
|
||||||
map = [ descriptionText: "$device.displayName: battery low", isStateChange: true ]
|
map = [ descriptionText: "$device.displayName: battery low", isStateChange: true ]
|
||||||
result << response(secure(zwave.batteryV1.batteryGet()))
|
result << response(secure(zwave.batteryV1.batteryGet()))
|
||||||
} else {
|
} else {
|
||||||
@@ -431,7 +444,7 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
|||||||
} else {
|
} else {
|
||||||
map.value = cmd.batteryLevel
|
map.value = cmd.batteryLevel
|
||||||
}
|
}
|
||||||
state.lastbatt = new Date().time
|
state.lastbatt = now()
|
||||||
createEvent(map)
|
createEvent(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,15 +512,14 @@ def refresh() {
|
|||||||
cmds << "delay 4200"
|
cmds << "delay 4200"
|
||||||
cmds << zwave.associationV1.associationGet(groupingIdentifier:2).format() // old Schlage locks use group 2 and don't secure the Association CC
|
cmds << zwave.associationV1.associationGet(groupingIdentifier:2).format() // old Schlage locks use group 2 and don't secure the Association CC
|
||||||
cmds << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
|
cmds << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
|
||||||
state.associationQuery = new Date().time
|
state.associationQuery = now()
|
||||||
} else if (new Date().time - state.associationQuery.toLong() > 9000) {
|
} else if (secondsPast(state.associationQuery, 9)) {
|
||||||
log.debug "setting association"
|
|
||||||
cmds << "delay 6000"
|
cmds << "delay 6000"
|
||||||
cmds << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId).format()
|
cmds << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId).format()
|
||||||
cmds << secure(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId))
|
cmds << secure(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId))
|
||||||
cmds << zwave.associationV1.associationGet(groupingIdentifier:2).format()
|
cmds << zwave.associationV1.associationGet(groupingIdentifier:2).format()
|
||||||
cmds << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
|
cmds << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
|
||||||
state.associationQuery = new Date().time
|
state.associationQuery = now()
|
||||||
}
|
}
|
||||||
log.debug "refresh sending ${cmds.inspect()}"
|
log.debug "refresh sending ${cmds.inspect()}"
|
||||||
cmds
|
cmds
|
||||||
@@ -515,55 +527,22 @@ def refresh() {
|
|||||||
|
|
||||||
def poll() {
|
def poll() {
|
||||||
def cmds = []
|
def cmds = []
|
||||||
if (state.assoc != zwaveHubNodeId && secondsPast(state.associationQuery, 19 * 60)) {
|
// Only check lock state if it changed recently or we haven't had an update in an hour
|
||||||
log.debug "setting association"
|
def latest = device.currentState("lock")?.date?.time
|
||||||
cmds << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId).format()
|
if (!latest || !secondsPast(latest, 6 * 60) || secondsPast(state.lastPoll, 55 * 60)) {
|
||||||
cmds << secure(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId))
|
cmds << secure(zwave.doorLockV1.doorLockOperationGet())
|
||||||
cmds << zwave.associationV1.associationGet(groupingIdentifier:2).format()
|
state.lastPoll = now()
|
||||||
cmds << "delay 6000"
|
} else if (!state.lastbatt || now() - state.lastbatt > 53*60*60*1000) {
|
||||||
cmds << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
|
cmds << secure(zwave.batteryV1.batteryGet())
|
||||||
cmds << "delay 6000"
|
state.lastbatt = now() //inside-214
|
||||||
state.associationQuery = new Date().time
|
|
||||||
} else {
|
|
||||||
// Only check lock state if it changed recently or we haven't had an update in an hour
|
|
||||||
def latest = device.currentState("lock")?.date?.time
|
|
||||||
if (!latest || !secondsPast(latest, 6 * 60) || secondsPast(state.lastPoll, 55 * 60)) {
|
|
||||||
cmds << secure(zwave.doorLockV1.doorLockOperationGet())
|
|
||||||
state.lastPoll = (new Date()).time
|
|
||||||
} else if (!state.MSR) {
|
|
||||||
cmds << zwave.manufacturerSpecificV1.manufacturerSpecificGet().format()
|
|
||||||
} else if (!state.fw) {
|
|
||||||
cmds << zwave.versionV1.versionGet().format()
|
|
||||||
} else if (!state.codes) {
|
|
||||||
state.pollCode = 1
|
|
||||||
cmds << secure(zwave.userCodeV1.usersNumberGet())
|
|
||||||
} else if (state.pollCode && state.pollCode <= state.codes) {
|
|
||||||
cmds << requestCode(state.pollCode)
|
|
||||||
} else if (!state.lastbatt || (new Date().time) - state.lastbatt > 53*60*60*1000) {
|
|
||||||
cmds << secure(zwave.batteryV1.batteryGet())
|
|
||||||
} else if (!state.enc) {
|
|
||||||
encryptCodes()
|
|
||||||
state.enc = 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
log.debug "poll is sending ${cmds.inspect()}"
|
if (cmds) {
|
||||||
device.activity()
|
log.debug "poll is sending ${cmds.inspect()}"
|
||||||
cmds ?: null
|
cmds
|
||||||
}
|
} else {
|
||||||
|
// workaround to keep polling from stopping due to lack of activity
|
||||||
private def encryptCodes() {
|
sendEvent(descriptionText: "skipping poll", isStateChange: true, displayed: false)
|
||||||
def keys = new ArrayList(state.keySet().findAll { it.startsWith("code") })
|
null
|
||||||
keys.each { key ->
|
|
||||||
def match = (key =~ /^code(\d+)$/)
|
|
||||||
if (match) try {
|
|
||||||
def keynum = match[0][1].toInteger()
|
|
||||||
if (keynum > 30 && !state[key]) {
|
|
||||||
state.remove(key)
|
|
||||||
} else if (state[key] && !state[key].startsWith("~")) {
|
|
||||||
log.debug "encrypting $key: ${state[key].inspect()}"
|
|
||||||
state[key] = encrypt(state[key])
|
|
||||||
}
|
|
||||||
} catch (java.lang.NumberFormatException e) { }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,7 +651,7 @@ private Boolean secondsPast(timestamp, seconds) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (new Date().time - timestamp) > (seconds * 1000)
|
return (now() - timestamp) > (seconds * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
private allCodesDeleted() {
|
private allCodesDeleted() {
|
||||||
|
|||||||
@@ -115,6 +115,10 @@ def strobe() {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def both() {
|
||||||
|
on()
|
||||||
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
log.debug "sending battery refresh command"
|
log.debug "sending battery refresh command"
|
||||||
zwave.batteryV1.batteryGet().format()
|
zwave.batteryV1.batteryGet().format()
|
||||||
|
|||||||
@@ -246,6 +246,9 @@ def toggle(devices) {
|
|||||||
else if (devices*.currentValue('lock').contains('locked')) {
|
else if (devices*.currentValue('lock').contains('locked')) {
|
||||||
devices.unlock()
|
devices.unlock()
|
||||||
}
|
}
|
||||||
|
else if (devices*.currentValue('lock').contains('unlocked')) {
|
||||||
|
devices.lock()
|
||||||
|
}
|
||||||
else if (devices*.currentValue('alarm').contains('off')) {
|
else if (devices*.currentValue('alarm').contains('off')) {
|
||||||
devices.siren()
|
devices.siren()
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -592,7 +592,7 @@ def updated() {
|
|||||||
// log.debug "External Id=${app.id}:${member.id}"
|
// log.debug "External Id=${app.id}:${member.id}"
|
||||||
|
|
||||||
// create the device
|
// create the device
|
||||||
def childDevice = addChildDevice("smartthings", "life360-user", "${app.id}.${member.id}",null,[name:member.firstName, completedSetup: true])
|
def childDevice = addChildDevice("smartthings", "Life360 User", "${app.id}.${member.id}",null,[name:member.firstName, completedSetup: true])
|
||||||
// childDevice.setMemberId(member.id)
|
// childDevice.setMemberId(member.id)
|
||||||
|
|
||||||
if (childDevice)
|
if (childDevice)
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ preferences {
|
|||||||
section("Via a push notification and/or an SMS message"){
|
section("Via a push notification and/or an SMS message"){
|
||||||
input("recipients", "contact", title: "Send notifications to") {
|
input("recipients", "contact", title: "Send notifications to") {
|
||||||
input "phone", "phone", title: "Phone Number (for SMS, optional)", required: false
|
input "phone", "phone", title: "Phone Number (for SMS, optional)", required: false
|
||||||
|
paragraph "If outside the US please make sure to enter the proper country code"
|
||||||
input "pushAndPhone", "enum", title: "Both Push and SMS?", required: false, options: ["Yes", "No"]
|
input "pushAndPhone", "enum", title: "Both Push and SMS?", required: false, options: ["Yes", "No"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ def firstPage()
|
|||||||
def motionsDiscovered = motionsDiscovered()
|
def motionsDiscovered = motionsDiscovered()
|
||||||
def lightSwitchesDiscovered = lightSwitchesDiscovered()
|
def lightSwitchesDiscovered = lightSwitchesDiscovered()
|
||||||
|
|
||||||
return dynamicPage(name:"firstPage", title:"Discovery Started!", nextPage:"", refreshInterval: refreshInterval, install:true, uninstall: selectedSwitches != null || selectedMotions != null || selectedLightSwitches != null) {
|
return dynamicPage(name:"firstPage", title:"Discovery Started!", nextPage:"", refreshInterval: refreshInterval, install:true, uninstall: true) {
|
||||||
section("Select a device...") {
|
section("Select a device...") {
|
||||||
input "selectedSwitches", "enum", required:false, title:"Select Wemo Switches \n(${switchesDiscovered.size() ?: 0} found)", multiple:true, options:switchesDiscovered
|
input "selectedSwitches", "enum", required:false, title:"Select Wemo Switches \n(${switchesDiscovered.size() ?: 0} found)", multiple:true, options:switchesDiscovered
|
||||||
input "selectedMotions", "enum", required:false, title:"Select Wemo Motions \n(${motionsDiscovered.size() ?: 0} found)", multiple:true, options:motionsDiscovered
|
input "selectedMotions", "enum", required:false, title:"Select Wemo Motions \n(${motionsDiscovered.size() ?: 0} found)", multiple:true, options:motionsDiscovered
|
||||||
|
|||||||
Reference in New Issue
Block a user