Compare commits

..

1 Commits

Author SHA1 Message Date
Eddie winter f403b10f7a MSA-1961: Slingtv app 2017-05-06 09:21:55 -07:00
29 changed files with 391 additions and 386 deletions
@@ -38,9 +38,9 @@ metadata {
tiles (scale: 2){
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL", icon: "st.Lighting.light18") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', icon:"st.switches.light.on", backgroundColor:"#00A0DC"
attributeState "turningOn", label:'${name}', icon:"st.switches.light.on", backgroundColor:"#79b821"
attributeState "turningOff", label:'${name}', icon:"st.switches.light.off", backgroundColor:"#ffffff"
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
@@ -52,20 +52,20 @@ metadata {
}
standardTile("motion", "device.motion", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
}
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state "temperature", label:'${currentValue}°', unit:"F", icon:"", // would be better if the units would switch to the desired units of the system (imperial or metric)
backgroundColors:[
[value: 0, color: "#153591"], // blue=cold
[value: 65, color: "#44b621"], // green
[value: 70, color: "#44b621"], // green
[value: 75, color: "#f1d801"], // yellow
[value: 80, color: "#f1d801"], // yellow
[value: 85, color: "#f1d801"], // yellow
[value: 90, color: "#d04e00"], // red
[value: 95, color: "#bc2323"] // red=hot
[value: 0, color: "#1010ff"], // blue=cold
[value: 65, color: "#a0a0f0"],
[value: 70, color: "#e0e050"],
[value: 75, color: "#f0d030"], // yellow
[value: 80, color: "#fbf020"],
[value: 85, color: "#fbdc01"],
[value: 90, color: "#fb3a01"],
[value: 95, color: "#fb0801"] // red=hot
]
}
@@ -0,0 +1,77 @@
/**
* Sony Blu-ray
*
* Copyright 2017 Eddie winter
*
* 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: "Sony Blu-ray", namespace: "Eddie", author: "Eddie winter") {
capability "Acceleration Sensor"
capability "Buffered Video Capture"
capability "Location Mode"
capability "Media Controller"
capability "Refresh"
capability "Video Stream"
}
simulator {
// TODO: define status and reply messages here
}
tiles {
// TODO: define your main and details tiles here
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle 'acceleration' attribute
// TODO: handle 'clip' attribute
// TODO: handle 'mode' attribute
// TODO: handle 'activities' attribute
// TODO: handle 'currentActivity' attribute
// TODO: handle 'stream' attribute
}
// handle commands
def capture() {
log.debug "Executing 'capture'"
// TODO: handle 'capture' command
}
def setMode() {
log.debug "Executing 'setMode'"
// TODO: handle 'setMode' command
}
def startActivity() {
log.debug "Executing 'startActivity'"
// TODO: handle 'startActivity' command
}
def refresh() {
log.debug "Executing 'refresh'"
// TODO: handle 'refresh' command
}
def startStream() {
log.debug "Executing 'startStream'"
// TODO: handle 'startStream' command
}
def stopStream() {
log.debug "Executing 'stopStream'"
// TODO: handle 'stopStream' command
}
@@ -34,8 +34,8 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.motion", key:"PRIMARY_CONTROL") {
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#cccccc")
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
@@ -95,10 +95,10 @@ metadata {
multiAttributeTile(name:"doorCtrl", type:"generic", width:6, height:4) {tileAttribute("device.doorState", key: "PRIMARY_CONTROL")
{
attributeState "unknown", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", nextState:"Sent"
attributeState "open", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#00A0DC" , nextState:"Sent"
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#00A0DC"
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffffff", nextState:"Sent"
attributeState "closing", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffffff"
attributeState "open", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#0000ff" , nextState:"Sent"
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffa81e"
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#79b821", nextState:"Sent"
attributeState "closing", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffa81e"
attributeState "jammed", label: '${name}', action:"closeDoorHiI", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
attributeState "forced close", label: 'forced\rclose', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff8000", nextState:"Sent"
attributeState "fault", label: 'FAULT', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
@@ -135,13 +135,13 @@ metadata {
}
standardTile("autoClose", "device.autoCloseEnable", width: 2, height: 2){
state "on", label: 'Auto', action:"autoCloseOff", icon: "st.doors.garage.garage-closing", backgroundColor: "#00A0DC", nextState:"Sent"
state "on", label: 'Auto', action:"autoCloseOff", icon: "st.doors.garage.garage-closing", backgroundColor: "#79b821", nextState:"Sent"
state "off", label: 'Auto', action:"autoCloseOn", icon: "st.doors.garage.garage-closing", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
standardTile("autoOpen", "device.autoOpenEnable", width: 2, height: 2){
state "on", label: 'Auto', action:"autoOpenOff", icon: "st.doors.garage.garage-opening", backgroundColor: "#00A0DC", nextState:"Sent"
state "on", label: 'Auto', action:"autoOpenOff", icon: "st.doors.garage.garage-opening", backgroundColor: "#79b821", nextState:"Sent"
state "off", label: 'Auto', action:"autoOpenOn", icon: "st.doors.garage.garage-opening", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
@@ -189,13 +189,13 @@ metadata {
standardTile("aux1", "device.Aux1", width: 2, height: 2, canChangeIcon: true) {
state "off", label:'Aux 1', action:"Aux1On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent"
state "on", label:'Aux 1', action:"Aux1Off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"Sent"
state "on", label:'Aux 1', action:"Aux1Off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
standardTile("aux2", "device.Aux2", width: 2, height: 2, canChangeIcon: true) {
state "off", label:'Aux 2', action:"Aux2On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent"
state "on", label:'Aux 2', action:"Aux2Off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"Sent"
state "on", label:'Aux 2', action:"Aux2Off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
@@ -68,8 +68,8 @@
tiles {
standardTile("contact", "device.contact", width: 2, height: 2) {
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
}
valueTile("temperature", "device.temperature", inactiveLabel: false) {
state "temperature", label:'${currentValue}°',
@@ -86,7 +86,7 @@
}
standardTile("tamper", "device.alarm") {
state("secure", label:'secure', icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#00a0dc")
state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
@@ -62,8 +62,8 @@ metadata {
state "off", label: '${name}', action: "on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
}
standardTile("contact", "device.contact", inactiveLabel: false) {
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
@@ -4,7 +4,7 @@ Cloud Execution
Works with:
* [FortrezZ Siren Strobe Alarm](https://www.smartthings.com/products/fortrezz-siren-strobe-alarm)
* [FortrezZ Siren Strobe Alarm](https://www.smartthings.com/works-with-smartthings/other/fortrezz-water-valve)
## Table of contents
@@ -44,9 +44,9 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
@@ -56,8 +56,8 @@ metadata {
state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#00A0DC")
}
standardTile("contact", "device.contact") {
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
}
standardTile("acceleration", "device.acceleration", decoration: "flat") {
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC")
@@ -22,16 +22,16 @@ metadata {
tiles {
standardTile("contact", "device.contact", width: 2, height: 2) {
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC", action: "open")
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13", action: "close")
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821", action: "open")
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e", action: "close")
}
standardTile("freezerDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
}
standardTile("mainDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
}
standardTile("control", "device.contact", width: 1, height: 1, decoration: "flat") {
state("closed", label:'${name}', icon:"st.contact.contact.closed", action: "open")
@@ -25,8 +25,8 @@ metadata {
tiles(scale: 2) {
standardTile("contact", "device.contact", width: 4, height: 4) {
state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#00A0DC")
state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#e86d13")
state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#79b821")
state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#ffa81e")
}
childDeviceTile("freezerDoor", "freezerDoor", height: 2, width: 2, childTileName: "freezerDoor")
childDeviceTile("mainDoor", "mainDoor", height: 2, width: 2, childTileName: "mainDoor")
@@ -27,7 +27,7 @@ metadata {
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
}
@@ -35,7 +35,7 @@ metadata {
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'${name}', backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute("device.level", key: "SECONDARY_CONTROL") {
@@ -59,7 +59,7 @@ metadata {
tileAttribute("device.switch", key: "SECONDARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'…', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'…', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'…', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute("device.level", key: "VALUE_CONTROL") {
@@ -40,11 +40,11 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#cccccc"
attributeState "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#ff0000"
}
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
attributeState "currentIP", label: ''
@@ -38,11 +38,11 @@
tiles(scale: 2) {
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#cccccc"
attributeState "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ff0000"
}
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
attributeState "currentIP", label: ''
@@ -50,11 +50,11 @@
}
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
state "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#cccccc"
state "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ff0000"
}
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
@@ -25,7 +25,6 @@ metadata {
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: "SYLVANIA Smart A19 Soft White"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM 10 Year", deviceJoinName: "SYLVANIA Smart 10-Year A19"
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, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY PAR38 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart PAR38 Soft White"
@@ -46,9 +46,9 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
@@ -41,9 +41,9 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
}
@@ -45,9 +45,9 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
@@ -49,9 +49,9 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
@@ -1,2 +0,0 @@
.st-ignore
README.md
@@ -1,38 +0,0 @@
# Z-Wave Water Valve
Cloud Execution
Works with:
* [Leak Intelligence Leak Gopher Water Shutoff Valve](https://www.smartthings.com/works-with-smartthings/other/leak-intelligence-leak-gopher-water-shutoff-valve)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Health Check** - indicates ability to get device health notifications
* **Valve** - allows for the control of a valve device
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
## Device Health
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Leak Intelligence Leak Gopher Water Shutoff Valve Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/209631423-Leak-Gopher-Z-Wave-Valve-Control)
@@ -14,14 +14,12 @@
metadata {
definition (name: "Z-Wave Water Valve", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Health Check"
capability "Valve"
capability "Polling"
capability "Refresh"
capability "Sensor"
fingerprint deviceId: "0x1006", inClusters: "0x25"
fingerprint mfr:"0173", prod:"0003", model:"0002", deviceJoinName: "Leak Intelligence Leak Gopher Water Shutoff Valve"
}
// simulator metadata
@@ -55,14 +53,7 @@ metadata {
}
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
response(refresh())
}
@@ -123,13 +114,6 @@ def poll() {
zwave.switchBinaryV1.switchBinaryGet().format()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() {
log.debug "refresh() is called"
def commands = [zwave.switchBinaryV1.switchBinaryGet().format()]
@@ -0,0 +1,52 @@
/**
* slingtv
*
* Copyright 2017 Eddie winter
*
* 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.
*
*/
definition(
name: "slingtv",
namespace: "aenomads63@gmail.com",
author: "Eddie winter",
description: "Slingtv app ",
category: "Convenience",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png") {
appSetting "play store"
}
preferences {
section("Title") {
// TODO: put inputs here
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
// TODO: subscribe to attributes, devices, locations, etc.
}
// TODO: implement event handlers
@@ -765,6 +765,7 @@ def turnOffSwitch() {
} else {
device.off();
return [Device_id: params.id, result_action: "200"]
}
}
@@ -788,7 +789,6 @@ def getTempSensorsStatus(id) {
return []
} else {
def bat = getBatteryStatus(device.id)
def scale = [Scale: location.temperatureScale]
return [temperature: device.currentValue('temperature')] + bat + scale
return [temperature: device.currentValue('temperature')] + bat
}
}
@@ -41,14 +41,14 @@ def updated() {
def motionHandler(evt) {
log.debug "handler $evt.name: $evt.value"
if (evt.value == "inactive") {
runIn(delayMins * 60, scheduleCheck, [overwrite: true])
runIn(delayMins * 60, scheduleCheck, [overwrite: false])
}
}
def presenceHandler(evt) {
log.debug "handler $evt.name: $evt.value"
if (evt.value == "not present") {
runIn(delayMins * 60, scheduleCheck, [overwrite: true])
runIn(delayMins * 60, scheduleCheck, [overwrite: false])
}
}
@@ -1,7 +1,3 @@
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
/**
* OpenT2T SmartApp Test
*
@@ -85,33 +81,28 @@ def getInputs() {
//API external Endpoints
mappings {
path("/devices") {
action:
[
action: [
GET: "getDevices"
]
}
path("/devices/:id") {
action:
[
action: [
GET: "getDevice"
]
}
path("/update/:id") {
action:
[
action: [
PUT: "updateDevice"
]
}
path("/deviceSubscription") {
action:
[
action: [
POST: "registerDeviceChange",
DELETE: "unregisterDeviceChange"
]
}
path("/locationSubscription") {
action:
[
action: [
POST: "registerDeviceGraph",
DELETE: "unregisterDeviceGraph"
]
@@ -125,8 +116,6 @@ def installed() {
def updated() {
log.debug "Updating with settings: ${settings}"
//Initialize state variables if didn't exist.
if(state.deviceSubscriptionMap == null){
state.deviceSubscriptionMap = [:]
log.debug "deviceSubscriptionMap created."
@@ -135,11 +124,6 @@ def updated() {
state.locationSubscriptionMap = [:]
log.debug "locationSubscriptionMap created."
}
if (state.verificationKeyMap == null) {
state.verificationKeyMap = [:]
log.debug "verificationKeyMap created."
}
unsubscribe()
registerAllDeviceSubscriptions()
}
@@ -148,11 +132,9 @@ def initialize() {
log.debug "Initializing with settings: ${settings}"
state.deviceSubscriptionMap = [:]
log.debug "deviceSubscriptionMap created."
registerAllDeviceSubscriptions()
state.locationSubscriptionMap = [:]
log.debug "locationSubscriptionMap created."
state.verificationKeyMap = [:]
log.debug "verificationKeyMap created."
registerAllDeviceSubscriptions()
}
/*** Subscription Functions ***/
@@ -178,7 +160,6 @@ def registerDeviceChange() {
def subscriptionEndpt = params.subscriptionURL
def deviceId = params.deviceId
def myDevice = findDevice(deviceId)
if( myDevice == null ){
httpError(404, "Cannot find device with device ID ${deviceId}.")
}
@@ -198,18 +179,12 @@ def registerDeviceChange() {
state.deviceSubscriptionMap[deviceId] << subscriptionEndpt
log.info "Added subscription URL: ${subscriptionEndpt} for ${myDevice.displayName}"
}
if (params.key != null) {
state.verificationKeyMap[subscriptionEndpt] = params.key
log.info "Added verification key: ${params.key} for ${subscriptionEndpt}"
}
}
} catch (e) {
httpError(500, "something went wrong: $e")
}
log.info "Current subscription map is ${state.deviceSubscriptionMap}"
log.info "Current verification key map is ${state.verificationKeyMap}"
return ["succeed"]
}
@@ -231,7 +206,6 @@ def unregisterDeviceChange() {
} else {
state.deviceSubscriptionMap[deviceId].remove(subscriptionEndpt)
}
state.verificationKeyMap.remove(subscriptionEndpt)
log.info "Removed subscription URL: ${subscriptionEndpt} for ${myDevice.displayName}"
}
} else {
@@ -243,7 +217,6 @@ def unregisterDeviceChange() {
}
log.info "Current subscription map is ${state.deviceSubscriptionMap}"
log.info "Current verification key map is ${state.verificationKeyMap}"
}
//Endpoints function: Subscribe to device additiona/removal updated in a location
@@ -262,14 +235,7 @@ def registerDeviceGraph() {
state.locationSubscriptionMap[location.id] << subscriptionEndpt
log.info "Added subscription URL: ${subscriptionEndpt} for Location ${location.name}"
}
if (params.key != null) {
state.verificationKeyMap[subscriptionEndpt] = params.key
log.info "Added verification key: ${params.key} for ${subscriptionEndpt}"
}
log.info "Current location subscription map is ${state.locationSubscriptionMap}"
log.info "Current verification key map is ${state.verificationKeyMap}"
return ["succeed"]
} else {
httpError(400, "missing input parameter: subscriptionURL")
@@ -288,7 +254,6 @@ def unregisterDeviceGraph() {
} else {
state.locationSubscriptionMap[location.id].remove(subscriptionEndpt)
}
state.verificationKeyMap.remove(subscriptionEndpt)
log.info "Removed subscription URL: ${subscriptionEndpt} for Location ${location.name}"
}
}else{
@@ -299,38 +264,26 @@ def unregisterDeviceGraph() {
}
log.info "Current location subscription map is ${state.locationSubscriptionMap}"
log.info "Current verification key map is ${state.verificationKeyMap}"
}
//When events are triggered, send HTTP post to web socket servers
def deviceEventHandler(evt) {
def evtDevice = evt.device
def evtDeviceType = getDeviceType(evtDevice)
def deviceData = [];
def evt_device = evt.device
def evt_deviceType = getDeviceType(evt_device)
def deviceInfo
def params = [ body: [deviceName: evt_device.displayName, deviceId: evt_device.id, locationId: location.id] ]
if(evt.data != null){
def evtData = parseJson(evt.data)
log.info "Received event for ${evtDevice.displayName}, data: ${evtData}, description: ${evt.descriptionText}"
log.info "Received event for ${evt_device.displayName}, data: ${evtData}, description: ${evt.descriptionText}"
}
if (evtDeviceType == "thermostat") {
deviceData = [name: evtDevice.displayName, id: evtDevice.id, status: evtDevice.status, deviceType: evtDeviceType, manufacturer: evtDevice.manufacturerName, model: evtDevice.modelName, attributes: deviceAttributeList(evtDevice, evtDeviceType), locationMode: getLocationModeInfo(), locationId: location.id]
} else {
deviceData = [name: evtDevice.displayName, id: evtDevice.id, status: evtDevice.status, deviceType: evtDeviceType, manufacturer: evtDevice.manufacturerName, model: evtDevice.modelName, attributes: deviceAttributeList(evtDevice, evtDeviceType), locationId: location.id]
}
def params = [body: deviceData]
//send event to all subscriptions urls
log.debug "Current subscription urls for ${evtDevice.displayName} is ${state.deviceSubscriptionMap[evtDevice.id]}"
state.deviceSubscriptionMap[evtDevice.id].each {
log.debug "Current subscription urls for ${evt_device.displayName} is ${state.deviceSubscriptionMap[evt_device.id]}"
state.deviceSubscriptionMap[evt_device.id].each {
params.uri = "${it}"
if (state.verificationKeyMap[it] != null) {
def key = state.verificationKeyMap[it]
params.header = [Signature: ComputHMACValue(key, groovy.json.JsonOutput.toJson(params.body))]
}
log.trace "POST URI: ${params.uri}"
log.trace "Header: ${params.header}"
log.trace "Payload: ${params.body}"
try{
httpPostJson(params) { resp ->
@@ -348,22 +301,15 @@ def locationEventHandler(evt) {
switch(evt.name){
case "DeviceCreated":
case "DeviceDeleted":
def evtDevice = evt.device
def evtDeviceType = getDeviceType(evtDevice)
def params = [body: [eventType: evt.name, deviceId: evtDevice.id, locationId: location.id]]
def evt_device = evt.device
def evt_deviceType = getDeviceType(evt_device)
log.info "DeviceName: ${evt_device.displayName}, DeviceID: ${evt_device.id}, deviceType: ${evt_deviceType}"
if (evt.name == "DeviceDeleted" && state.deviceSubscriptionMap[deviceId] != null) {
state.deviceSubscriptionMap.remove(evtDevice.id)
}
def params = [ body: [ eventType:evt.name, deviceId: evt_device.id, locationId: location.id ] ]
state.locationSubscriptionMap[location.id].each {
params.uri = "${it}"
if (state.verificationKeyMap[it] != null) {
def key = state.verificationKeyMap[it]
params.header = [Signature: ComputHMACValue(key, groovy.json.JsonOutput.toJson(params.body))]
}
log.trace "POST URI: ${params.uri}"
log.trace "Header: ${params.header}"
log.trace "Payload: ${params.body}"
try{
httpPostJson(params) { resp ->
@@ -380,23 +326,6 @@ def locationEventHandler(evt) {
}
}
private ComputHMACValue(key, data) {
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA1")
Mac mac = Mac.getInstance("HmacSHA1")
mac.init(secretKeySpec)
byte[] digest = mac.doFinal(data.getBytes("UTF-8"))
return byteArrayToString(digest)
} catch (InvalidKeyException e) {
log.error "Invalid key exception while converting to HMac SHA1"
}
}
private def byteArrayToString(byte[] data) {
BigInteger bigInteger = new BigInteger(1, data)
String hash = bigInteger.toString(16)
return hash
}
/*** Device Query/Update Functions ***/
@@ -504,7 +433,8 @@ private getDeviceType(device) {
//Loop through the device capability list to determine the device type.
capabilities.each {capability ->
switch (capability.name.toLowerCase()) {
switch(capability.name.toLowerCase())
{
case "switch":
deviceType = "switch"
@@ -649,7 +579,8 @@ private mapDeviceCommands(command, value) {
if (value == 1 || value == "1" || value == "lock") {
resultCommand = "lock"
resultValue = ""
} else if (value == 0 || value == "0" || value == "unlock") {
}
else if (value == 0 || value == "0" || value == "unlock") {
resultCommand = "unlock"
resultValue = ""
}
@@ -30,15 +30,12 @@ preferences {
section("Monitor this door or window") {
input "contact", "capability.contactSensor"
}
section("And notify me if it's open for more than this many minutes (default 10)") {
input "openThreshold", "number", description: "Number of minutes", required: false
}
section("Delay between notifications (default 10 minutes") {
input "frequency", "number", title: "Number of minutes", description: "", required: false
}
section("Via text message at this number (or via push notification if not specified") {
input("recipients", "contact", title: "Send notifications to") {
input "phone", "phone", title: "Phone number (optional)", required: false
@@ -62,15 +59,18 @@ def subscribe() {
subscribe(contact, "contact.closed", doorClosed)
}
def doorOpen(evt) {
def doorOpen(evt)
{
log.trace "doorOpen($evt.name: $evt.value)"
def t0 = now()
def delay = (openThreshold != null && openThreshold != "") ? openThreshold * 60 : 600
runIn(delay, doorOpenTooLong, [overwrite: true])
runIn(delay, doorOpenTooLong, [overwrite: false])
log.debug "scheduled doorOpenTooLong in ${now() - t0} msec"
}
def doorClosed(evt) {
def doorClosed(evt)
{
log.trace "doorClosed($evt.name: $evt.value)"
unschedule(doorOpenTooLong)
}
def doorOpenTooLong() {
@@ -92,13 +92,15 @@ def doorOpenTooLong() {
}
}
void sendMessage() {
void sendMessage()
{
def minutes = (openThreshold != null && openThreshold != "") ? openThreshold : 10
def msg = "${contact.displayName} has been left open for ${minutes} minutes."
log.info msg
if (location.contactBookEnabled) {
sendNotificationToContacts(msg, recipients)
} else {
}
else {
if (phone) {
sendSms phone, msg
} else {
@@ -98,7 +98,7 @@ def motionHandler(evt) {
else {
state.motionStopTime = now()
if(delayMinutes) {
runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: true])
runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: false])
} else {
turnOffMotionAfterDelay()
}
@@ -125,19 +125,19 @@
if(allOk) {
if(everyoneIsAway() && (state.sunMode == "sunrise")) {
log.debug("Home is Empty Setting New Away Mode")
log.info("Home is Empty Setting New Away Mode")
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
runIn(delay, "setAway")
}
if(everyoneIsAway() && (state.sunMode == "sunset")) {
log.debug("Home is Empty Setting New Away Mode")
log.info("Home is Empty Setting New Away Mode")
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
runIn(delay, "setAway")
}
else {
log.debug("Home is Occupied Setting New Home Mode")
log.info("Home is Occupied Setting New Home Mode")
setHome()
@@ -152,7 +152,7 @@
log.debug("Checking if everyone is away")
if(everyoneIsAway()) {
log.debug("Nobody is home, running away sequence")
log.info("Nobody is home, running away sequence")
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
runIn(delay, "setAway")
}
@@ -161,7 +161,7 @@
else {
def lastTime = state[evt.deviceId]
if (lastTime == null || now() - lastTime >= 1 * 60000) {
log.debug("Someone is home, running home sequence")
log.info("Someone is home, running home sequence")
setHome()
}
state[evt.deviceId] = now()
@@ -175,14 +175,14 @@
if(everyoneIsAway()) {
if(state.sunMode == "sunset") {
def message = "Performing \"${awayNight}\" for you as requested."
log.debug(message)
log.info(message)
sendAway(message)
location.helloHome.execute(settings.awayNight)
}
else if(state.sunMode == "sunrise") {
def message = "Performing \"${awayDay}\" for you as requested."
log.debug(message)
log.info(message)
sendAway(message)
location.helloHome.execute(settings.awayDay)
}
@@ -192,19 +192,19 @@
}
else {
log.debug("Somebody returned home before we set to '${newAwayMode}'")
log.info("Somebody returned home before we set to '${newAwayMode}'")
}
}
//set home mode when house is occupied
def setHome() {
sendOutOfDateNotification()
log.debug("Setting Home Mode!!")
log.info("Setting Home Mode!!")
if(anyoneIsHome()) {
if(state.sunMode == "sunset"){
if (location.mode != "${homeModeNight}"){
def message = "Performing \"${homeNight}\" for you as requested."
log.debug(message)
log.info(message)
sendHome(message)
location.helloHome.execute(settings.homeNight)
}
@@ -213,7 +213,7 @@
if(state.sunMode == "sunrise"){
if (location.mode != "${homeModeDay}"){
def message = "Performing \"${homeDay}\" for you as requested."
log.debug(message)
log.info(message)
sendHome(message)
location.helloHome.execute(settings.homeDay)
}