mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-25 05:04:09 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e529624d36 | ||
|
|
6ba37caa03 | ||
|
|
8d0fa7f561 | ||
|
|
6ede225715 |
@@ -27,7 +27,7 @@ metadata {
|
|||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-S", deviceJoinName: "Water Leak Sensor"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-S", deviceJoinName: "Water Leak Sensor"
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315"
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-Seu", deviceJoinName: "Water Leak Sensor"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-Seu", deviceJoinName: "Water Leak Sensor"
|
||||||
|
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "moisturev4", deviceJoinName: "Water Leak Sensor"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ metadata {
|
|||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3305"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3305"
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325"
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326"
|
||||||
|
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv4", deviceJoinName: "Motion Sensor"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -352,4 +353,4 @@ private byte[] reverseArray(byte[] array) {
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return array
|
return array
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320"
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321"
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321-S", deviceJoinName: "Multipurpose Sensor"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321-S", deviceJoinName: "Multipurpose Sensor"
|
||||||
|
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500,FC02", outClusters: "0019", manufacturer: "SmartThings", model: "multiv4", deviceJoinName: "Multipurpose Sensor"
|
||||||
|
|
||||||
attribute "status", "string"
|
attribute "status", "string"
|
||||||
}
|
}
|
||||||
@@ -374,26 +375,26 @@ def getTemperature(value) {
|
|||||||
|
|
||||||
/* sensitivity - default value (8) */
|
/* sensitivity - default value (8) */
|
||||||
|
|
||||||
"zcl mfg-code 0x104E", "delay 200",
|
"zcl mfg-code ${manufacturerCode}", "delay 200",
|
||||||
"zcl global write 0xFC02 0 0x20 {02}", "delay 200",
|
"zcl global write 0xFC02 0 0x20 {02}", "delay 200",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 400",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 400",
|
||||||
|
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200",
|
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E", "delay 200",
|
"zcl mfg-code ${manufacturerCode}", "delay 200",
|
||||||
"zcl global read 0xFC02 0x0010",
|
"zcl global read 0xFC02 0x0010",
|
||||||
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E", "delay 200",
|
"zcl mfg-code ${manufacturerCode}", "delay 200",
|
||||||
"zcl global read 0xFC02 0x0012",
|
"zcl global read 0xFC02 0x0012",
|
||||||
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E", "delay 200",
|
"zcl mfg-code ${manufacturerCode}", "delay 200",
|
||||||
"zcl global read 0xFC02 0x0013",
|
"zcl global read 0xFC02 0x0013",
|
||||||
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E", "delay 200",
|
"zcl mfg-code ${manufacturerCode}", "delay 200",
|
||||||
"zcl global read 0xFC02 0x0014",
|
"zcl global read 0xFC02 0x0014",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 400"
|
"send 0x${device.deviceNetworkId} 1 1", "delay 400"
|
||||||
]
|
]
|
||||||
@@ -420,19 +421,19 @@ def getTemperature(value) {
|
|||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0xFC02 {${device.zigbeeId}} {}", "delay 200",
|
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0xFC02 {${device.zigbeeId}} {}", "delay 200",
|
||||||
"zcl mfg-code 0x104E",
|
"zcl mfg-code ${manufacturerCode}",
|
||||||
"zcl global send-me-a-report 0xFC02 0x0010 0x18 10 3600 {01}",
|
"zcl global send-me-a-report 0xFC02 0x0010 0x18 10 3600 {01}",
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E",
|
"zcl mfg-code ${manufacturerCode}",
|
||||||
"zcl global send-me-a-report 0xFC02 0x0012 0x29 1 3600 {01}",
|
"zcl global send-me-a-report 0xFC02 0x0012 0x29 1 3600 {01}",
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E",
|
"zcl mfg-code ${manufacturerCode}",
|
||||||
"zcl global send-me-a-report 0xFC02 0x0013 0x29 1 3600 {01}",
|
"zcl global send-me-a-report 0xFC02 0x0013 0x29 1 3600 {01}",
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E",
|
"zcl mfg-code ${manufacturerCode}",
|
||||||
"zcl global send-me-a-report 0xFC02 0x0014 0x29 1 3600 {01}",
|
"zcl global send-me-a-report 0xFC02 0x0014 0x29 1 3600 {01}",
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500"
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500"
|
||||||
|
|
||||||
@@ -530,6 +531,14 @@ private Map getXyzResult(results, description) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getManufacturerCode() {
|
||||||
|
if (device.getDataValue("manufacturer") == "SmartThings") {
|
||||||
|
return "0x110A"
|
||||||
|
} else {
|
||||||
|
return "0x104E"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private hexToInt(value) {
|
private hexToInt(value) {
|
||||||
new BigInteger(value, 16)
|
new BigInteger(value, 16)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,526 +0,0 @@
|
|||||||
/**
|
|
||||||
* Total Comfort API
|
|
||||||
*
|
|
||||||
* Based on Code by Eric Thomas
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
preferences {
|
|
||||||
input("username", "text", title: "Username", description: "Your Total Comfort User Name")
|
|
||||||
input("password", "password", title: "Password", description: "Your Total Comfort password")
|
|
||||||
input("honeywelldevice", "text", title: "Device ID", description: "Your Device ID")
|
|
||||||
|
|
||||||
}
|
|
||||||
metadata {
|
|
||||||
definition (name: "Total Comfort API", namespace: "Total Comfort API", author: "Eric Thomas") {
|
|
||||||
capability "Polling"
|
|
||||||
capability "Thermostat"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Temperature Measurement"
|
|
||||||
capability "Sensor"
|
|
||||||
capability "Relative Humidity Measurement"
|
|
||||||
command "heatLevelUp"
|
|
||||||
command "heatLevelDown"
|
|
||||||
command "coolLevelUp"
|
|
||||||
command "coolLevelDown"
|
|
||||||
}
|
|
||||||
|
|
||||||
simulator {
|
|
||||||
// TODO: define status and reply messages here
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles {
|
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2, canChangeIcon: true) {
|
|
||||||
state("temperature", label: '${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("thermostatMode", "device.thermostatMode", inactiveLabel: false, canChangeIcon: true) {
|
|
||||||
state "off", label:'${name}', action:"thermostat.cool", icon: "st.Outdoor.outdoor19"
|
|
||||||
state "cool", label:'${name}', action:"thermostat.heat", icon: "st.Weather.weather7", backgroundColor: '#003CEC'
|
|
||||||
state "heat", label:'${name}', action:"thermostat.auto", icon: "st.Weather.weather14", backgroundColor: '#E14902'
|
|
||||||
state "auto", label:'${name}', action:"thermostat.off", icon: "st.Weather.weather3", backgroundColor: '#44b621'
|
|
||||||
}
|
|
||||||
standardTile("thermostatFanMode", "device.thermostatFanMode", inactiveLabel: false, canChangeIcon: true) {
|
|
||||||
state "auto", label:'${name}', action:"thermostat.fanOn", icon: "st.Appliances.appliances11"
|
|
||||||
state "on", label:'${name}', action:"thermostat.fanAuto", icon: "st.Appliances.appliances11", backgroundColor: '#44b621'
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 3, width: 1, inactiveLabel: false) {
|
|
||||||
state "setCoolingSetpoint", label:'Set temperarure to', action:"thermostat.setCoolingSetpoint",
|
|
||||||
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("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false)
|
|
||||||
{
|
|
||||||
state "default", label:'Cool @${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 @${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"]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//tile added for operating state - Create the tiles for each possible state, look at other examples if you wish to change the icons here.
|
|
||||||
|
|
||||||
standardTile("thermostatOperatingState", "device.thermostatOperatingState", inactiveLabel: false) {
|
|
||||||
state "heating", label:'${name}'
|
|
||||||
state "cooling", label:'${name}'
|
|
||||||
state "idle", label:'${name}'
|
|
||||||
}
|
|
||||||
|
|
||||||
standardTile("refresh", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "default", action:"polling.poll", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
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"
|
|
||||||
}
|
|
||||||
|
|
||||||
valueTile("relativeHumidity", "device.relativeHumidity", inactiveLabel: false){
|
|
||||||
state "default", label:'${currentValue}', unit:"%"
|
|
||||||
|
|
||||||
}
|
|
||||||
main "temperature"
|
|
||||||
details(["temperature", "thermostatMode", "thermostatFanMode", "heatLevelUp", "heatingSetpoint" , "heatLevelDown", "coolLevelUp","coolingSetpoint", "coolLevelDown" ,"thermostatOperatingState", "refresh","relativeHumidity"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// parse events into attributes
|
|
||||||
def parse(String description) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle commands
|
|
||||||
def setHeatingSetpoint(temp) {
|
|
||||||
data.SystemSwitch = 'null'
|
|
||||||
data.HeatSetpoint = temp
|
|
||||||
data.CoolSetpoint = 'null'
|
|
||||||
data.HeatNextPeriod = 'null'
|
|
||||||
data.CoolNextPeriod = 'null'
|
|
||||||
data.StatusHeat='1'
|
|
||||||
data.StatusCool='1'
|
|
||||||
data.FanMode = 'null'
|
|
||||||
setStatus()
|
|
||||||
|
|
||||||
if(data.SetStatus==1)
|
|
||||||
{
|
|
||||||
sendEvent(name: 'heatingSetpoint', value: temp as Integer)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def setCoolingSetpoint(temp) {
|
|
||||||
data.SystemSwitch = 'null'
|
|
||||||
data.HeatSetpoint = 'null'
|
|
||||||
data.CoolSetpoint = temp
|
|
||||||
data.HeatNextPeriod = 'null'
|
|
||||||
data.CoolNextPeriod = 'null'
|
|
||||||
data.StatusHeat='1'
|
|
||||||
data.StatusCool='1'
|
|
||||||
data.FanMode = 'null'
|
|
||||||
setStatus()
|
|
||||||
|
|
||||||
if(data.SetStatus==1)
|
|
||||||
{
|
|
||||||
sendEvent(name: 'coolingSetpoint', value: temp as Integer)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def setTargetTemp(temp) {
|
|
||||||
data.SystemSwitch = 'null'
|
|
||||||
data.HeatSetpoint = temp
|
|
||||||
data.CoolSetpoint = temp
|
|
||||||
data.HeatNextPeriod = 'null'
|
|
||||||
data.CoolNextPeriod = 'null'
|
|
||||||
data.StatusHeat='1'
|
|
||||||
data.StatusCool='1'
|
|
||||||
data.FanMode = 'null'
|
|
||||||
setStatus()
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
setThermostatMode(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
def auto() {
|
|
||||||
setThermostatMode(4)
|
|
||||||
}
|
|
||||||
|
|
||||||
def heat() {
|
|
||||||
setThermostatMode(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
def emergencyHeat() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def cool() {
|
|
||||||
setThermostatMode(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
def setThermostatMode(mode) {
|
|
||||||
data.SystemSwitch = mode
|
|
||||||
data.HeatSetpoint = 'null'
|
|
||||||
data.CoolSetpoint = 'null'
|
|
||||||
data.HeatNextPeriod = 'null'
|
|
||||||
data.CoolNextPeriod = 'null'
|
|
||||||
data.StatusHeat=1
|
|
||||||
data.StatusCool=1
|
|
||||||
data.FanMode = 'null'
|
|
||||||
|
|
||||||
setStatus()
|
|
||||||
|
|
||||||
def switchPos
|
|
||||||
|
|
||||||
if(mode==1)
|
|
||||||
switchPos = 'heat'
|
|
||||||
if(mode==2)
|
|
||||||
switchPos = 'off'
|
|
||||||
if(mode==3)
|
|
||||||
switchPos = 'cool'
|
|
||||||
if(mode==4)
|
|
||||||
switchPos = 'auto'
|
|
||||||
if(data.SetStatus==1)
|
|
||||||
{
|
|
||||||
sendEvent(name: 'thermostatMode', value: switchPos)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def fanOn() {
|
|
||||||
setThermostatFanMode(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
def fanAuto() {
|
|
||||||
setThermostatFanMode(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
def fanCirculate() {
|
|
||||||
setThermostatFanMode(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
def setThermostatFanMode(mode) {
|
|
||||||
|
|
||||||
data.SystemSwitch = 'null'
|
|
||||||
data.HeatSetpoint = 'null'
|
|
||||||
data.CoolSetpoint = 'null'
|
|
||||||
data.HeatNextPeriod = 'null'
|
|
||||||
data.CoolNextPeriod = 'null'
|
|
||||||
data.StatusHeat='null'
|
|
||||||
data.StatusCool='null'
|
|
||||||
data.FanMode = mode
|
|
||||||
|
|
||||||
setStatus()
|
|
||||||
|
|
||||||
def fanMode
|
|
||||||
|
|
||||||
if(mode==0)
|
|
||||||
fanMode = 'auto'
|
|
||||||
if(mode==1)
|
|
||||||
fanMode = 'on'
|
|
||||||
|
|
||||||
if(data.SetStatus==1)
|
|
||||||
{
|
|
||||||
sendEvent(name: 'thermostatFanMode', value: fanMode)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def poll() {
|
|
||||||
refresh()
|
|
||||||
}
|
|
||||||
def setStatus() {
|
|
||||||
|
|
||||||
data.SetStatus = 0
|
|
||||||
|
|
||||||
login()
|
|
||||||
log.debug "Executing 'setStatus'"
|
|
||||||
def today= new Date()
|
|
||||||
log.debug "https://mytotalconnectcomfort.com/portal/Device/SubmitControlScreenChanges"
|
|
||||||
|
|
||||||
|
|
||||||
def params = [
|
|
||||||
uri: "https://mytotalconnectcomfort.com/portal/Device/SubmitControlScreenChanges",
|
|
||||||
headers: [
|
|
||||||
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
|
||||||
'DNT': '1',
|
|
||||||
'Accept-Encoding': 'gzip,deflate,sdch',
|
|
||||||
'Cache-Control': 'max-age=0',
|
|
||||||
'Accept-Language': 'en-US,en,q=0.8',
|
|
||||||
'Connection': 'keep-alive',
|
|
||||||
'Host': 'rs.alarmnet.com',
|
|
||||||
'Referer': "https://mytotalconnectcomfort.com/portal/Device/Control/${settings.honeywelldevice}",
|
|
||||||
'X-Requested-With': 'XMLHttpRequest',
|
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36',
|
|
||||||
'Cookie': data.cookiess ],
|
|
||||||
body: [ DeviceID: "${settings.honeywelldevice}", SystemSwitch : data.SystemSwitch ,HeatSetpoint : data.HeatSetpoint, CoolSetpoint: data.CoolSetpoint, HeatNextPeriod: data.HeatNextPeriod,CoolNextPeriod:data.CoolNextPeriod,StatusHeat:data.StatusHeat,StatusCool:data.StatusCool,FanMode:data.FanMode]
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
httpPost(params) { response ->
|
|
||||||
log.debug "Request was successful, $response.status"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug "SetStatus is 1 now"
|
|
||||||
data.SetStatus = 1
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def getStatus() {
|
|
||||||
log.debug "Executing 'getStatus'"
|
|
||||||
def today= new Date()
|
|
||||||
log.debug "https://mytotalconnectcomfort.com/portal/Device/CheckDataSession/${settings.honeywelldevice}?_=$today.time"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def params = [
|
|
||||||
uri: "https://mytotalconnectcomfort.com/portal/Device/CheckDataSession/${settings.honeywelldevice}",
|
|
||||||
headers: [
|
|
||||||
'Accept': '*/*',
|
|
||||||
'DNT': '1',
|
|
||||||
'Accept-Encoding': 'plain',
|
|
||||||
'Cache-Control': 'max-age=0',
|
|
||||||
'Accept-Language': 'en-US,en,q=0.8',
|
|
||||||
'Connection': 'keep-alive',
|
|
||||||
'Host': 'rs.alarmnet.com',
|
|
||||||
'Referer': 'https://mytotalconnectcomfort.com/portal',
|
|
||||||
'X-Requested-With': 'XMLHttpRequest',
|
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36',
|
|
||||||
'Cookie': data.cookiess ],
|
|
||||||
]
|
|
||||||
|
|
||||||
httpGet(params) { response ->
|
|
||||||
log.debug "Request was successful, $response.status"
|
|
||||||
|
|
||||||
|
|
||||||
def curTemp = response.data.latestData.uiData.DispTemperature
|
|
||||||
def fanMode = response.data.latestData.fanData.fanMode
|
|
||||||
def switchPos = response.data.latestData.uiData.SystemSwitchPosition
|
|
||||||
def coolSetPoint = response.data.latestData.uiData.CoolSetpoint
|
|
||||||
def heatSetPoint = response.data.latestData.uiData.HeatSetpoint
|
|
||||||
def statusCool = response.data.latestData.uiData.StatusCool
|
|
||||||
def statusHeat = response.data.latestData.uiData.StatusHeat
|
|
||||||
def curHumidity = response.data.latestData.uiData.IndoorHumidity
|
|
||||||
|
|
||||||
|
|
||||||
log.trace("IndoorHumidity: ${response.data.latestData.uiData.IndoorHumidity}")
|
|
||||||
log.trace("IndoorHumiditySensorAvailable: ${response.data.latestData.uiData.IndoorHumiditySensorAvailable}")
|
|
||||||
log.trace("IndoorHumiditySensorNotFault: ${response.data.latestData.uiData.IndoorHumiditySensorNotFault}")
|
|
||||||
log.trace("IndoorHumidStatus: ${response.data.latestData.uiData.IndoorHumidStatus}")
|
|
||||||
|
|
||||||
//Operating State Section
|
|
||||||
//Set the operating state to off
|
|
||||||
|
|
||||||
def operatingState = "off"
|
|
||||||
|
|
||||||
//Check the status of heat and cool
|
|
||||||
if(statusCool == 1 && switchPos == 3) {
|
|
||||||
operatingState = "cooling"
|
|
||||||
} else if (statusHeat == 1 && switchPos == 1) {
|
|
||||||
operatingState = "heating"
|
|
||||||
|
|
||||||
} else {
|
|
||||||
operatingState = "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
//End Operating State
|
|
||||||
|
|
||||||
log.debug curTemp
|
|
||||||
log.debug fanMode
|
|
||||||
log.debug switchPos
|
|
||||||
|
|
||||||
//fan mode 0=auto, 2=circ, 1=on
|
|
||||||
|
|
||||||
if(fanMode==0)
|
|
||||||
fanMode = 'auto'
|
|
||||||
if(fanMode==1)
|
|
||||||
fanMode = 'on'
|
|
||||||
|
|
||||||
if(switchPos==1)
|
|
||||||
switchPos = 'heat'
|
|
||||||
if(switchPos==2)
|
|
||||||
switchPos = 'off'
|
|
||||||
if(switchPos==3)
|
|
||||||
switchPos = 'cool'
|
|
||||||
if(switchPos==4)
|
|
||||||
switchPos = 'auto'
|
|
||||||
|
|
||||||
//Send events
|
|
||||||
sendEvent(name: 'thermostatOperatingState', value: operatingState)
|
|
||||||
sendEvent(name: 'thermostatFanMode', value: fanMode)
|
|
||||||
sendEvent(name: 'thermostatMode', value: switchPos)
|
|
||||||
sendEvent(name: 'coolingSetpoint', value: coolSetPoint as Integer)
|
|
||||||
sendEvent(name: 'heatingSetpoint', value: heatSetPoint as Integer)
|
|
||||||
sendEvent(name: 'temperature', value: curTemp as Integer, state: switchPos)
|
|
||||||
sendEvent(name: 'relativeHumidity', value: curHumidity as Integer)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def api(method, args = [], success = {}) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to be logged in before this is called. So don't call this. Call api.
|
|
||||||
def doRequest(uri, args, type, success) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def refresh() {
|
|
||||||
log.debug "Executing 'refresh'"
|
|
||||||
login()
|
|
||||||
getStatus()
|
|
||||||
}
|
|
||||||
|
|
||||||
def login() {
|
|
||||||
log.debug "Executing 'login'"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def params = [
|
|
||||||
uri: 'https://mytotalconnectcomfort.com/portal',
|
|
||||||
headers: [
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
||||||
'Accept-Encoding': 'sdch',
|
|
||||||
'Host': 'mytotalconnectcomfort.com',
|
|
||||||
'DNT': '1',
|
|
||||||
'Origin': 'mytotalconnectcomfort.com/portal/',
|
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36'
|
|
||||||
],
|
|
||||||
body: [timeOffset: '240', UserName: "${settings.username}", Password: "${settings.password}", RememberMe: 'false']
|
|
||||||
]
|
|
||||||
|
|
||||||
data.cookiess = ''
|
|
||||||
|
|
||||||
httpPost(params) { response ->
|
|
||||||
log.debug "Request was successful, $response.status"
|
|
||||||
log.debug response.headers
|
|
||||||
response.getHeaders('Set-Cookie').each {
|
|
||||||
String cookie = it.value.split(';|,')[0]
|
|
||||||
log.debug "Adding cookie to collection: $cookie"
|
|
||||||
if(cookie != ".ASPXAUTH_TH_A=") {
|
|
||||||
data.cookiess = data.cookiess+cookie+';'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.debug "cookies: $data.cookiess"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def isLoggedIn() {
|
|
||||||
if(!data.auth) {
|
|
||||||
log.debug "No data.auth"
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
def now = new Date().getTime();
|
|
||||||
return data.auth.expires_in > now
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,341 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Bose® SoundTouch® Control
|
||||||
|
*
|
||||||
|
* Author: SmartThings & Joe Geiger
|
||||||
|
*
|
||||||
|
* Date: 2015-30-09
|
||||||
|
*/
|
||||||
|
definition(
|
||||||
|
name: "Bose® SoundTouch® Control",
|
||||||
|
namespace: "smartthings",
|
||||||
|
author: "SmartThings & Joe Geiger",
|
||||||
|
description: "Control your Bose® SoundTouch® when certain actions take place in your home.",
|
||||||
|
category: "SmartThings Labs",
|
||||||
|
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||||
|
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png",
|
||||||
|
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
page(name: "mainPage", title: "Control your Bose® SoundTouch® when something happens", install: true, uninstall: true)
|
||||||
|
page(name: "timeIntervalInput", title: "Only during a certain time") {
|
||||||
|
section {
|
||||||
|
input "starting", "time", title: "Starting", required: false
|
||||||
|
input "ending", "time", title: "Ending", required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def mainPage() {
|
||||||
|
dynamicPage(name: "mainPage") {
|
||||||
|
def anythingSet = anythingSet()
|
||||||
|
if (anythingSet) {
|
||||||
|
section("When..."){
|
||||||
|
ifSet "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
|
||||||
|
ifSet "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
|
||||||
|
ifSet "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
|
||||||
|
ifSet "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
|
||||||
|
ifSet "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
|
||||||
|
ifSet "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
|
||||||
|
ifSet "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
|
||||||
|
ifSet "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
|
||||||
|
ifSet "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
|
||||||
|
ifSet "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
|
||||||
|
ifSet "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
|
||||||
|
ifSet "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
|
||||||
|
ifSet "timeOfDay", "time", title: "At a Scheduled Time", required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
section(anythingSet ? "Select additional triggers" : "When...", hideable: anythingSet, hidden: true){
|
||||||
|
ifUnset "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
|
||||||
|
ifUnset "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
|
||||||
|
ifUnset "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
|
||||||
|
ifUnset "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
|
||||||
|
ifUnset "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
|
||||||
|
ifUnset "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
|
||||||
|
ifUnset "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
|
||||||
|
ifUnset "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
|
||||||
|
ifUnset "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
|
||||||
|
ifUnset "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
|
||||||
|
ifUnset "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
|
||||||
|
ifUnset "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
|
||||||
|
ifUnset "timeOfDay", "time", title: "At a Scheduled Time", required: false
|
||||||
|
}
|
||||||
|
section("Perform this action"){
|
||||||
|
input "actionType", "enum", title: "Action?", required: true, defaultValue: "play", options: [
|
||||||
|
"Turn On & Play",
|
||||||
|
"Turn Off",
|
||||||
|
"Toggle Play/Pause",
|
||||||
|
"Skip to Next Track",
|
||||||
|
"Skip to Beginning/Previous Track",
|
||||||
|
"Play Preset 1",
|
||||||
|
"Play Preset 2",
|
||||||
|
"Play Preset 3",
|
||||||
|
"Play Preset 4",
|
||||||
|
"Play Preset 5",
|
||||||
|
"Play Preset 6"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
section {
|
||||||
|
input "bose", "capability.musicPlayer", title: "Bose® SoundTouch® music player", required: true
|
||||||
|
}
|
||||||
|
section("More options", hideable: true, hidden: true) {
|
||||||
|
input "volume", "number", title: "Set the volume volume", description: "0-100%", required: false
|
||||||
|
input "frequency", "decimal", title: "Minimum time between actions (defaults to every event)", description: "Minutes", required: false
|
||||||
|
href "timeIntervalInput", title: "Only during a certain time", description: timeLabel ?: "Tap to set", state: timeLabel ? "complete" : "incomplete"
|
||||||
|
input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
|
||||||
|
options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
||||||
|
if (settings.modes) {
|
||||||
|
input "modes", "mode", title: "Only when mode is", multiple: true, required: false
|
||||||
|
}
|
||||||
|
input "oncePerDay", "bool", title: "Only once per day", required: false, defaultValue: false
|
||||||
|
}
|
||||||
|
section([mobileOnly:true]) {
|
||||||
|
label title: "Assign a name", required: false
|
||||||
|
mode title: "Set for specific mode(s)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private anythingSet() {
|
||||||
|
for (name in ["motion","contact","contactClosed","acceleration","mySwitch","mySwitchOff","arrivalPresence","departurePresence","smoke","water","button1","triggerModes","timeOfDay"]) {
|
||||||
|
if (settings[name]) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private ifUnset(Map options, String name, String capability) {
|
||||||
|
if (!settings[name]) {
|
||||||
|
input(options, name, capability)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ifSet(Map options, String name, String capability) {
|
||||||
|
if (settings[name]) {
|
||||||
|
input(options, name, capability)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
log.debug "Installed with settings: ${settings}"
|
||||||
|
subscribeToEvents()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
log.debug "Updated with settings: ${settings}"
|
||||||
|
unsubscribe()
|
||||||
|
unschedule()
|
||||||
|
subscribeToEvents()
|
||||||
|
}
|
||||||
|
|
||||||
|
def subscribeToEvents() {
|
||||||
|
log.trace "subscribeToEvents()"
|
||||||
|
subscribe(app, appTouchHandler)
|
||||||
|
subscribe(contact, "contact.open", eventHandler)
|
||||||
|
subscribe(contactClosed, "contact.closed", eventHandler)
|
||||||
|
subscribe(acceleration, "acceleration.active", eventHandler)
|
||||||
|
subscribe(motion, "motion.active", eventHandler)
|
||||||
|
subscribe(mySwitch, "switch.on", eventHandler)
|
||||||
|
subscribe(mySwitchOff, "switch.off", eventHandler)
|
||||||
|
subscribe(arrivalPresence, "presence.present", eventHandler)
|
||||||
|
subscribe(departurePresence, "presence.not present", eventHandler)
|
||||||
|
subscribe(smoke, "smoke.detected", eventHandler)
|
||||||
|
subscribe(smoke, "smoke.tested", eventHandler)
|
||||||
|
subscribe(smoke, "carbonMonoxide.detected", eventHandler)
|
||||||
|
subscribe(water, "water.wet", eventHandler)
|
||||||
|
subscribe(button1, "button.pushed", eventHandler)
|
||||||
|
|
||||||
|
if (triggerModes) {
|
||||||
|
subscribe(location, modeChangeHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeOfDay) {
|
||||||
|
schedule(timeOfDay, scheduledTimeHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def eventHandler(evt) {
|
||||||
|
if (allOk) {
|
||||||
|
def lastTime = state[frequencyKey(evt)]
|
||||||
|
if (oncePerDayOk(lastTime)) {
|
||||||
|
if (frequency) {
|
||||||
|
if (lastTime == null || now() - lastTime >= frequency * 60000) {
|
||||||
|
takeAction(evt)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.debug "Not taking action because $frequency minutes have not elapsed since last action"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
takeAction(evt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.debug "Not taking action because it was already taken today"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def modeChangeHandler(evt) {
|
||||||
|
log.trace "modeChangeHandler $evt.name: $evt.value ($triggerModes)"
|
||||||
|
if (evt.value in triggerModes) {
|
||||||
|
eventHandler(evt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def scheduledTimeHandler() {
|
||||||
|
eventHandler(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
def appTouchHandler(evt) {
|
||||||
|
takeAction(evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
private takeAction(evt) {
|
||||||
|
log.debug "takeAction($actionType)"
|
||||||
|
def options = [:]
|
||||||
|
if (volume) {
|
||||||
|
bose.setLevel(volume as Integer)
|
||||||
|
options.delay = 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (actionType) {
|
||||||
|
case "Turn On & Play":
|
||||||
|
options ? bose.on(options) : bose.on()
|
||||||
|
break
|
||||||
|
case "Turn Off":
|
||||||
|
options ? bose.off(options) : bose.off()
|
||||||
|
break
|
||||||
|
case "Toggle Play/Pause":
|
||||||
|
def currentStatus = bose.currentValue("playpause")
|
||||||
|
if (currentStatus == "play") {
|
||||||
|
options ? bose.pause(options) : bose.pause()
|
||||||
|
}
|
||||||
|
else if (currentStatus == "pause") {
|
||||||
|
options ? bose.play(options) : bose.play()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "Skip to Next Track":
|
||||||
|
options ? bose.nextTrack(options) : bose.nextTrack()
|
||||||
|
break
|
||||||
|
case "Skip to Beginning/Previous Track":
|
||||||
|
options ? bose.previousTrack(options) : bose.previousTrack()
|
||||||
|
break
|
||||||
|
case "Play Preset 1":
|
||||||
|
options ? bose.preset1(options) : bose.preset1()
|
||||||
|
break
|
||||||
|
case "Play Preset 2":
|
||||||
|
options ? bose.preset2(options) : bose.preset2()
|
||||||
|
break
|
||||||
|
case "Play Preset 3":
|
||||||
|
options ? bose.preset3(options) : bose.preset3()
|
||||||
|
break
|
||||||
|
case "Play Preset 4":
|
||||||
|
options ? bose.preset4(options) : bose.preset4()
|
||||||
|
break
|
||||||
|
case "Play Preset 5":
|
||||||
|
options ? bose.preset5(options) : bose.preset5()
|
||||||
|
break
|
||||||
|
case "Play Preset 6":
|
||||||
|
options ? bose.preset6(options) : bose.preset6()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
log.error "Action type '$actionType' not defined"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frequency) {
|
||||||
|
state.lastActionTimeStamp = now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private frequencyKey(evt) {
|
||||||
|
//evt.deviceId ?: evt.value
|
||||||
|
"lastActionTimeStamp"
|
||||||
|
}
|
||||||
|
|
||||||
|
private dayString(Date date) {
|
||||||
|
def df = new java.text.SimpleDateFormat("yyyy-MM-dd")
|
||||||
|
if (location.timeZone) {
|
||||||
|
df.setTimeZone(location.timeZone)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
|
||||||
|
}
|
||||||
|
df.format(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
private oncePerDayOk(Long lastTime) {
|
||||||
|
def result = true
|
||||||
|
if (oncePerDay) {
|
||||||
|
result = lastTime ? dayString(new Date()) != dayString(new Date(lastTime)) : true
|
||||||
|
log.trace "oncePerDayOk = $result"
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - centralize somehow
|
||||||
|
private getAllOk() {
|
||||||
|
modeOk && daysOk && timeOk
|
||||||
|
}
|
||||||
|
|
||||||
|
private getModeOk() {
|
||||||
|
def result = !modes || modes.contains(location.mode)
|
||||||
|
log.trace "modeOk = $result"
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
private getDaysOk() {
|
||||||
|
def result = true
|
||||||
|
if (days) {
|
||||||
|
def df = new java.text.SimpleDateFormat("EEEE")
|
||||||
|
if (location.timeZone) {
|
||||||
|
df.setTimeZone(location.timeZone)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
|
||||||
|
}
|
||||||
|
def day = df.format(new Date())
|
||||||
|
result = days.contains(day)
|
||||||
|
}
|
||||||
|
log.trace "daysOk = $result"
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTimeOk() {
|
||||||
|
def result = true
|
||||||
|
if (starting && ending) {
|
||||||
|
def currTime = now()
|
||||||
|
def start = timeToday(starting, location?.timeZone).time
|
||||||
|
def stop = timeToday(ending, location?.timeZone).time
|
||||||
|
result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
|
||||||
|
}
|
||||||
|
log.trace "timeOk = $result"
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
private hhmm(time, fmt = "h:mm a")
|
||||||
|
{
|
||||||
|
def t = timeToday(time, location.timeZone)
|
||||||
|
def f = new java.text.SimpleDateFormat(fmt)
|
||||||
|
f.setTimeZone(location.timeZone ?: timeZone(time))
|
||||||
|
f.format(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
private timeIntervalLabel()
|
||||||
|
{
|
||||||
|
(starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
|
||||||
|
}
|
||||||
|
// TODO - End Centralize
|
||||||
Reference in New Issue
Block a user