mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-20 21:03:46 +00:00
Compare commits
1 Commits
MSA-1986-1
...
PROD_2017.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4d9cd51a3 |
@@ -38,9 +38,9 @@ metadata {
|
|||||||
tiles (scale: 2){
|
tiles (scale: 2){
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL", icon: "st.Lighting.light18") {
|
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 "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"
|
attributeState "turningOff", label:'${name}', icon:"st.switches.light.off", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
||||||
@@ -52,20 +52,20 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("motion", "device.motion", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
|
standardTile("motion", "device.motion", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
|
||||||
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC"
|
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
||||||
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
|
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
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)
|
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:[
|
backgroundColors:[
|
||||||
[value: 0, color: "#153591"], // blue=cold
|
[value: 0, color: "#1010ff"], // blue=cold
|
||||||
[value: 65, color: "#44b621"], // green
|
[value: 65, color: "#a0a0f0"],
|
||||||
[value: 70, color: "#44b621"], // green
|
[value: 70, color: "#e0e050"],
|
||||||
[value: 75, color: "#f1d801"], // yellow
|
[value: 75, color: "#f0d030"], // yellow
|
||||||
[value: 80, color: "#f1d801"], // yellow
|
[value: 80, color: "#fbf020"],
|
||||||
[value: 85, color: "#f1d801"], // yellow
|
[value: 85, color: "#fbdc01"],
|
||||||
[value: 90, color: "#d04e00"], // red
|
[value: 90, color: "#fb3a01"],
|
||||||
[value: 95, color: "#bc2323"] // red=hot
|
[value: 95, color: "#fb0801"] // red=hot
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
|
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") {
|
tileAttribute("device.motion", key:"PRIMARY_CONTROL") {
|
||||||
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#cccccc")
|
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
|
||||||
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
|
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
|
||||||
}
|
}
|
||||||
|
|
||||||
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
||||||
|
|||||||
@@ -95,12 +95,12 @@ metadata {
|
|||||||
multiAttributeTile(name:"doorCtrl", type:"generic", width:6, height:4) {tileAttribute("device.doorState", key: "PRIMARY_CONTROL")
|
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 "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 "open", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#0000ff" , nextState:"Sent"
|
||||||
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#00A0DC"
|
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffa81e"
|
||||||
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffffff", nextState:"Sent"
|
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: "#ffffff"
|
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 "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 "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"
|
attributeState "fault", label: 'FAULT', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
|
||||||
attributeState "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
attributeState "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
||||||
}
|
}
|
||||||
@@ -135,13 +135,13 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("autoClose", "device.autoCloseEnable", width: 2, height: 2){
|
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 "off", label: 'Auto', action:"autoCloseOn", icon: "st.doors.garage.garage-closing", nextState:"Sent"
|
||||||
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("autoOpen", "device.autoOpenEnable", width: 2, height: 2){
|
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 "off", label: 'Auto', action:"autoOpenOn", icon: "st.doors.garage.garage-opening", nextState:"Sent"
|
||||||
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
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) {
|
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 "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"
|
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("aux2", "device.Aux2", width: 2, height: 2, canChangeIcon: true) {
|
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 "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"
|
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,8 +68,8 @@
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("contact", "device.contact", width: 2, height: 2) {
|
standardTile("contact", "device.contact", width: 2, height: 2) {
|
||||||
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
|
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
|
||||||
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
|
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
||||||
state "temperature", label:'${currentValue}°',
|
state "temperature", label:'${currentValue}°',
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
}
|
}
|
||||||
standardTile("tamper", "device.alarm") {
|
standardTile("tamper", "device.alarm") {
|
||||||
state("secure", label:'secure', icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
|
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") {
|
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ metadata {
|
|||||||
state "off", label: '${name}', action: "on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
state "off", label: '${name}', action: "on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
||||||
}
|
}
|
||||||
standardTile("contact", "device.contact", inactiveLabel: false) {
|
standardTile("contact", "device.contact", inactiveLabel: false) {
|
||||||
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
|
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
|
||||||
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
|
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Cloud Execution
|
|||||||
|
|
||||||
Works with:
|
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
|
## Table of contents
|
||||||
|
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
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 "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"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ metadata {
|
|||||||
state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#00A0DC")
|
state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#00A0DC")
|
||||||
}
|
}
|
||||||
standardTile("contact", "device.contact") {
|
standardTile("contact", "device.contact") {
|
||||||
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
||||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
|
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
||||||
}
|
}
|
||||||
standardTile("acceleration", "device.acceleration", decoration: "flat") {
|
standardTile("acceleration", "device.acceleration", decoration: "flat") {
|
||||||
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC")
|
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC")
|
||||||
|
|||||||
@@ -22,16 +22,16 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("contact", "device.contact", width: 2, height: 2) {
|
standardTile("contact", "device.contact", width: 2, height: 2) {
|
||||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC", action: "open")
|
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821", action: "open")
|
||||||
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13", action: "close")
|
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e", action: "close")
|
||||||
}
|
}
|
||||||
standardTile("freezerDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
|
standardTile("freezerDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
|
||||||
state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
|
state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
||||||
state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
||||||
}
|
}
|
||||||
standardTile("mainDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
|
standardTile("mainDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
|
||||||
state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
|
state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
||||||
state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
||||||
}
|
}
|
||||||
standardTile("control", "device.contact", width: 1, height: 1, decoration: "flat") {
|
standardTile("control", "device.contact", width: 1, height: 1, decoration: "flat") {
|
||||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", action: "open")
|
state("closed", label:'${name}', icon:"st.contact.contact.closed", action: "open")
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ metadata {
|
|||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
standardTile("contact", "device.contact", width: 4, height: 4) {
|
standardTile("contact", "device.contact", width: 4, height: 4) {
|
||||||
state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#00A0DC")
|
state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#79b821")
|
||||||
state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#e86d13")
|
state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#ffa81e")
|
||||||
}
|
}
|
||||||
childDeviceTile("freezerDoor", "freezerDoor", height: 2, width: 2, childTileName: "freezerDoor")
|
childDeviceTile("freezerDoor", "freezerDoor", height: 2, width: 2, childTileName: "freezerDoor")
|
||||||
childDeviceTile("mainDoor", "mainDoor", height: 2, width: 2, childTileName: "mainDoor")
|
childDeviceTile("mainDoor", "mainDoor", height: 2, width: 2, childTileName: "mainDoor")
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ metadata {
|
|||||||
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
|
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:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
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"
|
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") {
|
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
|
attributeState "on", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
|
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"
|
attributeState "turningOff", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute("device.level", key: "SECONDARY_CONTROL") {
|
tileAttribute("device.level", key: "SECONDARY_CONTROL") {
|
||||||
@@ -59,7 +59,7 @@ metadata {
|
|||||||
tileAttribute("device.switch", key: "SECONDARY_CONTROL") {
|
tileAttribute("device.switch", key: "SECONDARY_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:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
|
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"
|
attributeState "turningOff", label:'…', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute("device.level", key: "VALUE_CONTROL") {
|
tileAttribute("device.level", key: "VALUE_CONTROL") {
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
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 "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 "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") {
|
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
|
||||||
attributeState "currentIP", label: ''
|
attributeState "currentIP", label: ''
|
||||||
|
|||||||
@@ -38,11 +38,11 @@
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
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 "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 "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") {
|
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
|
||||||
attributeState "currentIP", label: ''
|
attributeState "currentIP", label: ''
|
||||||
@@ -50,11 +50,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
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 "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 "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") {
|
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
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 "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"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
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 "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"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
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 "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"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
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 "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"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
|
|||||||
@@ -15,66 +15,66 @@ definition(
|
|||||||
)
|
)
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
section("Light switches to turn off") {
|
section("Light switches to turn off") {
|
||||||
input "switches", "capability.switch", title: "Choose light switches", multiple: true
|
input "switches", "capability.switch", title: "Choose light switches", multiple: true
|
||||||
}
|
}
|
||||||
section("Turn off when there is no motion and presence") {
|
section("Turn off when there is no motion and presence") {
|
||||||
input "motionSensor", "capability.motionSensor", title: "Choose motion sensor"
|
input "motionSensor", "capability.motionSensor", title: "Choose motion sensor"
|
||||||
input "presenceSensors", "capability.presenceSensor", title: "Choose presence sensors", multiple: true
|
input "presenceSensors", "capability.presenceSensor", title: "Choose presence sensors", multiple: true
|
||||||
}
|
}
|
||||||
section("Delay before turning off") {
|
section("Delay before turning off") {
|
||||||
input "delayMins", "number", title: "Minutes of inactivity?"
|
input "delayMins", "number", title: "Minutes of inactivity?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def installed() {
|
def installed() {
|
||||||
subscribe(motionSensor, "motion", motionHandler)
|
subscribe(motionSensor, "motion", motionHandler)
|
||||||
subscribe(presenceSensors, "presence", presenceHandler)
|
subscribe(presenceSensors, "presence", presenceHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
subscribe(motionSensor, "motion", motionHandler)
|
subscribe(motionSensor, "motion", motionHandler)
|
||||||
subscribe(presenceSensors, "presence", presenceHandler)
|
subscribe(presenceSensors, "presence", presenceHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
def motionHandler(evt) {
|
def motionHandler(evt) {
|
||||||
log.debug "handler $evt.name: $evt.value"
|
log.debug "handler $evt.name: $evt.value"
|
||||||
if (evt.value == "inactive") {
|
if (evt.value == "inactive") {
|
||||||
runIn(delayMins * 60, scheduleCheck, [overwrite: true])
|
runIn(delayMins * 60, scheduleCheck, [overwrite: false])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def presenceHandler(evt) {
|
def presenceHandler(evt) {
|
||||||
log.debug "handler $evt.name: $evt.value"
|
log.debug "handler $evt.name: $evt.value"
|
||||||
if (evt.value == "not present") {
|
if (evt.value == "not present") {
|
||||||
runIn(delayMins * 60, scheduleCheck, [overwrite: true])
|
runIn(delayMins * 60, scheduleCheck, [overwrite: false])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def isActivePresence() {
|
def isActivePresence() {
|
||||||
// check all the presence sensors, make sure none are present
|
// check all the presence sensors, make sure none are present
|
||||||
def noPresence = presenceSensors.find{it.currentPresence == "present"} == null
|
def noPresence = presenceSensors.find{it.currentPresence == "present"} == null
|
||||||
!noPresence
|
!noPresence
|
||||||
}
|
}
|
||||||
|
|
||||||
def scheduleCheck() {
|
def scheduleCheck() {
|
||||||
log.debug "scheduled check"
|
log.debug "scheduled check"
|
||||||
def motionState = motionSensor.currentState("motion")
|
def motionState = motionSensor.currentState("motion")
|
||||||
if (motionState.value == "inactive") {
|
if (motionState.value == "inactive") {
|
||||||
def elapsed = now() - motionState.rawDateCreated.time
|
def elapsed = now() - motionState.rawDateCreated.time
|
||||||
def threshold = 1000 * 60 * delayMins - 1000
|
def threshold = 1000 * 60 * delayMins - 1000
|
||||||
if (elapsed >= threshold) {
|
if (elapsed >= threshold) {
|
||||||
if (!isActivePresence()) {
|
if (!isActivePresence()) {
|
||||||
log.debug "Motion has stayed inactive since last check ($elapsed ms) and no presence: turning lights off"
|
log.debug "Motion has stayed inactive since last check ($elapsed ms) and no presence: turning lights off"
|
||||||
switches.off()
|
switches.off()
|
||||||
} else {
|
} else {
|
||||||
log.debug "Presence is active: do nothing"
|
log.debug "Presence is active: do nothing"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.debug "Motion has not stayed inactive long enough since last check ($elapsed ms): do nothing"
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
log.debug "Motion has not stayed inactive long enough since last check ($elapsed ms): do nothing"
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log.debug "Motion is active: do nothing"
|
log.debug "Motion is active: do nothing"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,82 +27,84 @@ definition(
|
|||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
|
|
||||||
section("Monitor this door or window") {
|
section("Monitor this door or window") {
|
||||||
input "contact", "capability.contactSensor"
|
input "contact", "capability.contactSensor"
|
||||||
}
|
}
|
||||||
|
section("And notify me if it's open for more than this many minutes (default 10)") {
|
||||||
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
|
||||||
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("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
|
|
||||||
}
|
}
|
||||||
}
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def installed() {
|
def installed() {
|
||||||
log.trace "installed()"
|
log.trace "installed()"
|
||||||
subscribe()
|
subscribe()
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
log.trace "updated()"
|
log.trace "updated()"
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
subscribe()
|
subscribe()
|
||||||
}
|
}
|
||||||
|
|
||||||
def subscribe() {
|
def subscribe() {
|
||||||
subscribe(contact, "contact.open", doorOpen)
|
subscribe(contact, "contact.open", doorOpen)
|
||||||
subscribe(contact, "contact.closed", doorClosed)
|
subscribe(contact, "contact.closed", doorClosed)
|
||||||
}
|
}
|
||||||
|
|
||||||
def doorOpen(evt) {
|
def doorOpen(evt)
|
||||||
log.trace "doorOpen($evt.name: $evt.value)"
|
{
|
||||||
def delay = (openThreshold != null && openThreshold != "") ? openThreshold * 60 : 600
|
log.trace "doorOpen($evt.name: $evt.value)"
|
||||||
runIn(delay, doorOpenTooLong, [overwrite: true])
|
def t0 = now()
|
||||||
|
def delay = (openThreshold != null && openThreshold != "") ? openThreshold * 60 : 600
|
||||||
|
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)
|
log.trace "doorClosed($evt.name: $evt.value)"
|
||||||
}
|
}
|
||||||
|
|
||||||
def doorOpenTooLong() {
|
def doorOpenTooLong() {
|
||||||
def contactState = contact.currentState("contact")
|
def contactState = contact.currentState("contact")
|
||||||
def freq = (frequency != null && frequency != "") ? frequency * 60 : 600
|
def freq = (frequency != null && frequency != "") ? frequency * 60 : 600
|
||||||
|
|
||||||
if (contactState.value == "open") {
|
if (contactState.value == "open") {
|
||||||
def elapsed = now() - contactState.rawDateCreated.time
|
def elapsed = now() - contactState.rawDateCreated.time
|
||||||
def threshold = ((openThreshold != null && openThreshold != "") ? openThreshold * 60000 : 60000) - 1000
|
def threshold = ((openThreshold != null && openThreshold != "") ? openThreshold * 60000 : 60000) - 1000
|
||||||
if (elapsed >= threshold) {
|
if (elapsed >= threshold) {
|
||||||
log.debug "Contact has stayed open long enough since last check ($elapsed ms): calling sendMessage()"
|
log.debug "Contact has stayed open long enough since last check ($elapsed ms): calling sendMessage()"
|
||||||
sendMessage()
|
sendMessage()
|
||||||
runIn(freq, doorOpenTooLong, [overwrite: false])
|
runIn(freq, doorOpenTooLong, [overwrite: false])
|
||||||
} else {
|
} else {
|
||||||
log.debug "Contact has not stayed open long enough since last check ($elapsed ms): doing nothing"
|
log.debug "Contact has not stayed open long enough since last check ($elapsed ms): doing nothing"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.warn "doorOpenTooLong() called but contact is closed: doing nothing"
|
log.warn "doorOpenTooLong() called but contact is closed: doing nothing"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendMessage() {
|
void sendMessage()
|
||||||
def minutes = (openThreshold != null && openThreshold != "") ? openThreshold : 10
|
{
|
||||||
def msg = "${contact.displayName} has been left open for ${minutes} minutes."
|
def minutes = (openThreshold != null && openThreshold != "") ? openThreshold : 10
|
||||||
log.info msg
|
def msg = "${contact.displayName} has been left open for ${minutes} minutes."
|
||||||
if (location.contactBookEnabled) {
|
log.info msg
|
||||||
sendNotificationToContacts(msg, recipients)
|
if (location.contactBookEnabled) {
|
||||||
} else {
|
sendNotificationToContacts(msg, recipients)
|
||||||
if (phone) {
|
}
|
||||||
sendSms phone, msg
|
else {
|
||||||
} else {
|
if (phone) {
|
||||||
sendPush msg
|
sendSms phone, msg
|
||||||
|
} else {
|
||||||
|
sendPush msg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,373 +0,0 @@
|
|||||||
/**
|
|
||||||
* SmartThingsToStart REST Api
|
|
||||||
*
|
|
||||||
* Copyright 2017 Dr1rrb
|
|
||||||
*
|
|
||||||
* 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: "SmartThingsToStart",
|
|
||||||
namespace: "torick.net",
|
|
||||||
author: "Dr1rrb",
|
|
||||||
description: "SmartThingsToStart REST Api",
|
|
||||||
category: "My Apps",
|
|
||||||
iconUrl: "http://smartthingstostartproxy.azurewebsites.net/Assets/AppLogo.png",
|
|
||||||
iconX2Url: "http://smartthingstostartproxy.azurewebsites.net/Assets/AppLogo@2X.png",
|
|
||||||
iconX3Url: "http://smartthingstostartproxy.azurewebsites.net/Assets/AppLogo@3X.png",
|
|
||||||
oauth: true)
|
|
||||||
|
|
||||||
|
|
||||||
preferences {
|
|
||||||
section("Control these devices") {
|
|
||||||
input "switches", "capability.switch", title: "Select switches", multiple: true, required: false
|
|
||||||
input "bubls", "capability.bulb", title: "Select bubls", hideWhenEmpty: true, multiple: true, required: false
|
|
||||||
input "lights", "capability.light", title: "Select lights", hideWhenEmpty: true, multiple: true, required: false
|
|
||||||
input "outlets", "capability.outlet", title: "Select outlets", hideWhenEmpty: true, multiple: true, required: false
|
|
||||||
input "relaySwitches", "capability.relaySwitch", title: "Select relay switches", hideWhenEmpty: true, multiple: true, required: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mappings {
|
|
||||||
path("/infos") {
|
|
||||||
action: [GET: "retreiveServerInfos"]
|
|
||||||
}
|
|
||||||
path("/items") {
|
|
||||||
action: [GET: "retreiveDevicesAndRoutines"]
|
|
||||||
}
|
|
||||||
path("/device/:id") {
|
|
||||||
action: [GET: "retreiveDevice"]
|
|
||||||
}
|
|
||||||
path("/device/:id/subscription/:subscriptionId") {
|
|
||||||
action: [
|
|
||||||
PUT: "updateOrCreateSubscription",
|
|
||||||
POST: "updateOrCreateSubscription",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
// TODO
|
|
||||||
//path("/device/:id/unsubscribe") {
|
|
||||||
// action: [POST: "unsubscribeFromDevice"]
|
|
||||||
//}
|
|
||||||
path("/device/:id/:command") {
|
|
||||||
action: [ PUT: "updateDevice" ]
|
|
||||||
}
|
|
||||||
path("/routine/:id/execute") {
|
|
||||||
action: [PUT: "executeRoutine"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Region: App lifecycle
|
|
||||||
def installed() {
|
|
||||||
log.debug "Installed with settings: ${settings}"
|
|
||||||
|
|
||||||
initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
def updated() {
|
|
||||||
log.debug "Updated with settings: ${settings}"
|
|
||||||
|
|
||||||
unsubscribe()
|
|
||||||
//state.pushChannels = [:]
|
|
||||||
initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
def initialize() {
|
|
||||||
def channels = state.pushChannels = state.pushChannels ?: [:];
|
|
||||||
channels.each
|
|
||||||
{
|
|
||||||
def device = findDevice(it.key);
|
|
||||||
if (device != null)
|
|
||||||
{
|
|
||||||
subscribeToDevice(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Region: Http request handlers
|
|
||||||
def retreiveServerInfos()
|
|
||||||
{
|
|
||||||
return [version: 1]
|
|
||||||
}
|
|
||||||
|
|
||||||
def retreiveDevicesAndRoutines() {
|
|
||||||
def details = params.details == "true" ? true : false;
|
|
||||||
|
|
||||||
return [
|
|
||||||
devices: getDevices().collect { getDeviceInfos(it, details) },
|
|
||||||
routines: location.helloHome?.getPhrases().collect { getRoutineInfos(it, details) }
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
def retreiveDevice() {
|
|
||||||
def device = getDevice(params.id);
|
|
||||||
def details = params.details == "true" ? true : false;
|
|
||||||
|
|
||||||
return getDeviceInfos(device, details);
|
|
||||||
}
|
|
||||||
|
|
||||||
def updateOrCreateSubscription() {
|
|
||||||
def device = getDevice(params.id);
|
|
||||||
def channelUri = notNull("channelUri", request.JSON?.channelUri);
|
|
||||||
def token = notNull("token", request.JSON?.token);
|
|
||||||
|
|
||||||
log.debug "Subscribing to device '${device.id}' (target: '${channelUri}' / token: '${token}')"
|
|
||||||
|
|
||||||
// Get or create the push notification channel from / into the local state
|
|
||||||
def subscriptionId = params.subscriptionId ?: UUID.randomUUID().toString() ;
|
|
||||||
def allSubscriptions = state.pushChannels ?: (state.pushChannels = [:]);
|
|
||||||
def deviceSubscriptions = allSubscriptions[device.id] ?: (allSubscriptions[device.id] = []);
|
|
||||||
def subscription = deviceSubscriptions.find { it.id == subscriptionId };
|
|
||||||
if (subscription == null)
|
|
||||||
{
|
|
||||||
deviceSubscriptions << [
|
|
||||||
id: subscriptionId,
|
|
||||||
deviceId: device.id,
|
|
||||||
channelUri: channelUri,
|
|
||||||
token: token
|
|
||||||
];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
subscription["channelUri"] = channelUri;
|
|
||||||
subscription["token"] = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug "Active subscriptions: \n" + state.pushChannels.collect { "** Device ${it.key} **\n" + it.value.collect{c -> "- - - > ${c.channelUri} : ${c.token.substring(0, 10)}..."}.join('\n') + "\n***************************" }.join('\n\n')
|
|
||||||
|
|
||||||
// (Re)create the subscription(s)
|
|
||||||
subscribeToDevice(device)
|
|
||||||
|
|
||||||
return [subscriptionId: subscriptionId];
|
|
||||||
}
|
|
||||||
|
|
||||||
def subscribeToDevice(device)
|
|
||||||
{
|
|
||||||
log.debug "Subscribing to device '${device.id}'"
|
|
||||||
|
|
||||||
unsubscribe(device);
|
|
||||||
subscribe(device, "switch", switchStateChanged)
|
|
||||||
|
|
||||||
if (device.hasCapability("Color Control"))
|
|
||||||
{
|
|
||||||
log.debug "Device '${device.id}' has also the color capability. Subscribe to it."
|
|
||||||
subscribe(device, "color", colorStateChanged)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def switchStateChanged(eventArgs) { sendPushNotification("switch", eventArgs) }
|
|
||||||
def colorStateChanged(eventArgs) { sendPushNotification("color", eventArgs) }
|
|
||||||
|
|
||||||
def updateDevice() {
|
|
||||||
def device = getDevice(params.id)
|
|
||||||
def command = notNull("command", params.command)
|
|
||||||
|
|
||||||
log.debug "Executing '${command}' on device '${device.id}'."
|
|
||||||
|
|
||||||
switch(command) {
|
|
||||||
case "on":
|
|
||||||
case "On":
|
|
||||||
device.on()
|
|
||||||
break
|
|
||||||
|
|
||||||
case "off":
|
|
||||||
case "Off":
|
|
||||||
device.off()
|
|
||||||
break
|
|
||||||
|
|
||||||
case "toggle":
|
|
||||||
case "Toggle":
|
|
||||||
if (device.currentSwitch == "on")
|
|
||||||
device.off();
|
|
||||||
else
|
|
||||||
device.on();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
httpError(501, "'${command}' is not a valid command for '${device.id}'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return getDeviceInfos(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
def executeRoutine() {
|
|
||||||
def routine = getRoutine(params.id);
|
|
||||||
log.debug "Executing routine '${routine.id}' (${routine.label})"
|
|
||||||
|
|
||||||
location.helloHome?.execute(routine.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Region: Get device
|
|
||||||
def getDevices()
|
|
||||||
{
|
|
||||||
return switches
|
|
||||||
+ bubls
|
|
||||||
+ lights
|
|
||||||
+ outlets
|
|
||||||
+ relaySwitches;
|
|
||||||
}
|
|
||||||
|
|
||||||
def findDevice(deviceId)
|
|
||||||
{
|
|
||||||
notNull("deviceId", deviceId);
|
|
||||||
|
|
||||||
return getDevices().find { it.id == deviceId };
|
|
||||||
}
|
|
||||||
|
|
||||||
def getDevice(deviceId)
|
|
||||||
{
|
|
||||||
def device = findDevice(deviceId);
|
|
||||||
if (device == null)
|
|
||||||
{
|
|
||||||
httpError(404, "Device '${deviceId}' not found.")
|
|
||||||
}
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Region: Get routine
|
|
||||||
def findRoutine(routineId)
|
|
||||||
{
|
|
||||||
return location.helloHome?.getPhrases().find{ it.id == routineId};
|
|
||||||
}
|
|
||||||
|
|
||||||
def getRoutine(routineId)
|
|
||||||
{
|
|
||||||
def routine = findRoutine(routineId);
|
|
||||||
if (routine == null)
|
|
||||||
{
|
|
||||||
httpError(404, "Routine '${routineId}' not found.")
|
|
||||||
}
|
|
||||||
return routine;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Region: Parameters assertion helpers
|
|
||||||
def notNull(parameterName, value)
|
|
||||||
{
|
|
||||||
if(value == null || value == "")
|
|
||||||
{
|
|
||||||
httpError(404, "Missing parameter '${parameterName}'.")
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Region: Get infos
|
|
||||||
def getDeviceInfos(device, details = false)
|
|
||||||
{
|
|
||||||
def infos = [
|
|
||||||
id: device.id,
|
|
||||||
name: device.displayName,
|
|
||||||
state: device.currentValue("switch"),
|
|
||||||
color: device.currentValue("color"),
|
|
||||||
hue: device.currentValue("hue"),
|
|
||||||
saturation: device.currentValue("saturation"),
|
|
||||||
capabilities: device.capabilities.collect { getCapabilityInfos(it, details) }
|
|
||||||
]
|
|
||||||
|
|
||||||
if (details)
|
|
||||||
{
|
|
||||||
infos["attributes"] = device.supportedAttributes.collect { getAttributeInfos(it, details) }
|
|
||||||
infos["commands"] = device.supportedCommands.collect { getCommandInfos(it, details) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return infos;
|
|
||||||
}
|
|
||||||
|
|
||||||
def getCapabilityInfos(capablity, details = false)
|
|
||||||
{
|
|
||||||
def infos = [name: capablity.name]
|
|
||||||
|
|
||||||
if(details)
|
|
||||||
{
|
|
||||||
infos["attributes"] = capablity.attributes.collect { getAttributeInfos(it, details) }
|
|
||||||
infos["commands"] = capablity.commands.collect { getCommandInfos(it, details) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return infos;
|
|
||||||
}
|
|
||||||
|
|
||||||
def getCommandInfos(command, details = false)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
name: command.name,
|
|
||||||
arguments: command.arguments
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
def getAttributeInfos(attribute, details = false)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
name: attribute.name,
|
|
||||||
arguments: attribute.dataType,
|
|
||||||
values: attribute.values
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
def getRoutineInfos(routine, details = false)
|
|
||||||
{
|
|
||||||
def infos = [
|
|
||||||
id: routine.id,
|
|
||||||
name: routine.label
|
|
||||||
];
|
|
||||||
|
|
||||||
if (details)
|
|
||||||
{
|
|
||||||
infos["hasSecureActions"] = routine.hasSecureActions;
|
|
||||||
infos["action"] = routine.action;
|
|
||||||
}
|
|
||||||
|
|
||||||
return infos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Region: Push notification
|
|
||||||
def sendPushNotification(capability, eventArgs)
|
|
||||||
{
|
|
||||||
def deviceId = eventArgs.deviceId;
|
|
||||||
log.debug "Received notification for '${capability}' for device '${deviceId}'.";
|
|
||||||
|
|
||||||
def subscriptions = state.pushChannels.get(deviceId);
|
|
||||||
if (subscriptions == null || subscriptions.empty)
|
|
||||||
{
|
|
||||||
log.error "No subscription found for device ${deviceId}, unsubscribing!";
|
|
||||||
unsubscribe(eventArgs.device);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
subscriptions.groupBy { it.channelUri }.each { sendPushNotification(capability, eventArgs, it.key, it.value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
def sendPushNotification(capability, eventArgs, channelUri, subscriptions)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
def request = [
|
|
||||||
uri: channelUri,
|
|
||||||
//headers: [name: "Authorization", value: "Bearer ${subscription.token}"],
|
|
||||||
body: [
|
|
||||||
location: [
|
|
||||||
id: eventArgs.locationId,
|
|
||||||
],
|
|
||||||
device: getDeviceInfos(eventArgs.device),
|
|
||||||
event: [
|
|
||||||
source: capability,
|
|
||||||
date: eventArgs.isoDate,
|
|
||||||
value: eventArgs.value,
|
|
||||||
name: eventArgs.name,
|
|
||||||
],
|
|
||||||
subscriptions: subscriptions.collect { [id: it.id, token: it.token] }
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
// Async post is still in beta stage ...
|
|
||||||
httpPostJson(request) { resp -> log.debug "response: ${resp.status}." }
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
log.error "Failed to push notification: ${e}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user