Compare commits

..

1 Commits

Author SHA1 Message Date
Patrick Malm
6cef95c141 MSA-1846: null 2017-03-16 13:59:18 -07:00
142 changed files with 1897 additions and 4909 deletions

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,41 +0,0 @@
# Fibaro Door Window Sensor ZW5
Cloud Execution
Works with:
* [Fibaro Door/Window Sensor ZW5](https://www.smartthings.com/works-with-smartthings/sensors/fibaro-doorwindow-sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Battery** - defines device uses a battery
* **Contact Sensor** - can detect contact (possible values: open,closed)
* **Sensor** - detects sensor events
* **Tamper Alert** - detects tampers
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Health Check** - indicates ability to get device health notifications
## Device Health
Fibaro Door/Window Sensor ZW5 is a Z-wave sleepy device and wakes up every 4 hours.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*4*60 + 2)mins = 482 mins.
* __482min__ checkInterval
## Battery Specification
One 1/2AA 3.6V battery is required.
## 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:
* [Fibaro Door/Window Sensor ZW5 Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204075194-Fibaro-Door-Window-Sensor)

View File

@@ -20,7 +20,6 @@ metadata {
capability "Sensor" capability "Sensor"
capability "Configuration" capability "Configuration"
capability "Tamper Alert" capability "Tamper Alert"
capability "Health Check"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x86, 0x84", outClusters: "" fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x86, 0x84", outClusters: ""
} }
@@ -200,9 +199,7 @@ def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLoca
def configure() { def configure() {
log.debug "Executing 'configure'" log.debug "Executing 'configure'"
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
def cmds = [] def cmds = []
cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds:21600, nodeid: zwaveHubNodeId)//FGK's default wake up interval cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds:21600, nodeid: zwaveHubNodeId)//FGK's default wake up interval

View File

@@ -34,13 +34,13 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"FGFS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app multiAttributeTile(name:"FGFS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.water", key:"PRIMARY_CONTROL") { tileAttribute("device.water", key:"PRIMARY_CONTROL") {
attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff") attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#00a0dc")
attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#00a0dc") attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#e86d13")
} }
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") { tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#cccccc") attributeState("active", label:'tamper active', backgroundColor:"#00a0dc")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#00A0DC") attributeState("inactive", label:'tamper inactive', backgroundColor:"#cccccc")
} }
} }

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,39 +0,0 @@
# Keen Home Smart Vent
Cloud Execution
Works with:
* [Keen Home Smart Vent](https://www.smartthings.com/works-with-smartthings/keen-home/keen-home-smart-vent)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Switch** - can detect state (possible values: on/off)
* **Switch Level** - represents current light level, usually 0-100 in percent
* **Sensor** - detects sensor events
* **Temperature Measurement** - represents capability to measure temperature
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Battery** - defines device uses a battery
* **Refresh** - _refresh()_ command for status updates
* **Health Check** - indicates ability to get device health notifications
## Device Health
Keen Home Smart Vent with reporting interval of 10 mins.
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
* __22min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the different motion sensors from SmartThings can be found in the following links
for the different models:
* [Keen Home Smart Vent Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205302050-Keen-Home-Smart-Vent)

View File

@@ -11,7 +11,6 @@ metadata {
capability "Sensor" capability "Sensor"
capability "Temperature Measurement" capability "Temperature Measurement"
capability "Battery" capability "Battery"
// capability "Health Check"
command "getLevel" command "getLevel"
command "getOnOff" command "getOnOff"
@@ -21,7 +20,10 @@ metadata {
command "setZigBeeIdTile" command "setZigBeeIdTile"
command "clearObstruction" command "clearObstruction"
fingerprint endpoint: "1", profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0006,0008,0020,0402,0403,0B05,FC01,FC02", outClusters: "0019" fingerprint endpoint: "1",
profileId: "0104",
inClusters: "0000,0001,0003,0004,0005,0006,0008,0020,0402,0403,0B05,FC01,FC02",
outClusters: "0019"
} }
// simulator metadata // simulator metadata
@@ -38,10 +40,10 @@ metadata {
// UI tile definitions // UI tile definitions
tiles { tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", action: "switch.off", icon: "st.vents.vent-open-text", backgroundColor: "#00a0dc" state "on", action: "switch.off", icon: "st.vents.vent-open-text", backgroundColor: "#53a7c0"
state "off", action: "switch.on", icon: "st.vents.vent-closed", backgroundColor: "#ffffff" state "off", action: "switch.on", icon: "st.vents.vent-closed", backgroundColor: "#ffffff"
state "obstructed", action: "clearObstruction", icon: "st.vents.vent-closed", backgroundColor: "#e86d13" state "obstructed", action: "clearObstruction", icon: "st.vents.vent-closed", backgroundColor: "#ff0000"
state "clearing", action: "", icon: "st.vents.vent-closed", backgroundColor: "#ffffff" state "clearing", action: "", icon: "st.vents.vent-closed", backgroundColor: "#ffff33"
} }
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false) { controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false) {
state "level", action:"switch level.setLevel" state "level", action:"switch level.setLevel"
@@ -464,27 +466,15 @@ def refresh() {
getBattery() getBattery()
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return refresh()
}
def configure() { def configure() {
log.debug "CONFIGURE" log.debug "CONFIGURE"
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
// sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
// get ZigBee ID by hidden tile because that's the only way we can do it // get ZigBee ID by hidden tile because that's the only way we can do it
setZigBeeIdTile() setZigBeeIdTile()
def configCmds = [ def configCmds = [
// bind reporting clusters to hub // bind reporting clusters to hub
//commenting out switch cluster bind as using wrapper onOffConfig of zigbee class "zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 500",
//"zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0008 {${device.zigbeeId}} {}", "delay 500", "zdo bind 0x${device.deviceNetworkId} 1 1 0x0008 {${device.zigbeeId}} {}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0402 {${device.zigbeeId}} {}", "delay 500", "zdo bind 0x${device.deviceNetworkId} 1 1 0x0402 {${device.zigbeeId}} {}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0403 {${device.zigbeeId}} {}", "delay 500", "zdo bind 0x${device.deviceNetworkId} 1 1 0x0403 {${device.zigbeeId}} {}", "delay 500",
@@ -520,5 +510,5 @@ def configure() {
// "send 0x${device.deviceNetworkId} 1 1", "delay 1500", // "send 0x${device.deviceNetworkId} 1 1", "delay 1500",
] ]
return configCmds + zigbee.onOffConfig() + refresh() return configCmds + refresh()
} }

View File

@@ -1,5 +1,6 @@
/** /**
* Spruce Controller V2_4 Big Tiles * * Spruce Controller - Pre Release V2 10/11/2015
*
* Copyright 2015 Plaid Systems * Copyright 2015 Plaid Systems
* *
* Author: NC * Author: NC
@@ -20,96 +21,82 @@
*/ */
metadata { metadata {
definition (name: 'Spruce Controller', namespace: 'plaidsystems', author: 'Plaid Systems') { definition (name: "Spruce Controller", namespace: "plaidsystems", author: "NCauffman") {
capability 'Switch' capability "Switch"
capability 'Configuration' capability "Configuration"
capability 'Refresh' capability "Refresh"
capability 'Actuator' capability "Actuator"
capability 'Valve' capability "Valve"
attribute 'switch', 'string' attribute "switch", "string"
attribute 'switch1', 'string' attribute "switch1", "string"
attribute 'switch2', 'string' attribute "switch2", "string"
attribute 'switch8', 'string' attribute "switch8", "string"
attribute 'switch5', 'string' attribute "switch5", "string"
attribute 'switch3', 'string' attribute "switch3", "string"
attribute 'switch4', 'string' attribute "switch4", "string"
attribute 'switch6', 'string' attribute "switch6", "string"
attribute 'switch7', 'string' attribute "switch7", "string"
attribute 'switch9', 'string' attribute "switch9", "string"
attribute 'switch10', 'string' attribute "switch10", "string"
attribute 'switch11', 'string' attribute "switch11", "string"
attribute 'switch12', 'string' attribute "switch12", "string"
attribute 'switch13', 'string' attribute "switch13", "string"
attribute 'switch14', 'string' attribute "switch14", "string"
attribute 'switch15', 'string' attribute "switch15", "string"
attribute 'switch16', 'string' attribute "switch16", "string"
attribute 'rainsensor', 'string' attribute "status", "string"
attribute 'status', 'string'
attribute 'tileMessage', 'string'
attribute 'minutes', 'string'
attribute 'VALUE_UP', 'string'
attribute 'VALUE_DOWN', 'string'
command 'levelUp' command "programOn"
command 'levelDown' command "programOff"
command 'programOn' command "on"
command 'programOff' command "off"
command 'programWait' command "z1on"
command 'programEnd' command "z1off"
command "z2on"
command "z2off"
command "z3on"
command "z3off"
command "z4on"
command "z4off"
command "z5on"
command "z5off"
command "z6on"
command "z6off"
command "z7on"
command "z7off"
command "z8on"
command "z8off"
command "z9on"
command "z9off"
command "z10on"
command "z10off"
command "z11on"
command "z11off"
command "z12on"
command "z12off"
command "z13on"
command "z13off"
command "z14on"
command "z14off"
command "z15on"
command "z15off"
command "z16on"
command "z16off"
command "offtime"
command 'on' command "refresh"
command 'off' command "rain"
command 'zon' command "manual"
command 'zoff' command "setDisplay"
command 'z1on'
command 'z1off'
command 'z2on'
command 'z2off'
command 'z3on'
command 'z3off'
command 'z4on'
command 'z4off'
command 'z5on'
command 'z5off'
command 'z6on'
command 'z6off'
command 'z7on'
command 'z7off'
command 'z8on'
command 'z8off'
command 'z9on'
command 'z9off'
command 'z10on'
command 'z10off'
command 'z11on'
command 'z11off'
command 'z12on'
command 'z12off'
command 'z13on'
command 'z13off'
command 'z14on'
command 'z14off'
command 'z15on'
command 'z15off'
command 'z16on'
command 'z16off'
command 'config' command "settingsMap"
command 'refresh' command "writeTime"
command 'rain' command "writeType"
command 'manual' command "notify"
command 'manualTime' command "updated"
command 'settingsMap'
command 'writeTime' fingerprint endpointId: "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18", profileId: "0104", deviceId: "0002", deviceVersion: "00", inClusters: "0000,0003,0004,0005,0006,000F", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZ16-01"
command 'writeType'
command 'notify'
command 'updated'
//ST release
//fingerprint endpointId: '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18', profileId: '0104', deviceId: '0002', deviceVersion: '00', inClusters: '0000,0003,0004,0005,0006,000F', outClusters: '0003, 0019', manufacturer: 'PLAID SYSTEMS', model: 'PS-SPRZ16-01'
//new release
fingerprint endpointId: "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18", profileId: "0104", deviceId: "0002", deviceVersion: "00", inClusters: "0000,0003,0004,0005,0006,0009,000A,000F", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZ16-01"
} }
@@ -117,230 +104,162 @@ metadata {
simulator { simulator {
// status messages // status messages
// reply messages // reply messages
} }
preferences { preferences {
input description: 'If you have a rain sensor wired to the rain sensor input on the Spruce controller, turn it on here.', displayDuringSetup: true, type: 'paragraph', element: 'paragraph', title: 'Rain Sensor' input description: "Press Configure button after making changes to these preferences", displayDuringSetup: true, type: "paragraph", element: "paragraph", title: ""
input description: 'The SYNC SETTINGS button must be pressed after making a change to the Rain sensor:', displayDuringSetup: false, type: 'paragraph', element: 'paragraph', title: '' input "RainEnable", "bool", title: "Rain Sensor Attached?", required: false, displayDuringSetup: true
input 'RainEnable', 'bool', title: 'Rain Sensor Attached?', required: false, displayDuringSetup: true input "ManualTime", "number", title: "Automatic shutoff time when a zone is turned on manually?", required: false, displayDuringSetup: true
input description: 'Adjust manual water time with arrows on main tile. The time indicated in the first small tile indicates the time the zone will water when manually switched on.', displayDuringSetup: false, type: 'paragraph', element: 'paragraph', title: '' }
}
// UI tile definitions // UI tile definitions
tiles { tiles {
multiAttributeTile(name:"switchall", type:"generic", width:6, height:4) { standardTile("status", "device.status") {
tileAttribute('device.status', key: 'PRIMARY_CONTROL') { state "schedule", label: 'Schedule Set', icon: "http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_t.png"
attributeState 'schedule', label: 'Ready', icon: 'http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_top.png' state "finished", label: 'Spruce Finished', icon: "st.Outdoor.outdoor5", backgroundColor: "#46c2e8"
attributeState 'finished', label: 'Finished', icon: 'st.Outdoor.outdoor5', backgroundColor: '#46c2e8' state "raintoday", label: 'Rain Today', icon: "st.custom.wuk.nt_chancerain"
attributeState 'raintoday', label: 'Rain Today', icon: 'http://www.plaidsystems.com/smartthings/st_rain.png', backgroundColor: '#d65fe3' state "rainy", label: 'Previous Rain', icon: "st.custom.wuk.nt_chancerain"
attributeState 'rainy', label: 'Rain', icon: 'http://www.plaidsystems.com/smartthings/st_rain.png', backgroundColor: '#d65fe3' state "raintom", label: 'Rain Tomorrow', icon: "st.custom.wuk.nt_chancerain"
attributeState 'raintom', label: 'Rain Tomorrow', icon: 'http://www.plaidsystems.com/smartthings/st_rain.png', backgroundColor: '#d65fe3' state "donewweek", label: 'Spruce Finished', icon: "st.Outdoor.outdoor5", backgroundColor: "#00A0DC"
attributeState 'donewweek', label: 'Finished', icon: 'st.Outdoor.outdoor5', backgroundColor: '#00A0DC' state "skipping", label: 'Skip Today', icon: "st.Outdoor.outdoor20", backgroundColor: "#36cfe3"
attributeState 'skipping', label: 'Skip', icon: 'st.Outdoor.outdoor20', backgroundColor: '#46c2e8' state "moisture", label: '', icon: "st.Weather.weather2", backgroundColor: "#36cfe3"
attributeState 'moisture', label: 'Ready', icon: 'st.Weather.weather2', backgroundColor: '#46c2e8' state "pause", label: 'PAUSE', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
attributeState 'pause', label: 'PAUSE', icon: 'st.contact.contact.open', backgroundColor: '#e86d13' state "active", label: 'Active', icon: "st.Outdoor.outdoor12", backgroundColor: "#3DC72E"
attributeState 'delayed', label: 'Delayed', icon: 'st.contact.contact.open', backgroundColor: '#e86d13' state "season", label: 'Seasonal Adjustment', icon: "st.Outdoor.outdoor17", backgroundColor: "#ffb900"
attributeState 'active', label: 'Active', icon: 'st.Outdoor.outdoor12', backgroundColor: '#3DC72E' state "disable", label: 'Disabled', icon: "st.secondary.off", backgroundColor: "#cccccc"
attributeState 'season', label: 'Adjust', icon: 'st.Outdoor.outdoor17', backgroundColor: '#ffb900' state "warning", label: '', icon: "st.categories.damageAndDanger", backgroundColor: "#ffff7f"
attributeState 'disable', label: 'Off', icon: 'st.secondary.off', backgroundColor: '#cccccc' state "alarm", label: 'Alarm', icon: "st.categories.damageAndDanger", backgroundColor: "#f9240c"
attributeState 'warning', label: 'Warning', icon: 'http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_top_yellow.png'
attributeState 'alarm', label: 'Alarm', icon: 'http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_s_red.png', backgroundColor: '#e66565'
}
tileAttribute("device.minutes", key: "VALUE_CONTROL") {
attributeState "VALUE_UP", action: "levelUp"
attributeState "VALUE_DOWN", action: "levelDown"
}
tileAttribute("device.tileMessage", key: "SECONDARY_CONTROL") {
attributeState "tileMessage", label: '${currentValue}'
}
} }
valueTile('minutes', 'device.minutes'){ standardTile("switch", "device.switch") {
state 'minutes', label: '${currentValue} min' //state "programOff", label: 'Start Program', action: "programOn", icon: "st.sonos.play-icon", backgroundColor: "#a9a9a9"
} state "off", label: 'Start Program', action: "programOn", icon: "st.sonos.play-icon", backgroundColor: "#a9a9a9"
valueTile('dummy', 'device.minutes'){ state "programOn", label: 'Initialize Program', action: "programOff", icon: "st.contact.contact.open", backgroundColor: "#f6e10e"
state 'minutes', label: '' state "on", label: 'Program Running', action: "off", icon: "st.Outdoor.outdoor12", backgroundColor: "#3DC72E"
} }
standardTile('switch', 'device.switch', width:2, height:2) { standardTile("rainsensor", "device.rainsensor") {
state 'off', label: 'Start', action: 'programOn', icon: 'st.Outdoor.outdoor12', backgroundColor: '#a9a9a9' state "rainSensrooff", label: 'Rain Sensor Clear', icon: "st.Weather.weather14", backgroundColor: "#a9a9a9"
state 'programOn', label: 'Wait', action: 'programOff', icon: 'st.contact.contact.open', backgroundColor: '#f6e10e' state "rainSensoron", label: 'Rain Detected', icon: "st.Weather.weather10", backgroundColor: "#f6e10e"
state 'programWait', label: 'Wait', action: 'programEnd', icon: 'st.contact.contact.open', backgroundColor: '#f6e10e' }
state 'on', label: 'Running', action: 'programEnd', icon: 'st.Outdoor.outdoor12', backgroundColor: '#3DC72E' standardTile("switch1", "device.switch1") {
state "z1off", label: '1', action: "z1on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z1on", label: '1', action: "z1off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
}
standardTile("switch2", "device.switch2") {
state "z2off", label: '2', action: "z2on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z2on", label: '2', action: "z2off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
} }
standardTile("rainsensor", "device.rainsensor", decoration: 'flat') { standardTile("switch3", "device.switch3", inactiveLabel: false) {
state "rainSensoroff", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_on.png' state "z3off", label: '3', action: "z3on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "rainSensoron", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_on_blue_small.png' state "z3on", label: '3', action: "z3off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
state "disable", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_x_small.png'
state "enable", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_on.png'
} }
standardTile('switch1', 'device.switch1', inactiveLabel: false) { standardTile("switch4", "device.switch4", inactiveLabel: false) {
state 'z1off', label: '1', action: 'z1on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff' state "z4off", label: '4', action: "z4on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state 'z1on', label: '1', action: 'z1off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC' state "z4on", label: '4', action: "z4off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
} }
standardTile('switch2', 'device.switch2', inactiveLabel: false) { standardTile("switch5", "device.switch5", inactiveLabel: false) {
state 'z2off', label: '2', action: 'z2on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff' state "z5off", label: '5', action: "z5on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state 'z2on', label: '2', action: 'z2off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC' state "z5on", label: '5', action: "z5off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
}
standardTile("switch6", "device.switch6", inactiveLabel: false) {
state "z6off", label: '6', action: "z6on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z6on", label: '6', action: "z6off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
}
standardTile("switch7", "device.switch7", inactiveLabel: false) {
state "z7off", label: '7', action: "z7on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z7on", label: '7', action: "z7off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
}
standardTile("switch8", "device.switch8", inactiveLabel: false) {
state "z8off", label: '8', action: "z8on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z8on", label: '8', action: "z8off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
}
standardTile("switch9", "device.switch9", inactiveLabel: false) {
state "z9off", label: '9', action: "z9on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z9on", label: '9', action: "z9off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
}
standardTile("switch10", "device.switch10", inactiveLabel: false) {
state "z10off", label: '10', action: "z10on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z10on", label: '10', action: "z10off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
} }
standardTile('switch3', 'device.switch3', inactiveLabel: false) { standardTile("switch11", "device.switch11", inactiveLabel: false) {
state 'z3off', label: '3', action: 'z3on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff' state "z11off", label: '11', action: "z11on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state 'z3on', label: '3', action: 'z3off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC' state "z11on", label: '11', action: "z11off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
} }
standardTile('switch4', 'device.switch4', inactiveLabel: false) { standardTile("switch12", "device.switch12", inactiveLabel: false) {
state 'z4off', label: '4', action: 'z4on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff' state "z12off", label: '12', action: "z12on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state 'z4on', label: '4', action: 'z4off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC' state "z12on", label: '12', action: "z12off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
} }
standardTile('switch5', 'device.switch5', inactiveLabel: false) { standardTile("switch13", "device.switch13", inactiveLabel: false) {
state 'z5off', label: '5', action: 'z5on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff' state "z13off", label: '13', action: "z13on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state 'z5on', label: '5', action: 'z5off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC' state "z13on", label: '13', action: "z13off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
} }
standardTile('switch6', 'device.switch6', inactiveLabel: false) { standardTile("switch14", "device.switch14", inactiveLabel: false) {
state 'z6off', label: '6', action: 'z6on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff' state "z14off", label: '14', action: "z14on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state 'z6on', label: '6', action: 'z6off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC' state "z14on", label: '14', action: "z14off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
} }
standardTile('switch7', 'device.switch7', inactiveLabel: false) { standardTile("switch15", "device.switch15", inactiveLabel: false) {
state 'z7off', label: '7', action: 'z7on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff' state "z15off", label: '15', action: "z15on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state 'z7on', label: '7', action: 'z7off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC' state "z15on", label: '15', action: "z15off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
}
standardTile('switch8', 'device.switch8', inactiveLabel: false) {
state 'z8off', label: '8', action: 'z8on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z8on', label: '8', action: 'z8off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch9', 'device.switch9', inactiveLabel: false) {
state 'z9off', label: '9', action: 'z9on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z9on', label: '9', action: 'z9off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch10', 'device.switch10', inactiveLabel: false) {
state 'z10off', label: '10', action: 'z10on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z10on', label: '10', action: 'z10off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch11', 'device.switch11', inactiveLabel: false) {
state 'z11off', label: '11', action: 'z11on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z11on', label: '11', action: 'z11off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch12', 'device.switch12', inactiveLabel: false) {
state 'z12off', label: '12', action: 'z12on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z12on', label: '12', action: 'z12off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch13', 'device.switch13', inactiveLabel: false) {
state 'z13off', label: '13', action: 'z13on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z13on', label: '13', action: 'z13off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch14', 'device.switch14', inactiveLabel: false) {
state 'z14off', label: '14', action: 'z14on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z14on', label: '14', action: 'z14off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch15', 'device.switch15', inactiveLabel: false) {
state 'z15off', label: '15', action: 'z15on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z15on', label: '15', action: 'z15off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
} }
standardTile('switch16', 'device.switch16', inactiveLabel: false) { standardTile("switch16", "device.switch16", inactiveLabel: false) {
state 'z16off', label: '16', action: 'z16on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff' state "z16off", label: '16', action: "z16on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state 'z16on', label: '16', action: 'z16off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC' state "z16on", label: '16', action: "z16off", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
} }
standardTile('refresh', 'device.switch', inactiveLabel: false, decoration: 'flat') { standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
state 'default', action: 'refresh', icon:'st.secondary.refresh'//-icon' state "default", action: "refresh", icon:"st.secondary.refresh"
} }
standardTile('configure', 'device.configure', inactiveLabel: false, decoration: 'flat') { standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
state 'configure', label:'', action:'configuration.configure', icon:'http://www.plaidsystems.com/smartthings/st_syncsettings.png'//sync_icon_small.png' state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
} }
main (['switchall']) main (["status"])
details(['switchall','minutes','rainsensor','switch1','switch2','switch3','switch4','switch','switch5','switch6','switch7','switch8','switch9','switch10','switch11','switch12','refresh','configure','switch13','switch14','switch15','switch16']) details(["status","rainsensor","switch","switch1","switch2","switch3","switch4","switch5","switch6","switch7","switch8","switch9","switch10","switch11","switch12","switch13","switch14","switch15","switch16","refresh","configure"])
} }
} }
//used for schedule
def programOn(){ def programOn(){
sendEvent(name: 'switch', value: 'programOn', descriptionText: 'Program turned on') sendEvent(name: "switch", value: "programOn", descriptionText: "Program turned on")
}
def programWait(){
sendEvent(name: 'switch', value: 'programWait', descriptionText: "Initializing Schedule")
}
def programEnd(){
//sets switch to off and tells schedule switch is off/schedule complete with manaual
sendEvent(name: 'switch', value: 'off', descriptionText: 'Program manually turned off')
zoff()
} }
def programOff(){ def programOff(){
sendEvent(name: 'switch', value: 'off', descriptionText: 'Program turned off') sendEvent(name: "switch", value: "off", descriptionText: "Program turned off")
off() off()
} }
//set minutes def updated(){
def levelUp(){ log.debug "updated"
def newvalue = 1
if (device.latestValue('minutes') != null) newvalue = device.latestValue('minutes').toInteger()+1
if (newvalue >= 60) newvalue = 60
def value = newvalue.toString()
log.debug value
sendEvent(name: 'minutes', value: "${value}", descriptionText: "Manual Time set to ${value}", display: false)
}
def levelDown(){
def newvalue = device.latestValue('minutes').toInteger()-1
if (newvalue <= 0) newvalue = 1
def value = newvalue.toString()
log.debug value
sendEvent(name: 'minutes', value: "${value}", descriptionText: "Manual Time set to ${value}", display: false)
} }
// Parse incoming device messages to generate events // Parse incoming device messages to generate events
def parse(String description) { def parse(String description) {
log.debug "Parse description ${description}" //log.debug "Parse description $description"
def result = null def result = null
def map = [:] def map = [:]
if (description?.startsWith('read attr -')) { if (description?.startsWith("read attr -")) {
def descMap = parseDescriptionAsMap(description) def descMap = parseDescriptionAsMap(description)
//log.debug "Desc Map: $descMap" //log.debug "Desc Map: $descMap"
//using 000F cluster instead of 0006 (switch) because ST does not differentiate between EPs and processes all as switch //using 000F cluster instead of 0006 (switch) because ST does not differentiate between EPs and processes all as switch
if (descMap.cluster == '000F' && descMap.attrId == '0055') { if (descMap.cluster == "000F" && descMap.attrId == "0055") {
log.debug 'Zone' log.debug "Zone"
map = getZone(descMap) map = getZone(descMap)
} }
else if (descMap.cluster == '0009' && descMap.attrId == '0000') { else if (descMap.cluster == "0009" && descMap.attrId == "0000") {
log.debug 'Alarm' log.debug "Alarm"
map = getAlarm(descMap) map = getAlarm(descMap)
} }
}
if (map) {
result = createEvent(map)
} }
else if (description?.startsWith('catchall: 0104 0009')){ log.debug "Parse returned $map $result"
log.debug 'Sync settings to controller complete'
if (device.latestValue('status') != 'alarm'){
def configEvt = createEvent(name: 'status', value: 'schedule', descriptionText: "Sync settings to controller complete")
def configMsg = createEvent(name: 'tileMessage', value: 'Sync settings to controller complete', descriptionText: "Sync settings to controller complete", displayed: false)
result = [configEvt, configMsg]
}
return result
}
if (map) {
result = createEvent(map)
//configure after reboot
if (map.value == 'warning' || map.value == 'alarm'){
def cmds = config()
def alarmEvt = createEvent(name: 'tileMessage', value: map.descriptionText, descriptionText: "${map.descriptionText}", displayed: false)
result = cmds?.collect { new physicalgraph.device.HubAction(it) } + createEvent(map) + alarmEvt
return result
}
else if (map.name == 'rainsensor'){
def rainEvt = createEvent(name: 'tileMessage', value: map.descriptionText, descriptionText: "${map.descriptionText}", displayed: false)
result = [createEvent(map), rainEvt]
return result
}
}
if (map) log.debug "Parse returned ${map} ${result}"
return result return result
} }
def parseDescriptionAsMap(description) { def parseDescriptionAsMap(description) {
(description - 'read attr - ').split(',').inject([:]) { map, param -> (description - "read attr - ").split(",").inject([:]) { map, param ->
def nameAndValue = param.split(':') def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()] map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
} }
} }
@@ -351,28 +270,27 @@ def getZone(descMap){
def EP = Integer.parseInt(descMap.endpoint.trim(), 16) def EP = Integer.parseInt(descMap.endpoint.trim(), 16)
String onoff String onoff
if(descMap.value == '00'){ if(descMap.value == "00"){
onoff = 'off' onoff = "off"
} }
else onoff = 'on' else onoff = "on"
if (EP == 1){ if (EP == 1){
map.name = 'switch' map.name = "switch"
map.value = onoff map.value = onoff
map.descriptionText = "${device.displayName} turned sprinkler program ${onoff}" map.descriptionText = "${device.displayName} turned sprinkler program $onoff"
} }
else if (EP == 18) { else if (EP == 18) {
map.name = 'rainsensor' map.name = "rainsensor"
log.debug "Rain enable: ${RainEnable}, sensor: ${onoff}" map.value = "rainSensor" + onoff
map.value = 'rainSensor' + onoff map.descriptionText = "${device.displayName} rain sensor is $onoff"
map.descriptionText = "${device.displayName} rain sensor is ${onoff}"
} }
else { else {
EP -= 1 EP -= 1
map.name = 'switch' + EP map.name = "switch" + EP
map.value = 'z' + EP + onoff map.value = "z" + EP + onoff
map.descriptionText = "${device.displayName} turned Zone $EP ${onoff}" map.descriptionText = "${device.displayName} turned Zone $EP $onoff"
} }
map.isStateChange = true map.isStateChange = true
@@ -382,59 +300,37 @@ def getZone(descMap){
def getAlarm(descMap){ def getAlarm(descMap){
def map = [:] def map = [:]
map.name = 'status' map.name = "status"
def alarmID = Integer.parseInt(descMap.value.trim(), 16) def alarmID = Integer.parseInt(descMap.value.trim(), 16)
log.debug "${alarmID}" log.debug "${alarmID}"
map.value = 'alarm' if(alarmID <= 0) map.descriptionText = "${device.displayName} has rebooted, no other alarms"
map.displayed = true else map.descriptionText = "${device.displayName} rebooted, reported error on zone ${alarmID - 1}, please check zone is working correctly"
map.value = "alarm"
map.isStateChange = true map.isStateChange = true
if(alarmID <= 0){ map.displayed = true
map.descriptionText = "${device.displayName} reboot, no other alarms"
map.value = 'warning'
//map.isStateChange = false
}
else map.descriptionText = "${device.displayName} reboot, reported zone ${alarmID - 1} error, please check zone is working correctly, press SYNC SETTINGS button to clear"
return map return map
} }
//status notify and change status //status notify and change status
def notify(String val, String txt){ def notify(value, text){
sendEvent(name: 'status', value: val, descriptionText: txt, isStateChange: true, display: false) sendEvent(name:"status", value:"$value", descriptionText:"$text", isStateChange: true, display: false)
//String txtShort = txt.take(100)
sendEvent(name: 'tileMessage', value: txt, descriptionText: "", isStateChange: true, display: false)
}
def updated(){
log.debug "updated"
} }
//prefrences - rain sensor, manual time //prefrences - rain sensor, manual time
def rain() { def rain() {
log.debug "Rain sensor: ${RainEnable}" log.debug "Rain $RainEnable"
if (RainEnable) sendEvent(name: 'rainsensor', value: 'enable', descriptionText: "${device.displayName} rain sensor is enabled", isStateChange: true)
else sendEvent(name: 'rainsensor', value: 'disable', descriptionText: "${device.displayName} rain sensor is disabled", isStateChange: true)
if (RainEnable) "st wattr 0x${device.deviceNetworkId} 18 0x0F 0x51 0x10 {01}" if (RainEnable) "st wattr 0x${device.deviceNetworkId} 18 0x0F 0x51 0x10 {01}"
else "st wattr 0x${device.deviceNetworkId} 18 0x0F 0x51 0x10 {00}" else "st wattr 0x${device.deviceNetworkId} 18 0x0F 0x51 0x10 {00}"
} }
def manual(){
def manualTime(value){ log.debug "Time $ManualTime"
sendEvent(name: 'minutes', value: "${value}", descriptionText: "Manual Time set to ${value}", display: false) def mTime = 10
} if (ManualTime) mTime = ManualTime
def manualTime = hex(mTime)
def manual(){ "st wattr 0x${device.deviceNetworkId} 1 6 0x4002 0x21 {00${manualTime}}"
def newManaul = 10
if (device.latestValue('minutes')) newManaul = device.latestValue('minutes').toInteger()
log.debug "Manual Zone runtime ${newManaul} mins"
def manualTime = hex(newManaul)
def sendCmds = [] }
sendCmds.push("st wattr 0x${device.deviceNetworkId} 1 6 0x4002 0x21 {00${manualTime}}")
return sendCmds
}
//write switch time settings map //write switch time settings map
def settingsMap(WriteTimes, attrType){ def settingsMap(WriteTimes, attrType){
@@ -470,20 +366,13 @@ def writeTime(wEP, runTime){
//set reporting and binding //set reporting and binding
def configure() { def configure() {
sendEvent(name: 'status', value: 'schedule', descriptionText: "Syncing settings to controller")
sendEvent(name: 'minutes', value: "10", descriptionText: "Manual Time set to 10 mins", display: false)
sendEvent(name: 'tileMessage', value: 'Syncing settings to controller', descriptionText: 'Syncing settings to controller')
config()
}
def config(){
String zigbeeId = swapEndianHex(device.hub.zigbeeId) String zigbeeId = swapEndianHex(device.hub.zigbeeId)
log.debug "Configuring Reporting and Bindings ${device.deviceNetworkId} ${device.zigbeeId}" log.debug "Confuguring Reporting and Bindings ${device.deviceNetworkId} ${device.zigbeeId}"
sendEvent(name: 'configuration',value: 100, descriptionText: "Configuration initialized")
def configCmds = [ def configCmds = [
//program on/off //program on/off
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 1000", "zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 1000",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x09 {${device.zigbeeId}} {}", "delay 1000", "zdo bind 0x${device.deviceNetworkId} 1 1 0x09 {${device.zigbeeId}} {}", "delay 1000",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0F {${device.zigbeeId}} {}", "delay 1000", "zdo bind 0x${device.deviceNetworkId} 1 1 0x0F {${device.zigbeeId}} {}", "delay 1000",
@@ -569,16 +458,38 @@ def config(){
"zcl global send-me-a-report 0x09 0x00 0x21 1 0 {00}", "delay 500", "zcl global send-me-a-report 0x09 0x00 0x21 1 0 {00}", "delay 500",
"send 0x${device.deviceNetworkId} 1 1", "delay 500" "send 0x${device.deviceNetworkId} 1 1", "delay 500"
] ]
return configCmds + rain() return configCmds + rain() + manual()
} }
private hex(value) {
new BigInteger(Math.round(value).toString()).toString(16)
}
private String swapEndianHex(String hex) {
reverseArray(hex.decodeHex()).encodeHex()
}
private byte[] reverseArray(byte[] array) {
int i = 0;
int j = array.length - 1;
byte tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
return array
}
def refresh() { def refresh() {
log.debug "refresh pressed" log.debug "refresh"
sendEvent(name: 'tileMessage', value: 'Refresh', descriptionText: 'Refresh') def refreshCmds = [
def refreshCmds = [
"st rattr 0x${device.deviceNetworkId} 1 0x0F 0x55", "delay 500", "st rattr 0x${device.deviceNetworkId} 1 0x0F 0x55", "delay 500",
"st rattr 0x${device.deviceNetworkId} 2 0x0F 0x55", "delay 500", "st rattr 0x${device.deviceNetworkId} 2 0x0F 0x55", "delay 500",
@@ -602,96 +513,64 @@ def refresh() {
"st rattr 0x${device.deviceNetworkId} 18 0x0F 0x51","delay 500", "st rattr 0x${device.deviceNetworkId} 18 0x0F 0x51","delay 500",
] ]
return refreshCmds + rain() + manual()
return refreshCmds
}
private hex(value) {
new BigInteger(Math.round(value).toString()).toString(16)
}
private String swapEndianHex(String hex) {
reverseArray(hex.decodeHex()).encodeHex()
}
private byte[] reverseArray(byte[] array) {
int i = 0;
int j = array.length - 1;
byte tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
return array
}
//on & off redefined for Alexa to start manual schedule
def on() {
log.debug 'Alexa on'
//schedule subscribes to programOn
sendEvent(name: 'switch', value: 'programOn', descriptionText: 'Alexa turned program on')
}
def off() {
log.debug 'Alexa off'
sendEvent(name: 'switch', value: 'off', descriptionText: 'Alexa turned program off')
zoff()
} }
// Commands to device // Commands to device
//zones on - 8 //zones on - 8
def zon() { def on() {
"st cmd 0x${device.deviceNetworkId} 1 6 1 {}" //sendEvent(name:"status", value:"active", descriptionText:"Program Running", isStateChange: true, display: false)
log.debug "on"
"st cmd 0x${device.deviceNetworkId} 1 6 1 {}"
} }
def zoff() { def off() {
"st cmd 0x${device.deviceNetworkId} 1 6 0 {}" log.debug "off"
"st cmd 0x${device.deviceNetworkId} 1 6 0 {}"
} }
def z1on() { def z1on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 2 6 1 {}" "st cmd 0x${device.deviceNetworkId} 2 6 1 {}"
} }
def z1off() { def z1off() {
"st cmd 0x${device.deviceNetworkId} 2 6 0 {}" "st cmd 0x${device.deviceNetworkId} 2 6 0 {}"
} }
def z2on() { def z2on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 3 6 1 {}" "st cmd 0x${device.deviceNetworkId} 3 6 1 {}"
} }
def z2off() { def z2off() {
"st cmd 0x${device.deviceNetworkId} 3 6 0 {}" "st cmd 0x${device.deviceNetworkId} 3 6 0 {}"
} }
def z3on() { def z3on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 4 6 1 {}" "st cmd 0x${device.deviceNetworkId} 4 6 1 {}"
} }
def z3off() { def z3off() {
"st cmd 0x${device.deviceNetworkId} 4 6 0 {}" "st cmd 0x${device.deviceNetworkId} 4 6 0 {}"
} }
def z4on() { def z4on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 5 6 1 {}" "st cmd 0x${device.deviceNetworkId} 5 6 1 {}"
} }
def z4off() { def z4off() {
"st cmd 0x${device.deviceNetworkId} 5 6 0 {}" "st cmd 0x${device.deviceNetworkId} 5 6 0 {}"
} }
def z5on() { def z5on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 6 6 1 {}" "st cmd 0x${device.deviceNetworkId} 6 6 1 {}"
} }
def z5off() { def z5off() {
"st cmd 0x${device.deviceNetworkId} 6 6 0 {}" "st cmd 0x${device.deviceNetworkId} 6 6 0 {}"
} }
def z6on() { def z6on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 7 6 1 {}" "st cmd 0x${device.deviceNetworkId} 7 6 1 {}"
} }
def z6off() { def z6off() {
"st cmd 0x${device.deviceNetworkId} 7 6 0 {}" "st cmd 0x${device.deviceNetworkId} 7 6 0 {}"
} }
def z7on() { def z7on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 8 6 1 {}" "st cmd 0x${device.deviceNetworkId} 8 6 1 {}"
} }
def z7off() { def z7off() {
"st cmd 0x${device.deviceNetworkId} 8 6 0 {}" "st cmd 0x${device.deviceNetworkId} 8 6 0 {}"
} }
def z8on() { def z8on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 9 6 1 {}" "st cmd 0x${device.deviceNetworkId} 9 6 1 {}"
} }
def z8off() { def z8off() {
"st cmd 0x${device.deviceNetworkId} 9 6 0 {}" "st cmd 0x${device.deviceNetworkId} 9 6 0 {}"
@@ -699,51 +578,50 @@ def z8off() {
//zones 9 - 16 //zones 9 - 16
def z9on() { def z9on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 10 6 1 {}" "st cmd 0x${device.deviceNetworkId} 10 6 1 {}"
} }
def z9off() { def z9off() {
"st cmd 0x${device.deviceNetworkId} 10 6 0 {}" "st cmd 0x${device.deviceNetworkId} 10 6 0 {}"
} }
def z10on() { def z10on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 11 6 1 {}" "st cmd 0x${device.deviceNetworkId} 11 6 1 {}"
} }
def z10off() { def z10off() {
"st cmd 0x${device.deviceNetworkId} 11 6 0 {}" "st cmd 0x${device.deviceNetworkId} 11 6 0 {}"
} }
def z11on() { def z11on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 12 6 1 {}" "st cmd 0x${device.deviceNetworkId} 12 6 1 {}"
} }
def z11off() { def z11off() {
"st cmd 0x${device.deviceNetworkId} 12 6 0 {}" "st cmd 0x${device.deviceNetworkId} 12 6 0 {}"
} }
def z12on() { def z12on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 13 6 1 {}" "st cmd 0x${device.deviceNetworkId} 13 6 1 {}"
} }
def z12off() { def z12off() {
"st cmd 0x${device.deviceNetworkId} 13 6 0 {}" "st cmd 0x${device.deviceNetworkId} 13 6 0 {}"
} }
def z13on() { def z13on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 14 6 1 {}" "st cmd 0x${device.deviceNetworkId} 14 6 1 {}"
} }
def z13off() { def z13off() {
"st cmd 0x${device.deviceNetworkId} 14 6 0 {}" "st cmd 0x${device.deviceNetworkId} 14 6 0 {}"
} }
def z14on() { def z14on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 15 6 1 {}" "st cmd 0x${device.deviceNetworkId} 15 6 1 {}"
} }
def z14off() { def z14off() {
"st cmd 0x${device.deviceNetworkId} 15 6 0 {}" "st cmd 0x${device.deviceNetworkId} 15 6 0 {}"
} }
def z15on() { def z15on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 16 6 1 {}" "st cmd 0x${device.deviceNetworkId} 16 6 1 {}"
} }
def z15off() { def z15off() {
"st cmd 0x${device.deviceNetworkId} 16 6 0 {}" "st cmd 0x${device.deviceNetworkId} 16 6 0 {}"
} }
def z16on() { def z16on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 17 6 1 {}" "st cmd 0x${device.deviceNetworkId} 17 6 1 {}"
} }
def z16off() { def z16off() {
"st cmd 0x${device.deviceNetworkId} 17 6 0 {}" "st cmd 0x${device.deviceNetworkId} 17 6 0 {}"
} }

View File

@@ -22,7 +22,7 @@ metadata
{ {
standardTile("mainTile", "device.status", width: 1, height: 1, icon: "st.Entertainment.entertainment11") standardTile("mainTile", "device.status", width: 1, height: 1, icon: "st.Entertainment.entertainment11")
{ {
state "default", label: "Simple Sync", icon: "st.Home.home2", backgroundColor: "#00a0dc" state "default", label: "Simple Sync", icon: "st.Home.home2", backgroundColor: "#55A7FF"
} }
def detailTiles = ["mainTile"] def detailTiles = ["mainTile"]

View File

@@ -82,8 +82,8 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){ multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") { tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC" attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc" attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
} }
} }
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) { valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,43 +0,0 @@
# Aeon Multisensor Gen5
Cloud Execution
Works with:
* [Aeon Labs MultiSensor (Gen 5)](https://www.smartthings.com/works-with-smartthings/sensors/aeon-labs-multisensor-gen-5)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Motion Sensor** - can detect motion
* **Temperature Measurement** - defines device measures current temperature
* **Relative Humidity Measurement** - allow reading the relative humidity from devices that support it
* **Illuminance Measurement** - gives the illuminance reading from devices that support it
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Sensor** - detects sensor events
* **Battery** - defines device uses a battery
* **Health Check** - indicates ability to get device health notifications
## Device Health
Aeon Labs MultiSensor (Gen 5) is polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __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:
* [Aeon Labs MultiSensor (Gen 5) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206157226-Aeon-Labs-MultiSensor-Gen-5-)

View File

@@ -20,12 +20,10 @@ metadata {
capability "Configuration" capability "Configuration"
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Health Check"
command "configureAfterSecure" command "configureAfterSecure"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A" fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A"
fingerprint mfr:"0086", prod:"0102", model:"004A", deviceJoinName: "Aeon Labs MultiSensor (Gen 5)"
} }
simulator { simulator {
@@ -66,8 +64,8 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){ multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") { tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00a0dc" attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc" attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
} }
} }
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) { valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
@@ -100,11 +98,6 @@ metadata {
} }
} }
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])
}
def parse(String description) def parse(String description)
{ {
def result = null def result = null
@@ -251,13 +244,6 @@ def configureAfterSecure() {
secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
secure(zwave.batteryV1.batteryGet())
}
def configure() { def configure() {
// log.debug "configure()" // log.debug "configure()"
//["delay 30000"] + secure(zwave.securityV1.securityCommandsSupportedGet()) //["delay 30000"] + secure(zwave.securityV1.securityCommandsSupportedGet())

View File

@@ -59,8 +59,8 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){ multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") { tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00a0dc" attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc" attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
} }
} }
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) { valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {

View File

@@ -53,7 +53,7 @@ metadata {
// tile definitions // tile definitions
tiles { tiles {
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.on", backgroundColor: "#00A0DC" state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
} }
valueTile("power", "device.power", decoration: "flat") { valueTile("power", "device.power", decoration: "flat") {

View File

@@ -42,8 +42,8 @@ metadata {
tiles { tiles {
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) { standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#00a0dc" state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff" state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ebeef2"
} }
standardTile("beep", "device.beep", decoration: "flat") { standardTile("beep", "device.beep", decoration: "flat") {
state "beep", label:'', action:"tone.beep", icon:"st.secondary.beep", backgroundColor:"#ffffff" state "beep", label:'', action:"tone.beep", icon:"st.secondary.beep", backgroundColor:"#ffffff"

View File

@@ -28,8 +28,6 @@ metadata {
capability "Refresh" capability "Refresh"
capability "Music Player" capability "Music Player"
capability "Health Check" capability "Health Check"
capability "Sensor"
capability "Actuator"
/** /**
* Define all commands, ie, if you have a custom action not * Define all commands, ie, if you have a custom action not
@@ -69,10 +67,10 @@ metadata {
} }
standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) { standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
state "on", label: '${name}', action: "forceOff", icon: "st.Electronics.electronics16", backgroundColor: "#00a0dc", nextState:"turningOff" state "on", label: '${name}', action: "forceOff", icon: "st.Electronics.electronics16", backgroundColor: "#79b821", nextState:"turningOff"
state "turningOff", label:'TURNING OFF', icon:"st.Electronics.electronics16", backgroundColor:"#ffffff" state "turningOff", label:'TURNING OFF', icon:"st.Electronics.electronics16", backgroundColor:"#ffffff"
state "off", label: '${name}', action: "forceOn", icon: "st.Electronics.electronics16", backgroundColor: "#ffffff", nextState:"turningOn" state "off", label: '${name}', action: "forceOn", icon: "st.Electronics.electronics16", backgroundColor: "#ffffff", nextState:"turningOn"
state "turningOn", label:'TURNING ON', icon:"st.Electronics.electronics16", backgroundColor:"#00a0dc" state "turningOn", label:'TURNING ON', icon:"st.Electronics.electronics16", backgroundColor:"#79b821"
} }
valueTile("1", "device.station1", decoration: "flat", canChangeIcon: false) { valueTile("1", "device.station1", decoration: "flat", canChangeIcon: false) {
state "station1", label:'${currentValue}', action:"preset1" state "station1", label:'${currentValue}', action:"preset1"

View File

@@ -81,13 +81,13 @@ metadata {
state "fanCirculate", label:'${name}', action:"switchFanMode" state "fanCirculate", label:'${name}', action:"switchFanMode"
} }
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) { controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
state "setHeatingSetpoint", action:"quickSetHeat", backgroundColor:"#e86d13" state "setHeatingSetpoint", action:"quickSetHeat", backgroundColor:"#d04e00"
} }
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false, decoration: "flat") { valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false, decoration: "flat") {
state "heat", label:'${currentValue}° heat', backgroundColor:"#ffffff" state "heat", label:'${currentValue}° heat', backgroundColor:"#ffffff"
} }
controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) { controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
state "setCoolingSetpoint", action:"quickSetCool", backgroundColor: "#00a0dc" state "setCoolingSetpoint", action:"quickSetCool", backgroundColor: "#1e9cbb"
} }
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") { valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
state "cool", label:'${currentValue}° cool', backgroundColor:"#ffffff" state "cool", label:'${currentValue}° cool', backgroundColor:"#ffffff"

View File

@@ -12,7 +12,7 @@
* *
*/ */
metadata { metadata {
definition (name: "Dimmer Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "Dimmer Switch", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level" capability "Switch Level"
capability "Actuator" capability "Actuator"
capability "Indicator" capability "Indicator"

View File

@@ -32,7 +32,7 @@ metadata {
command "switchMode" command "switchMode"
command "switchFanMode" command "switchFanMode"
attribute "displayThermostatSetpoint", "string" // Added to be able to show "Auto"/"Off" keeping attribute thermostatSetpoint a number attribute "thermostatSetpoint", "number"
attribute "thermostatStatus", "string" attribute "thermostatStatus", "string"
attribute "maxHeatingSetpoint", "number" attribute "maxHeatingSetpoint", "number"
attribute "minHeatingSetpoint", "number" attribute "minHeatingSetpoint", "number"
@@ -43,8 +43,8 @@ metadata {
} }
tiles { tiles {
standardTile("temperature", "device.temperature", width: 2, height: 2, decoration: "flat") { valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label:'${currentValue}°', unit:"F", icon: "st.thermostat.ac.air-conditioning", state("temperature", label:'${currentValue}°', unit:"F",
backgroundColors:[ backgroundColors:[
// Celsius // Celsius
[value: 0, color: "#153591"], [value: 0, color: "#153591"],
@@ -70,7 +70,7 @@ metadata {
state "heat", action:"switchMode", nextState: "updating", icon: "st.thermostat.heat" state "heat", action:"switchMode", nextState: "updating", icon: "st.thermostat.heat"
state "cool", action:"switchMode", nextState: "updating", icon: "st.thermostat.cool" state "cool", action:"switchMode", nextState: "updating", icon: "st.thermostat.cool"
state "auto", action:"switchMode", nextState: "updating", icon: "st.thermostat.auto" state "auto", action:"switchMode", nextState: "updating", icon: "st.thermostat.auto"
state "emergency heat", action:"switchMode", icon: "st.thermostat.emergency-heat" // emergency heat = auxHeatOnly state "auxHeatOnly", action:"switchMode", icon: "st.thermostat.emergency-heat"
state "updating", label:"Working", icon: "st.secondary.secondary" state "updating", label:"Working", icon: "st.secondary.secondary"
} }
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") { standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
@@ -81,8 +81,8 @@ metadata {
standardTile("upButtonControl", "device.thermostatSetpoint", inactiveLabel: false, decoration: "flat") { standardTile("upButtonControl", "device.thermostatSetpoint", inactiveLabel: false, decoration: "flat") {
state "setpoint", action:"raiseSetpoint", icon:"st.thermostat.thermostat-up" state "setpoint", action:"raiseSetpoint", icon:"st.thermostat.thermostat-up"
} }
valueTile("displayThermostatSetpoint", "device.displayThermostatSetpoint", width: 1, height: 1, decoration: "flat") { valueTile("thermostatSetpoint", "device.thermostatSetpoint", width: 1, height: 1, decoration: "flat") {
state "displayThermostatSetpoint", label:'${currentValue}' state "thermostatSetpoint", label:'${currentValue}'
} }
valueTile("currentStatus", "device.thermostatStatus", height: 1, width: 2, decoration: "flat") { valueTile("currentStatus", "device.thermostatStatus", height: 1, width: 2, decoration: "flat") {
state "thermostatStatus", label:'${currentValue}', backgroundColor:"#ffffff" state "thermostatStatus", label:'${currentValue}', backgroundColor:"#ffffff"
@@ -113,7 +113,7 @@ metadata {
state "humidity", label:'${currentValue}%' state "humidity", label:'${currentValue}%'
} }
main "temperature" main "temperature"
details(["temperature", "upButtonControl", "displayThermostatSetpoint", "currentStatus", "downButtonControl", "mode", "fanMode","humidity", "resumeProgram", "refresh"]) details(["temperature", "upButtonControl", "thermostatSetpoint", "currentStatus", "downButtonControl", "mode", "fanMode","humidity", "resumeProgram", "refresh"])
} }
preferences { preferences {
@@ -185,11 +185,6 @@ def generateEvent(Map results) {
isChange = isStateChange(device, name, value.toString()) isChange = isStateChange(device, name, value.toString())
event['isStateChange'] = isChange event['isStateChange'] = isChange
event['displayed'] = false event['displayed'] = false
} else if (name == "thermostatMode") {
def mode = value.toString()
mode = (mode == "auxHeatOnly") ? "emergency heat" : mode
isChange = isStateChange(device, name, mode)
event << [value: mode, isStateChange: isChange, displayed: isDisplayed]
} else { } else {
isChange = isStateChange(device, name, value.toString()) isChange = isStateChange(device, name, value.toString())
isDisplayed = isChange isDisplayed = isChange
@@ -457,10 +452,10 @@ def emergencyHeat() {
} }
def auxHeatOnly() { def auxHeatOnly() {
log.debug "auxHeatOnly = emergency heat" log.debug "auxHeatOnly"
def deviceId = device.deviceNetworkId.split(/\./).last() def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("auxHeatOnly", deviceId)) if (parent.setMode ("auxHeatOnly", deviceId))
generateModeEvent("emergency heat") // emergency heat = auxHeatOnly generateModeEvent("auxHeatOnly")
else { else {
log.debug "Error setting new mode." log.debug "Error setting new mode."
def currentMode = device.currentState("thermostatMode")?.value def currentMode = device.currentState("thermostatMode")?.value
@@ -579,23 +574,17 @@ def generateSetpointEvent() {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale) sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale) sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
def averageSetpoint = roundC((heatingSetpoint + coolingSetpoint) / 2)
if (mode == "heat") { if (mode == "heat") {
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale) sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"displayThermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale, displayed: false)
} }
else if (mode == "cool") { else if (mode == "cool") {
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale) sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"displayThermostatSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale, displayed: false)
} else if (mode == "auto") { } else if (mode == "auto") {
sendEvent("name":"thermostatSetpoint", "value":averageSetpoint, "unit":location.temperatureScale) sendEvent("name":"thermostatSetpoint", "value":"Auto")
sendEvent("name":"displayThermostatSetpoint", "value":"Auto", displayed: false)
} else if (mode == "off") { } else if (mode == "off") {
sendEvent("name":"thermostatSetpoint", "value":averageSetpoint, "unit":location.temperatureScale) sendEvent("name":"thermostatSetpoint", "value":"Off")
sendEvent("name":"displayThermostatSetpoint", "value":"Off", displayed: false) } else if (mode == "auxHeatOnly") {
} else if (mode == "emergency heat") { // emergency heat = auxHeatOnly
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale) sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"displayThermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale, displayed: false)
} }
} }
@@ -632,14 +621,13 @@ void raiseSetpoint() {
targetvalue = thermostatSetpoint ? thermostatSetpoint : 0 targetvalue = thermostatSetpoint ? thermostatSetpoint : 0
targetvalue = location.temperatureScale == "F"? targetvalue + 1 : targetvalue + 0.5 targetvalue = location.temperatureScale == "F"? targetvalue + 1 : targetvalue + 0.5
if ((mode == "heat" || mode == "emergency heat") && targetvalue > maxHeatingSetpoint) { // emergency heat = auxHeatOnly if ((mode == "heat" || mode == "auxHeatOnly") && targetvalue > maxHeatingSetpoint) {
targetvalue = maxHeatingSetpoint targetvalue = maxHeatingSetpoint
} else if (mode == "cool" && targetvalue > maxCoolingSetpoint) { } else if (mode == "cool" && targetvalue > maxCoolingSetpoint) {
targetvalue = maxCoolingSetpoint targetvalue = maxCoolingSetpoint
} }
sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false) sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"displayThermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
log.info "In mode $mode raiseSetpoint() to $targetvalue" log.info "In mode $mode raiseSetpoint() to $targetvalue"
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
@@ -678,14 +666,13 @@ void lowerSetpoint() {
targetvalue = thermostatSetpoint ? thermostatSetpoint : 0 targetvalue = thermostatSetpoint ? thermostatSetpoint : 0
targetvalue = location.temperatureScale == "F"? targetvalue - 1 : targetvalue - 0.5 targetvalue = location.temperatureScale == "F"? targetvalue - 1 : targetvalue - 0.5
if ((mode == "heat" || mode == "emergency heat") && targetvalue < minHeatingSetpoint) { // emergency heat = auxHeatOnly if ((mode == "heat" || mode == "auxHeatOnly") && targetvalue < minHeatingSetpoint) {
targetvalue = minHeatingSetpoint targetvalue = minHeatingSetpoint
} else if (mode == "cool" && targetvalue < minCoolingSetpoint) { } else if (mode == "cool" && targetvalue < minCoolingSetpoint) {
targetvalue = minCoolingSetpoint targetvalue = minCoolingSetpoint
} }
sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false) sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"displayThermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
log.info "In mode $mode lowerSetpoint() to $targetvalue" log.info "In mode $mode lowerSetpoint() to $targetvalue"
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
@@ -719,7 +706,7 @@ void alterSetpoint(temp) {
} }
//step1: check thermostatMode, enforce limits before sending request to cloud //step1: check thermostatMode, enforce limits before sending request to cloud
if (mode == "heat" || mode == "emergency heat"){ // emergency heat = auxHeatOnly if (mode == "heat" || mode == "auxHeatOnly"){
if (temp.value > coolingSetpoint){ if (temp.value > coolingSetpoint){
targetHeatingSetpoint = temp.value targetHeatingSetpoint = temp.value
targetCoolingSetpoint = temp.value targetCoolingSetpoint = temp.value
@@ -748,18 +735,15 @@ void alterSetpoint(temp) {
if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) { if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name": "thermostatSetpoint", "value": temp.value, displayed: false) sendEvent("name": "thermostatSetpoint", "value": temp.value, displayed: false)
sendEvent("name": "displayThermostatSetpoint", "value": temp.value, displayed: false)
sendEvent("name": "heatingSetpoint", "value": targetHeatingSetpoint, "unit": location.temperatureScale) sendEvent("name": "heatingSetpoint", "value": targetHeatingSetpoint, "unit": location.temperatureScale)
sendEvent("name": "coolingSetpoint", "value": targetCoolingSetpoint, "unit": location.temperatureScale) sendEvent("name": "coolingSetpoint", "value": targetCoolingSetpoint, "unit": location.temperatureScale)
log.debug "alterSetpoint in mode $mode succeed change setpoint to= ${temp.value}" log.debug "alterSetpoint in mode $mode succeed change setpoint to= ${temp.value}"
} else { } else {
log.error "Error alterSetpoint()" log.error "Error alterSetpoint()"
if (mode == "heat" || mode == "emergency heat"){ // emergency heat = auxHeatOnly if (mode == "heat" || mode == "auxHeatOnly"){
sendEvent("name": "thermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false) sendEvent("name": "thermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
sendEvent("name": "displayThermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
} else if (mode == "cool") { } else if (mode == "cool") {
sendEvent("name": "thermostatSetpoint", "value": coolingSetpoint.toString(), displayed: false) sendEvent("name": "thermostatSetpoint", "value": coolingSetpoint.toString(), displayed: false)
sendEvent("name": "displayThermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
} }
} }
@@ -775,7 +759,6 @@ def generateStatusEvent() {
def coolingSetpoint = device.currentValue("coolingSetpoint") def coolingSetpoint = device.currentValue("coolingSetpoint")
def temperature = device.currentValue("temperature") def temperature = device.currentValue("temperature")
def statusText def statusText
def operatingState = "idle"
log.debug "Generate Status Event for Mode = ${mode}" log.debug "Generate Status Event for Mode = ${mode}"
log.debug "Temperature = ${temperature}" log.debug "Temperature = ${temperature}"
@@ -784,29 +767,20 @@ def generateStatusEvent() {
log.debug "HVAC Mode = ${mode}" log.debug "HVAC Mode = ${mode}"
if (mode == "heat") { if (mode == "heat") {
if (temperature >= heatingSetpoint) { if (temperature >= heatingSetpoint)
statusText = "Right Now: Idle" statusText = "Right Now: Idle"
} else { else
statusText = "Heating to ${heatingSetpoint} ${location.temperatureScale}" statusText = "Heating to ${heatingSetpoint} ${location.temperatureScale}"
operatingState = "heating"
}
} else if (mode == "cool") { } else if (mode == "cool") {
if (temperature <= coolingSetpoint) { if (temperature <= coolingSetpoint)
statusText = "Right Now: Idle" statusText = "Right Now: Idle"
} else { else
statusText = "Cooling to ${coolingSetpoint} ${location.temperatureScale}" statusText = "Cooling to ${coolingSetpoint} ${location.temperatureScale}"
operatingState = "cooling"
}
} else if (mode == "auto") { } else if (mode == "auto") {
statusText = "Right Now: Auto" statusText = "Right Now: Auto"
if (temperature < heatingSetpoint) {
operatingState = "heating"
} else if (temperature > coolingSetpoint) {
operatingState = "cooling"
}
} else if (mode == "off") { } else if (mode == "off") {
statusText = "Right Now: Off" statusText = "Right Now: Off"
} else if (mode == "emergency heat") { // emergency heat = auxHeatOnly } else if (mode == "auxHeatOnly") {
statusText = "Emergency Heat" statusText = "Emergency Heat"
} else { } else {
statusText = "?" statusText = "?"
@@ -814,7 +788,6 @@ def generateStatusEvent() {
log.debug "Generate Status Event = ${statusText}" log.debug "Generate Status Event = ${statusText}"
sendEvent("name":"thermostatStatus", "value":statusText, "description":statusText, displayed: true) sendEvent("name":"thermostatStatus", "value":statusText, "description":statusText, displayed: true)
sendEvent("name":"thermostatOperatingState", "value":operatingState, "description":operatingState, displayed: false)
} }
def generateActivityFeedsEvent(notificationMessage) { def generateActivityFeedsEvent(notificationMessage) {

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,43 +0,0 @@
# EcoNet Vent
Cloud Execution
Works with:
* [EcoNet Controls Z-Wave Vent](https://www.smartthings.com/works-with-smartthings/econet-controls/econet-controls-z-wave-vent)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Switch Level** - allows for the control of the level attribute of a light
* **Actuator** - represents that a Device has commands
* **Switch** - allows for the control of a switch device
* **Battery** - defines that the device has a battery
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
* **Polling** - allows for the polling of devices that support it
* **Configuration** - allow configuration of devices that support it
* **Health Check** - indicates ability to get device health notifications
## Device Health
EcoNet Controls Z-Wave Vent is polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __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:
* [EcoNet Controls Z-Wave Vent Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204556420-EcoNet-EV100-Vent)

View File

@@ -26,13 +26,11 @@ metadata {
capability "Sensor" capability "Sensor"
capability "Polling" capability "Polling"
capability "Configuration" capability "Configuration"
// capability "Health Check"
command "open" command "open"
command "close" command "close"
fingerprint deviceId: "0x1100", inClusters: "0x26,0x72,0x86,0x77,0x80,0x20" fingerprint deviceId: "0x1100", inClusters: "0x26,0x72,0x86,0x77,0x80,0x20"
// fingerprint mfr:"0157", prod:"0100", model:"0100", deviceJoinName: "EcoNet Controls Z-Wave Vent"
} }
simulator { simulator {
@@ -55,7 +53,7 @@ metadata {
tiles { tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", action:"switch.off", icon:"st.vents.vent-open-text", backgroundColor:"#00a0dc" state "on", action:"switch.off", icon:"st.vents.vent-open-text", backgroundColor:"#53a7c0"
state "off", action:"switch.on", icon:"st.vents.vent-closed", backgroundColor:"#ffffff" state "off", action:"switch.on", icon:"st.vents.vent-closed", backgroundColor:"#ffffff"
} }
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") { valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
@@ -87,8 +85,6 @@ def parse(String description) {
//send the command to stop polling //send the command to stop polling
def updated() { 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("poll stop") response("poll stop")
} }
@@ -173,13 +169,6 @@ def setLevel(value, duration) {
setLevel(value) setLevel(value)
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() { def refresh() {
delayBetween([ delayBetween([
zwave.switchMultilevelV1.switchMultilevelGet().format(), zwave.switchMultilevelV1.switchMultilevelGet().format(),

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,40 +0,0 @@
# Everspring Flood Sensor
Cloud Execution
Works with:
* [Everspring Water Detector](https://www.smartthings.com/works-with-smartthings/sensors/everspring-water-detector)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Water Sensor** - can detect presence of water (dry or wet)
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Sensor** - detects sensor events
* **Battery** - defines device uses a battery
* **Health Check** - indicates ability to get device health notifications
## Device Health
Everspring Water Detector is a Z-wave sleepy device and wakes up every 4 hours.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*4*60 + 2)mins = 482 mins.
* __482min__ checkInterval
## Battery Specification
Three AA 1.5V batteries are required.
## 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:
* [Everspring Water Detector Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202088304-Everspring-Water-Detector)

View File

@@ -17,7 +17,6 @@ metadata {
capability "Configuration" capability "Configuration"
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Health Check"
fingerprint deviceId: "0xA102", inClusters: "0x86,0x72,0x85,0x84,0x80,0x70,0x9C,0x20,0x71" fingerprint deviceId: "0xA102", inClusters: "0x86,0x72,0x85,0x84,0x80,0x70,0x9C,0x20,0x71"
} }
@@ -139,8 +138,6 @@ def zwaveEvent(physicalgraph.zwave.Command cmd)
def configure() def configure()
{ {
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
if (!device.currentState("battery")) { if (!device.currentState("battery")) {
sendEvent(name: "battery", value:100, unit:"%", descriptionText:"(Default battery event)", displayed:false) sendEvent(name: "battery", value:100, unit:"%", descriptionText:"(Default battery event)", displayed:false)
} }

View File

@@ -56,9 +56,9 @@ metadata {
tiles { tiles {
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.on", backgroundColor:"#00a0dc", nextState:"turningOff" state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn" state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc", nextState:"turningOff" state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn" state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
} }
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") { standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,40 +0,0 @@
# Fibaro Door Window Sensor
Cloud Execution
Works with:
* [Fibaro Door/Window Sensor](https://www.smartthings.com/works-with-smartthings/sensors/fibaro-doorwindow-sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Contact Sensor** - can detect contact (possible values: open,closed)
* **Sensor** - detects sensor events
* **Battery** - defines device uses a battery
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Health Check** - indicates ability to get device health notifications
## Device Health
Fibaro Door/Window Sensor is a Z-wave sleepy device and wakes up every 4 hours.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*4*60 + 2)mins = 482 mins.
* __482min__ checkInterval
## Battery Specification
One 1/2AA 3.6V battery is required.
## 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:
* [Fibaro Door/Window Sensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204075194-Fibaro-Door-Window-Sensor)

View File

@@ -39,8 +39,7 @@
capability "Contact Sensor" capability "Contact Sensor"
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Configuration" capability "Configuration"
capability "Health Check"
command "resetParams2StDefaults" command "resetParams2StDefaults"
command "listCurrentParams" command "listCurrentParams"
@@ -267,9 +266,6 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
*/ */
def configure() { def configure() {
log.debug "Configuring Device..." log.debug "Configuring Device..."
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
def cmds = [] def cmds = []
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format()
// send associate to group 3 to get sensor data reported only to hub // send associate to group 3 to get sensor data reported only to hub

View File

@@ -77,7 +77,7 @@ metadata {
tiles { tiles {
standardTile("water", "device.water", width: 2, height: 2) { standardTile("water", "device.water", width: 2, height: 2) {
state "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff" state "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
state "wet", icon:"st.alarm.water.wet", backgroundColor:"#00a0dc" state "wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
} }
valueTile("temperature", "device.temperature", inactiveLabel: false) { valueTile("temperature", "device.temperature", inactiveLabel: false) {
state "temperature", label:'${currentValue}°', state "temperature", label:'${currentValue}°',
@@ -93,7 +93,7 @@ metadata {
} }
standardTile("tamper", "device.tamper") { standardTile("tamper", "device.tamper") {
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:""

View File

@@ -82,8 +82,8 @@
tiles { tiles {
standardTile("motion", "device.motion", width: 2, height: 2) { standardTile("motion", "device.motion", width: 2, height: 2) {
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", inactiveLabel: false) { valueTile("temperature", "device.temperature", inactiveLabel: false) {
state "temperature", label:'${currentValue}°', state "temperature", label:'${currentValue}°',

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,39 +0,0 @@
# FortrezZ Water Valve
Cloud Execution
Works with:
* [FortrezZ Water Valve](https://www.smartthings.com/works-with-smartthings/other/fortrezz-water-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
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
## Device Health
FortrezZ Water Valve is polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __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:
* [FortrezZ Water Valve Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202088434-FortrezZ-Water-Valve-Shutoff)

View File

@@ -14,13 +14,11 @@
metadata { metadata {
definition (name: "Fortrezz Water Valve", namespace: "smartthings", author: "SmartThings") { definition (name: "Fortrezz Water Valve", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Health Check"
capability "Valve" capability "Valve"
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70" fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70"
fingerprint mfr:"0084", prod:"0213", model:"0215", deviceJoinName: "FortrezZ Water Valve"
} }
// simulator metadata // simulator metadata
@@ -50,11 +48,6 @@ metadata {
} }
} }
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])
}
def parse(String description) { def parse(String description) {
log.trace description log.trace description
def result = null def result = null
@@ -83,13 +76,6 @@ def close() {
zwave.switchBinaryV1.switchBinarySet(switchValue: 0xFF).format() zwave.switchBinaryV1.switchBinarySet(switchValue: 0xFF).format()
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() { def refresh() {
zwave.switchBinaryV1.switchBinaryGet().format() zwave.switchBinaryV1.switchBinaryGet().format()
} }

View File

@@ -42,8 +42,8 @@ metadata {
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("battery", "device.battery", decoration: "flat", inactiveLabel: false) { valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) {

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,35 +0,0 @@
# Plant Link
Cloud Execution
Works with:
* [OSO Technologies PlantLink Soil Moisture Sensor](https://www.smartthings.com/works-with-smartthings/oso-technologies/oso-technologies-plantlink-soil-moisture-sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Relative Humidity Measurement** - allows reading the relative humidity from devices that support it
* **Sensor** - detects sensor events
* **Battery** - defines device uses a battery
* **Health Check** - indicates ability to get device health notifications
## Device Health
Plant Link sensor is a Z-wave sleepy device and checks in every 15 minutes.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the different motion sensors from SmartThings can be found in the following links
for the different models:
* [OSO Technologies PlantLink Soil Moisture Sensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206868986-PlantLink-Soil-Moisture-Sensor)

View File

@@ -21,10 +21,8 @@ metadata {
capability "Relative Humidity Measurement" capability "Relative Humidity Measurement"
capability "Battery" capability "Battery"
capability "Sensor" capability "Sensor"
capability "Health Check"
fingerprint profileId: "0104", inClusters: "0000,0003,0405,FC08", outClusters: "0003" fingerprint profileId: "0104", inClusters: "0000,0003,0405,FC08", outClusters: "0003"
fingerprint endpoint: "1", profileId: "0104", inClusters: "0000,0001,0003,0B04", outClusters: "0003", manufacturer: "", model: "", deviceJoinName: "OSO Technologies PlantLink Soil Moisture Sensor"
} }
tiles { tiles {
@@ -50,11 +48,6 @@ metadata {
} }
} }
def updated() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
// Parse incoming device messages to generate events // Parse incoming device messages to generate events
def parse(String description) { def parse(String description) {
log.debug "Parse description $description" log.debug "Parse description $description"

View File

@@ -16,7 +16,7 @@
* Date: 2013-03-05 * Date: 2013-03-05
*/ */
metadata { metadata {
definition (name: "SmartAlert Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.smokedetector") { definition (name: "SmartAlert Siren", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Switch" capability "Switch"
capability "Sensor" capability "Sensor"

View File

@@ -16,7 +16,7 @@
* Date: 2013-12-04 * Date: 2013-12-04
*/ */
metadata { metadata {
definition (name: "SmartPower Dimming Outlet", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.smartplug") { definition (name: "SmartPower Dimming Outlet", namespace: "smartthings", author: "SmartThings") {
capability "Switch" capability "Switch"
capability "Switch Level" capability "Switch Level"
capability "Power Meter" capability "Power Meter"

View File

@@ -15,7 +15,7 @@
*/ */
metadata { metadata {
// Automatically generated. Make future change here. // Automatically generated. Make future change here.
definition(name: "SmartPower Outlet", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.smartplug") { definition(name: "SmartPower Outlet", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Switch" capability "Switch"
capability "Power Meter" capability "Power Meter"

View File

@@ -33,7 +33,6 @@ metadata {
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-Seu", deviceJoinName: "Water Leak Sensor" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-Seu", deviceJoinName: "Water Leak Sensor"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-L", deviceJoinName: "Iris Smart Water Sensor" fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-L", deviceJoinName: "Iris Smart Water Sensor"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-G", deviceJoinName: "Centralite Water Sensor"
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "moisturev4", deviceJoinName: "Water Leak Sensor" fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "moisturev4", deviceJoinName: "Water Leak Sensor"
} }
@@ -59,7 +58,7 @@ metadata {
multiAttributeTile(name: "water", type: "generic", width: 6, height: 4) { multiAttributeTile(name: "water", type: "generic", width: 6, height: 4) {
tileAttribute("device.water", key: "PRIMARY_CONTROL") { tileAttribute("device.water", key: "PRIMARY_CONTROL") {
attributeState "dry", label: "Dry", icon: "st.alarm.water.dry", backgroundColor: "#ffffff" attributeState "dry", label: "Dry", icon: "st.alarm.water.dry", backgroundColor: "#ffffff"
attributeState "wet", label: "Wet", icon: "st.alarm.water.wet", backgroundColor: "#00A0DC" attributeState "wet", label: "Wet", icon: "st.alarm.water.wet", backgroundColor: "#53a7c0"
} }
} }
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) { valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
@@ -107,12 +106,6 @@ def parse(String description) {
} }
} }
} }
} else if (map.name == "temperature") {
if (tempOffset) {
map.value = (int) map.value + (int) tempOffset
}
map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F'
map.translatable = true
} }
log.debug "Parse returned $map" log.debug "Parse returned $map"

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,36 +0,0 @@
# Smartsense Moisture
Cloud Execution
Works with:
* [FortrezZ Moisture Sensor](https://www.smartthings.com/works-with-smartthings/fortrezz/fortrezz-moisture-sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Water Sensor** - can detect presence of water (dry or wet)
* **Sensor** - detects sensor events
* **Battery** - defines device uses a battery
* **Temperature Measurement** - represents capability to measure temperature
* **Health Check** - indicates ability to get device health notifications
## Device Health
Smartsense Moisture is a Z-wave sleepy device type and checks in every 4 hours.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*4*60 + 2)mins = 482 mins.
* __482min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the different motion sensors from SmartThings can be found in the following links
for the different models:
* [FortrezZ Moisture Sensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200930740-FortrezZ-Moisture-Sensor)

View File

@@ -17,11 +17,9 @@ metadata {
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Temperature Measurement" capability "Temperature Measurement"
capability "Health Check"
fingerprint deviceId: "0x2001", inClusters: "0x30,0x9C,0x9D,0x85,0x80,0x72,0x31,0x84,0x86" fingerprint deviceId: "0x2001", inClusters: "0x30,0x9C,0x9D,0x85,0x80,0x72,0x31,0x84,0x86"
fingerprint deviceId: "0x2101", inClusters: "0x71,0x70,0x85,0x80,0x72,0x31,0x84,0x86" fingerprint deviceId: "0x2101", inClusters: "0x71,0x70,0x85,0x80,0x72,0x31,0x84,0x86"
fingerprint mfr:"0084", prod:"0063", model:"010C", deviceJoinName: "FortrezZ Moisture Sensor"
} }
simulator { simulator {
@@ -91,11 +89,6 @@ def parse(String description) {
return result return result
} }
def updated() {
// Device-Watch simply pings if no device events received for 482min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 4 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
{ {
[descriptionText: "${device.displayName} woke up", isStateChange: false] [descriptionText: "${device.displayName} woke up", isStateChange: false]

View File

@@ -34,7 +34,6 @@ metadata {
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326-L", deviceJoinName: "Iris Motion Sensor" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326-L", deviceJoinName: "Iris Motion Sensor"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3328-G", deviceJoinName: "Centralite Micro Motion Sensor"
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv4", deviceJoinName: "Motion Sensor" fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv4", deviceJoinName: "Motion Sensor"
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv5", deviceJoinName: "Motion Sensor" fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv5", deviceJoinName: "Motion Sensor"
} }
@@ -113,12 +112,6 @@ def parse(String description) {
map = getMotionResult(value) map = getMotionResult(value)
} }
} }
} else if (map.name == "temperature") {
if (tempOffset) {
map.value = (int) map.value + (int) tempOffset
}
map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F'
map.translatable = true
} }
log.debug "Parse returned $map" log.debug "Parse returned $map"

View File

@@ -30,8 +30,8 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){ multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") { tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC" attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc" attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
} }
} }
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) { valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {

View File

@@ -33,7 +33,6 @@ metadata {
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321-S", deviceJoinName: "Multipurpose Sensor" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321-S", deviceJoinName: "Multipurpose Sensor"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3323-G", deviceJoinName: "Centralite Micro Door Sensor"
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500,FC02", outClusters: "0019", manufacturer: "SmartThings", model: "multiv4", deviceJoinName: "Multipurpose Sensor" fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500,FC02", outClusters: "0019", manufacturer: "SmartThings", model: "multiv4", deviceJoinName: "Multipurpose Sensor"
attribute "status", "string" attribute "status", "string"

View File

@@ -52,14 +52,14 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"contact", type: "generic", width: 6, height: 4){ multiAttributeTile(name:"contact", type: "generic", width: 6, height: 4){
tileAttribute ("device.contact", key: "PRIMARY_CONTROL") { tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13" attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00a0dc" attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
} }
} }
standardTile("acceleration", "device.acceleration", width: 2, height: 2) { standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00a0dc") state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
state("inactive", label:'${name}', icon:"st.motion.acceleration.inactive", backgroundColor:"#cccccc") state("inactive", label:'${name}', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
} }
valueTile("temperature", "device.temperature", width: 2, height: 2) { valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label:'${currentValue}°', state("temperature", label:'${currentValue}°',

View File

@@ -95,12 +95,6 @@ def parse(String description) {
} }
} }
} }
} else if (map.name == "temperature") {
if (tempOffset) {
map.value = (int) map.value + (int) tempOffset
}
map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F'
map.translatable = true
} }
log.debug "Parse returned $map" log.debug "Parse returned $map"

View File

@@ -88,12 +88,6 @@ def parse(String description) {
log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}" log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
} }
} }
} else if (map.name == "temperature") {
if (tempOffset) {
map.value = (int) map.value + (int) tempOffset
}
map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F'
map.translatable = true
} }
log.debug "Parse returned $map" log.debug "Parse returned $map"

View File

@@ -23,7 +23,6 @@ metadata {
capability "Refresh" capability "Refresh"
capability "Temperature Measurement" capability "Temperature Measurement"
capability "Health Check" capability "Health Check"
capability "Sensor"
command "enrollResponse" command "enrollResponse"
@@ -42,8 +41,8 @@ metadata {
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) {

View File

@@ -18,7 +18,7 @@
metadata { metadata {
definition (name: "Wemo Light Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "Wemo Light Switch", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Switch" capability "Switch"
capability "Polling" capability "Polling"

View File

@@ -16,7 +16,7 @@
* Date: 2015-10-11 * Date: 2015-10-11
*/ */
metadata { metadata {
definition (name: "Wemo Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.smartplug") { definition (name: "Wemo Switch", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Switch" capability "Switch"
capability "Polling" capability "Polling"

View File

@@ -44,7 +44,7 @@ metadata {
tiles { tiles {
standardTile("button", "device.button", width: 2, height: 2) { standardTile("button", "device.button", width: 2, height: 2) {
state "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff" state "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
state "button 1 pushed", label: "pushed #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#00A0DC" state "button 1 pushed", label: "pushed #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#79b821"
} }
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) { valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) {

View File

@@ -13,7 +13,7 @@
*/ */
metadata { metadata {
definition (name: "ZigBee Dimmer Power", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "ZigBee Dimmer Power", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Configuration" capability "Configuration"
capability "Refresh" capability "Refresh"

View File

@@ -13,7 +13,7 @@
*/ */
metadata { metadata {
definition (name: "ZigBee Dimmer", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "ZigBee Dimmer", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Configuration" capability "Configuration"
capability "Refresh" capability "Refresh"

View File

@@ -13,7 +13,7 @@
*/ */
metadata { metadata {
definition (name: "ZigBee Switch Power", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "ZigBee Switch Power", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Configuration" capability "Configuration"
capability "Refresh" capability "Refresh"

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,35 +0,0 @@
# Leviton Switch (ZigBee)
Cloud Execution
Works with:
* [Leviton Switch (ZigBee)](https://www.smartthings.com/works-with-smartthings/leviton/leviton-switch)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Refresh** - _refresh()_ command for status updates
* **Switch** - can detect state (possible values: on/off)
* **Health Check** - indicates ability to get device health notifications
## Device Health
A Zigbee Switch with reporting interval of 10 mins.
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
* __22min__ 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:
* [Leviton Switch Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/209686003-How-to-connect-Leviton-ZigBee-devices)

View File

@@ -13,12 +13,11 @@
*/ */
metadata { metadata {
definition (name: "ZigBee Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "ZigBee Switch", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Configuration" capability "Configuration"
capability "Refresh" capability "Refresh"
capability "Switch" capability "Switch"
capability "Health Check"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0003, 0006, 0019, 0406", manufacturer: "Leviton", model: "ZSS-10", deviceJoinName: "Leviton Switch" fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0003, 0006, 0019, 0406", manufacturer: "Leviton", model: "ZSS-10", deviceJoinName: "Leviton Switch"
@@ -76,20 +75,11 @@ def on() {
zigbee.on() zigbee.on()
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return refresh()
}
def refresh() { def refresh() {
zigbee.onOffRefresh() + zigbee.onOffConfig() zigbee.onOffRefresh() + zigbee.onOffConfig()
} }
def configure() { def configure() {
// Device-Watch allows 2 check-in misses from device + ping (plus 2 min lag time)
sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
log.debug "Configuring Reporting and Bindings." log.debug "Configuring Reporting and Bindings."
zigbee.onOffRefresh() + zigbee.onOffConfig() zigbee.onOffRefresh() + zigbee.onOffConfig()
} }

View File

@@ -30,7 +30,7 @@ metadata {
attribute "colorName", "string" attribute "colorName", "string"
command "setGenericName" command "setGenericName"
fingerprint profileId: "C05E", deviceId: "0220", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300", outClusters: "0019", manufacturer: "Eaton", model: "Halo_RL5601", deviceJoinName: "Halo RL56" fingerprint profileId: "C05E", deviceId: "0220", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300", outClusters: "0019", manufacturer: "Eaton", model: "Halo_LT01", deviceJoinName: "Halo RL56 Wireless"
} }
// UI tile definitions // UI tile definitions

View File

@@ -1,41 +0,0 @@
/**
* Zooz Power Strip Outlet
*
* Copyright 2017 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "Zooz Power Strip Outlet", namespace: "smartthings", author: "SmartThings") {
capability "Switch"
capability "Actuator"
capability "Sensor"
}
tiles {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState:"turningOn"
attributeState "on", 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:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
}
}
}
void on() {
parent.childOn(device.deviceNetworkId)
}
void off() {
parent.childOff(device.deviceNetworkId)
}

View File

@@ -1,217 +0,0 @@
/**
* Zooz ZEN20 Power Strip Outlet
*
* Implementation of the Zooz ZEN20 power strip that uses the new composite device capabilities to provide individual
* control of each outlet from SmartApps as well as the mobile app. Incorporates contributions from:
*
* Eric Maycock (https://github.com/erocm123/SmartThingsPublic/blob/master/devicetypes/erocm123/zooz-power-strip.src/zooz-power-strip.groovy)
* Robert Vandervoort (https://github.com/robertvandervoort/SmartThings/blob/master/zooZ-Strip-ZEN20/device_type-zooZ-strip-ZEN20_v1.0)
*
* Copyright 2017 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "Zooz Power Strip", namespace: "smartthings", author: "SmartThings") {
capability "Switch"
capability "Refresh"
capability "Actuator"
capability "Sensor"
capability "Configuration"
fingerprint manufacturer: "015D", prod: "0651", model: "F51C", deviceJoinName: "Zooz ZEN 20 Power Strip"
}
tiles {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState:"turningOn"
attributeState "on", 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:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
}
childDeviceTiles("outlets")
standardTile("refresh", "device.switch", width: 1, height: 1, inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
}
}
}
/////////////////////////////
// Installation and update //
/////////////////////////////
def installed() {
createChildDevices()
}
def updated() {
if (!childDevices) {
createChildDevices()
}
else if (device.label != state.oldLabel) {
childDevices.each {
def newLabel = "${device.displayName} (CH${channelNumber(it.deviceNetworkId)})"
it.setLabel(newLabel)
}
state.oldLabel = device.label
}
}
def configure() {
refresh()
}
//////////////////////
// Event Generation //
//////////////////////
def parse(String description) {
trace "parse('$description')"
def result = []
if (description.startsWith("Err")) {
result = createEvent(descriptionText:description, isStateChange:true)
} else if (description != "updated") {
def cmd = zwave.parse(description, [0x60: 3, 0x32: 3, 0x25: 1, 0x20: 1])
if (cmd) {
result += zwaveEvent(cmd, 1)
}
else {
log.warn "Unparsed description $description"
}
}
result
}
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1])
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer)
}
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, endpoint) {
trace "zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport $cmd, $endpoint)"
zwaveBinaryEvent(cmd, endpoint)
}
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, endpoint) {
trace "zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport $cmd, $endpoint)"
zwaveBinaryEvent(cmd, endpoint)
}
def zwaveBinaryEvent(cmd, endpoint) {
def result = []
def children = childDevices
def childDevice = children.find{it.deviceNetworkId.endsWith("$endpoint")}
if (childDevice) {
childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off")
if (cmd.value) {
// One on and the strip is on
result << createEvent(name: "switch", value: "on")
} else {
// All off and the strip is off
if (!children.any { it.currentValue("switch") == "on" }) {
result << createEvent(name: "switch", value: "off")
}
}
}
result
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd, ep) {
updateDataValue("MSR", String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId))
return null
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd, ep) {
trace "applicationVersion $cmd.applicationVersion"
}
def zwaveEvent(physicalgraph.zwave.Command cmd, ep) {
log.warn("${device.displayName}: Unhandled ${cmd}" + (ep ? " from endpoint $ep" : ""))
}
/////////////////////////////
// Installation and update //
/////////////////////////////
def on() {
def cmds = []
def cmd = zwave.switchBinaryV1.switchBinarySet(switchValue: 0xFF)
cmds << zwave.multiChannelV3.multiChannelCmdEncap(bitAddress: true, destinationEndPoint:0x1F).encapsulate(cmd).format()
cmds << "delay 400"
cmds.addAll(refresh())
return cmds
}
def off() {
def cmds = []
def cmd = zwave.switchBinaryV1.switchBinarySet(switchValue: 0x00)
cmds << zwave.multiChannelV3.multiChannelCmdEncap(bitAddress: true, destinationEndPoint:0x1F).encapsulate(cmd).format()
cmds << "delay 400"
cmds.addAll(refresh())
return cmds
}
//////////////////////
// Child Device API //
//////////////////////
void childOn(String dni) {
onOffCmd(0xFF, channelNumber(dni))
}
void childOff(String dni) {
onOffCmd(0, channelNumber(dni))
}
def refresh() {
def cmds = (1..5).collect { endpoint ->
encap(zwave.switchBinaryV1.switchBinaryGet(), endpoint)
}
delayBetween(cmds, 100)
}
///////////////////
// Local Methods //
///////////////////
private channelNumber(String dni) {
dni.split("-ep")[-1] as Integer
}
private void onOffCmd(value, endpoint = null) {
def actions = [
new physicalgraph.device.HubAction(encap(zwave.basicV1.basicSet(value: value), endpoint)),
new physicalgraph.device.HubAction(encap(zwave.switchBinaryV1.switchBinaryGet(), endpoint)),
]
sendHubCommand(actions, 500)
}
private void createChildDevices() {
state.oldLabel = device.label
for (i in 1..5) {
addChildDevice("Zooz Power Strip Outlet", "${device.deviceNetworkId}-ep${i}", null,
[completedSetup: true, label: "${device.displayName} (CH${i})",
isComponent: true, componentName: "ch$i", componentLabel: "Channel $i"])
}
}
private encap(cmd, endpoint) {
if (endpoint) {
zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:endpoint).encapsulate(cmd).format()
} else {
cmd.format()
}
}
private trace(msg) {
//log.trace(msg)
}

View File

@@ -40,7 +40,7 @@ metadata {
tiles { tiles {
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.unknown.zwave.device", backgroundColor: "#00A0DC" state "on", label: '${name}', action: "switch.off", icon: "st.unknown.zwave.device", backgroundColor: "#79b821"
state "off", label: '${name}', action: "switch.on", icon: "st.unknown.zwave.device", backgroundColor: "#ffffff" state "off", label: '${name}', action: "switch.on", icon: "st.unknown.zwave.device", backgroundColor: "#ffffff"
} }
standardTile("switchOn", "device.switch", inactiveLabel: false, decoration: "flat") { standardTile("switchOn", "device.switch", inactiveLabel: false, decoration: "flat") {

View File

@@ -12,7 +12,7 @@
* *
*/ */
metadata { metadata {
definition (name: "Z-Wave Dimmer Switch Generic", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "Z-Wave Dimmer Switch Generic", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level" capability "Switch Level"
capability "Actuator" capability "Actuator"
capability "Health Check" capability "Health Check"

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,36 +0,0 @@
# Z-Wave Door Window Sensor
Cloud Execution
Works with:
* [Aeon Labs Door/Window Sensor (Gen 5)](https://www.smartthings.com/works-with-smartthings/aeon-labs/aeon-labs-doorwindow-sensor-gen-5)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Health Check** - indicates ability to get device health notifications
* **Sensor** - detects sensor events
* **Battery** - defines that the device has a battery
* **Contact Sensor** - allows reading the value of a contact sensor device
## Device Health
Z-Wave Door Window Sensor is a Z-wave sleepy device and checks in every 4 hours.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*4*60 + 2)mins = 482 mins.
* __482min__ 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 links
for the different models:
* [Aeon Labs Door/Window Sensor (Gen 5) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/211834163-How-to-connect-Aeon-Labs-door-window-sensors)

View File

@@ -22,14 +22,12 @@ metadata {
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Configuration" capability "Configuration"
capability "Health Check"
fingerprint deviceId: "0x2001", inClusters: "0x30,0x80,0x84,0x85,0x86,0x72" fingerprint deviceId: "0x2001", inClusters: "0x30,0x80,0x84,0x85,0x86,0x72"
fingerprint deviceId: "0x07", inClusters: "0x30" fingerprint deviceId: "0x07", inClusters: "0x30"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x98" fingerprint deviceId: "0x0701", inClusters: "0x5E,0x98"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82" fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x80,0x71,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0x59,0x73,0x5A,0x8F,0x98,0x7A", outClusters:"0x20" // Philio multi+ fingerprint deviceId: "0x0701", inClusters: "0x5E,0x80,0x71,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0x59,0x73,0x5A,0x8F,0x98,0x7A", outClusters:"0x20" // Philio multi+
fingerprint mfr:"0086", prod:"0002", model:"001D", deviceJoinName: "Aeon Labs Door/Window Sensor (Gen 5)"
} }
// simulator metadata // simulator metadata
@@ -43,8 +41,8 @@ metadata {
// UI tile definitions // UI tile definitions
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("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:""
@@ -80,8 +78,6 @@ def parse(String description) {
} }
def updated() { def updated() {
// Device-Watch simply pings if no device events received for 482min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 4 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
def cmds = [] def cmds = []
if (!state.MSR) { if (!state.MSR) {
cmds = [ cmds = [

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,41 +0,0 @@
# Z-wave Garage Door Opener
Cloud Execution
Works with:
* [Linear GoControl Garage Door Opener](https://www.smartthings.com/works-with-smartthings/other/linear-gocontrol-garage-door-opener)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Door Control** - allow for the control of a door
* **Garage Door Control** - allow for the control of a garage door
* **Health Check** - indicates ability to get device health notifications
* **Contact Sensor** - can detect contact (with possible values - open/closed)
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
## Device Health
Linear GoControl Garage Door Opener is polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __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:
* [Linear GoControl Garage Door Opener Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204831116-GoControl-Linear-Garage-Door-Opener-GD00Z-4-)

View File

@@ -18,14 +18,12 @@ metadata {
capability "Actuator" capability "Actuator"
capability "Door Control" capability "Door Control"
capability "Garage Door Control" capability "Garage Door Control"
capability "Health Check"
capability "Contact Sensor" capability "Contact Sensor"
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
fingerprint deviceId: "0x4007", inClusters: "0x98" fingerprint deviceId: "0x4007", inClusters: "0x98"
fingerprint deviceId: "0x4006", inClusters: "0x98" fingerprint deviceId: "0x4006", inClusters: "0x98"
fingerprint mfr:"014F", prod:"4744", model:"3030", deviceJoinName: "Linear GoControl Garage Door Opener"
} }
simulator { simulator {
@@ -41,11 +39,11 @@ metadata {
tiles { tiles {
standardTile("toggle", "device.door", width: 2, height: 2) { standardTile("toggle", "device.door", width: 2, height: 2) {
state("unknown", label:'${name}', action:"refresh.refresh", icon:"st.doors.garage.garage-open", backgroundColor:"#ffffff") state("unknown", label:'${name}', action:"refresh.refresh", icon:"st.doors.garage.garage-open", backgroundColor:"#ffa81e")
state("closed", label:'${name}', action:"door control.open", icon:"st.doors.garage.garage-closed", backgroundColor:"#00a0dc", nextState:"opening") state("closed", label:'${name}', action:"door control.open", icon:"st.doors.garage.garage-closed", backgroundColor:"#79b821", nextState:"opening")
state("open", label:'${name}', action:"door control.close", icon:"st.doors.garage.garage-open", backgroundColor:"#e86d13", nextState:"closing") state("open", label:'${name}', action:"door control.close", icon:"st.doors.garage.garage-open", backgroundColor:"#ffa81e", nextState:"closing")
state("opening", label:'${name}', icon:"st.doors.garage.garage-opening", backgroundColor:"#e86d13") state("opening", label:'${name}', icon:"st.doors.garage.garage-opening", backgroundColor:"#ffe71e")
state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#00a0dc") state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#ffe71e")
} }
standardTile("open", "device.door", inactiveLabel: false, decoration: "flat") { standardTile("open", "device.door", inactiveLabel: false, decoration: "flat") {
@@ -65,11 +63,6 @@ metadata {
import physicalgraph.zwave.commands.barrieroperatorv1.* import physicalgraph.zwave.commands.barrieroperatorv1.*
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])
}
def parse(String description) { def parse(String description) {
def result = null def result = null
if (description.startsWith("Err")) { if (description.startsWith("Err")) {
@@ -294,13 +287,6 @@ def close() {
secure(zwave.barrierOperatorV1.barrierOperatorSet(requestedBarrierState: BarrierOperatorSet.REQUESTED_BARRIER_STATE_CLOSE)) secure(zwave.barrierOperatorV1.barrierOperatorSet(requestedBarrierState: BarrierOperatorSet.REQUESTED_BARRIER_STATE_CLOSE))
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() { def refresh() {
secure(zwave.barrierOperatorV1.barrierOperatorGet()) secure(zwave.barrierOperatorV1.barrierOperatorGet())
} }

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,45 +0,0 @@
# Z-Wave Switch
Cloud Execution
Works with:
* [Yale Key Free Touchscreen Deadbolt (YRD240)](https://www.smartthings.com/works-with-smartthings/yale/yale-key-free-touchscreen-deadbolt-yrd240)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Battery** - defines device uses a battery
* **Lock** - allows for the control of a lock device
* **Lock Codes** - allows for the lock code control of a lock device
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
* **Health Check** - indicates ability to get device health notifications
## Device Health
Z-Wave Locks are polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __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:
* [General Z-Wave/ZigBee Yale Lock Troubleshooting](https://support.smartthings.com/hc/en-us/articles/205138400-How-to-connect-Yale-locks)

View File

@@ -20,13 +20,11 @@ metadata {
capability "Sensor" capability "Sensor"
capability "Lock Codes" capability "Lock Codes"
capability "Battery" capability "Battery"
capability "Health Check"
command "unlockwtimeout" command "unlockwtimeout"
fingerprint deviceId: "0x4003", inClusters: "0x98" fingerprint deviceId: "0x4003", inClusters: "0x98"
fingerprint deviceId: "0x4004", inClusters: "0x98" fingerprint deviceId: "0x4004", inClusters: "0x98"
fingerprint mfr:"0129", prod:"0002", model:"0000", deviceJoinName: "Yale Key Free Touchscreen Deadbolt"
} }
simulator { simulator {
@@ -40,10 +38,10 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"toggle", type: "generic", width: 6, height: 4){ multiAttributeTile(name:"toggle", type: "generic", width: 6, height: 4){
tileAttribute ("device.lock", key: "PRIMARY_CONTROL") { tileAttribute ("device.lock", key: "PRIMARY_CONTROL") {
attributeState "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#00A0DC", nextState:"unlocking" attributeState "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#79b821", nextState:"unlocking"
attributeState "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff", nextState:"locking" attributeState "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff", nextState:"locking"
attributeState "unknown", label:"unknown", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking" attributeState "unknown", label:"unknown", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking"
attributeState "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#00A0DC" attributeState "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#79b821"
attributeState "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff" attributeState "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff"
} }
} }
@@ -69,8 +67,6 @@ import physicalgraph.zwave.commands.doorlockv1.*
import physicalgraph.zwave.commands.usercodev1.* import physicalgraph.zwave.commands.usercodev1.*
def updated() { 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])
try { try {
if (!state.init) { if (!state.init) {
state.init = true state.init = true
@@ -508,13 +504,6 @@ def unlockwtimeout() {
lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT) lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT)
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() { def refresh() {
def cmds = [secure(zwave.doorLockV1.doorLockOperationGet())] def cmds = [secure(zwave.doorLockV1.doorLockOperationGet())]
if (state.assoc == zwaveHubNodeId) { if (state.assoc == zwaveHubNodeId) {

View File

@@ -16,7 +16,7 @@
* *
*/ */
metadata { metadata {
definition (name: "Z-Wave Metering Dimmer", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "Z-Wave Metering Dimmer", namespace: "smartthings", author: "SmartThings") {
capability "Switch" capability "Switch"
capability "Polling" capability "Polling"
capability "Power Meter" capability "Power Meter"

View File

@@ -12,7 +12,7 @@
* *
*/ */
metadata { metadata {
definition (name: "Z-Wave Metering Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "Z-Wave Metering Switch", namespace: "smartthings", author: "SmartThings") {
capability "Energy Meter" capability "Energy Meter"
capability "Actuator" capability "Actuator"
capability "Switch" capability "Switch"
@@ -22,12 +22,10 @@ metadata {
capability "Configuration" capability "Configuration"
capability "Sensor" capability "Sensor"
capability "Light" capability "Light"
capability "Health Check"
command "reset" command "reset"
fingerprint inClusters: "0x25,0x32" fingerprint inClusters: "0x25,0x32"
fingerprint mfr:"0086", prod:"0003", model:"0012", deviceJoinName: "Aeon Labs Micro Smart Switch"
} }
// simulator metadata // simulator metadata
@@ -75,8 +73,6 @@ metadata {
} }
def updated() { 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])
try { try {
if (!state.MSR) { if (!state.MSR) {
response(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format()) response(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format())
@@ -86,7 +82,7 @@ def updated() {
def parse(String description) { def parse(String description) {
def result = null def result = null
if(description == "updated") return if(description == "updated") return
def cmd = zwave.parse(description, [0x20: 1, 0x32: 1, 0x72: 2]) def cmd = zwave.parse(description, [0x20: 1, 0x32: 1, 0x72: 2])
if (cmd) { if (cmd) {
result = zwaveEvent(cmd) result = zwaveEvent(cmd)
@@ -183,14 +179,6 @@ def poll() {
]) ])
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
log.debug "ping() called"
refresh()
}
def refresh() { def refresh() {
delayBetween([ delayBetween([
zwave.switchBinaryV1.switchBinaryGet().format(), zwave.switchBinaryV1.switchBinaryGet().format(),

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,39 +0,0 @@
# Z-wave Motion Sensor
Cloud Execution
Works with:
* [Ecolink PIR Motion Detector with Pet Immunity](https://www.smartthings.com/works-with-smartthings/sensors/ecolink-pir-motion-detector-with-pet-immunity)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Motion Sensor** - can detect motion
* **Sensor** - detects sensor events
* **Battery** - defines device uses a battery
* **Health Check** - indicates ability to get device health notifications
## Device Health
Ecolink PIR Motion Detector with Pet Immunity is a Z-wave sleepy device and wakes up every 4 hours.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*4*60 + 2)mins = 482 mins.
* __482min__ checkInterval
## Battery Specification
One CR123A Lithium 3V battery is required.
## 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:
* [Ecolink PIR Motion Detector with Pet Immunity Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202294400-Ecolink-PIR-Motion-Detector-PIRZWAVE2-ECO-)

View File

@@ -21,7 +21,6 @@ metadata {
capability "Motion Sensor" capability "Motion Sensor"
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Health Check"
fingerprint mfr: "011F", prod: "0001", model: "0001", deviceJoinName: "Schlage Motion Sensor" // Schlage motion fingerprint mfr: "011F", prod: "0001", model: "0001", deviceJoinName: "Schlage Motion Sensor" // Schlage motion
fingerprint mfr: "014A", prod: "0001", model: "0001", deviceJoinName: "Ecolink Motion Sensor" // Ecolink motion fingerprint mfr: "014A", prod: "0001", model: "0001", deviceJoinName: "Ecolink Motion Sensor" // Ecolink motion
@@ -51,11 +50,6 @@ metadata {
} }
} }
def updated(){
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def parse(String description) { def parse(String description) {
def result = null def result = null
if (description.startsWith("Err")) { if (description.startsWith("Err")) {

View File

@@ -37,8 +37,8 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"contact", type: "generic", width: 6, height: 4){ multiAttributeTile(name:"contact", type: "generic", width: 6, height: 4){
tileAttribute ("device.contact", key: "PRIMARY_CONTROL") { tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13" attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00a0dc" attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
} }
} }
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) { valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,42 +0,0 @@
# Z-wave Siren
Cloud Execution
Works with:
* [FortrezZ Siren Strobe Alarm](https://www.smartthings.com/works-with-smartthings/other/fortrezz-water-valve)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Alarm** - allows for interacting with devices that serve as alarms
* **Battery** - defines device uses a battery
* **Health Check** - indicates ability to get device health notifications
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
* **Switch** - can detect state (possible values: on/off)
## Device Health
FortrezZ Siren Strobe Alarm is polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __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:
* [FortrezZ Siren Strobe Alarm Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202294760-FortrezZ-Siren-Strobe-Alarm)

View File

@@ -20,7 +20,6 @@ metadata {
capability "Actuator" capability "Actuator"
capability "Alarm" capability "Alarm"
capability "Battery" capability "Battery"
capability "Health Check"
capability "Polling" capability "Polling"
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
@@ -28,7 +27,6 @@ metadata {
fingerprint inClusters: "0x20,0x25,0x86,0x80,0x85,0x72,0x71" fingerprint inClusters: "0x20,0x25,0x86,0x80,0x85,0x72,0x71"
fingerprint mfr:"0084", prod:"0313", model:"010B", deviceJoinName: "FortrezZ Siren Strobe Alarm"
} }
simulator { simulator {
@@ -60,11 +58,6 @@ metadata {
} }
} }
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])
}
def createEvents(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def createEvents(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ] def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) { if (cmd.batteryLevel == 0xFF) {
@@ -126,13 +119,6 @@ def both() {
on() on()
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() { def refresh() {
log.debug "sending battery refresh command" log.debug "sending battery refresh command"
zwave.batteryV1.batteryGet().format() zwave.batteryV1.batteryGet().format()

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,40 +0,0 @@
# Z-wave Smoke Alarm
Cloud Execution
Works with:
* [First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)](https://www.smartthings.com/works-with-smartthings/sensors/first-alert-smoke-detector-and-carbon-monoxide-alarm-zcombo)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Smoke Detector** - measure smoke and optionally carbon monoxide levels
* **Carbon Monoxide Detector** - measure carbon monoxide levels
* **Sensor** - detects sensor events
* **Battery** - defines device uses a battery
* **Health Check** - indicates ability to get device health notifications
## Device Health
First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO) is a Z-wave sleepy device and checks in every 1 hour.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*60 + 2)mins = 122 mins.
* __122min__ checkInterval
## Battery Specification
Two AA 1.5V batteries are required.
## 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:
* [First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/201581984-First-Alert-Smoke-Detector-and-Carbon-Monoxide-Alarm-ZCOMBO-)

View File

@@ -17,12 +17,10 @@ metadata {
capability "Carbon Monoxide Detector" capability "Carbon Monoxide Detector"
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Health Check"
attribute "alarmState", "string" attribute "alarmState", "string"
fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86" fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86"
fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)"
} }
simulator { simulator {
@@ -53,11 +51,6 @@ metadata {
} }
} }
def updated(){
// Device checks in every hour, this interval allows us to miss one check-in notification before marking offline
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def parse(String description) { def parse(String description) {
def results = [] def results = []
if (description.startsWith("Err")) { if (description.startsWith("Err")) {
@@ -72,6 +65,7 @@ def parse(String description) {
return results return results
} }
def createSmokeOrCOEvents(name, results) { def createSmokeOrCOEvents(name, results) {
def text = null def text = null
switch (name) { switch (name) {

View File

@@ -12,7 +12,7 @@
* *
*/ */
metadata { metadata {
definition (name: "Z-Wave Switch Generic", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "Z-Wave Switch Generic", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Health Check" capability "Health Check"
capability "Switch" capability "Switch"

View File

@@ -12,7 +12,7 @@
* *
*/ */
metadata { metadata {
definition (name: "Z-Wave Switch Secure", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "Z-Wave Switch Secure", namespace: "smartthings", author: "SmartThings") {
capability "Switch" capability "Switch"
capability "Refresh" capability "Refresh"
capability "Polling" capability "Polling"

View File

@@ -12,7 +12,7 @@
* *
*/ */
metadata { metadata {
definition (name: "Z-Wave Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") { definition (name: "Z-Wave Switch", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Indicator" capability "Indicator"
capability "Switch" capability "Switch"

View File

@@ -20,7 +20,6 @@ metadata {
capability "Configuration" capability "Configuration"
capability "Polling" capability "Polling"
capability "Sensor" capability "Sensor"
capability "Health Check"
attribute "thermostatFanState", "string" attribute "thermostatFanState", "string"
@@ -31,7 +30,6 @@ metadata {
fingerprint deviceId: "0x08" fingerprint deviceId: "0x08"
fingerprint inClusters: "0x43,0x40,0x44,0x31" fingerprint inClusters: "0x43,0x40,0x44,0x31"
fingerprint mfr:"0039", prod:"0011", model:"0001", deviceJoinName: "Honeywell Z-Wave Thermostat"
} }
// simulator metadata // simulator metadata
@@ -42,9 +40,9 @@ metadata {
status "auto" : "command: 4003, payload: 03" status "auto" : "command: 4003, payload: 03"
status "emergencyHeat" : "command: 4003, payload: 04" status "emergencyHeat" : "command: 4003, payload: 04"
status "auto" : "command: 4403, payload: 00" // "fanAuto" status "fanAuto" : "command: 4403, payload: 00"
status "on" : "command: 4403, payload: 01" // "fanOn" status "fanOn" : "command: 4403, payload: 01"
status "circulate" : "command: 4403, payload: 06" // "fanCirculate status "fanCirculate" : "command: 4403, payload: 06"
status "heat 60" : "command: 4303, payload: 01 09 3C" status "heat 60" : "command: 4303, payload: 01 09 3C"
status "heat 68" : "command: 4303, payload: 01 09 44" status "heat 68" : "command: 4303, payload: 01 09 44"
@@ -74,9 +72,8 @@ metadata {
} }
tiles { tiles {
// Using standardTile instead of valueTile as it renders the icon better valueTile("temperature", "device.temperature", width: 2, height: 2) {
standardTile("temperature", "device.temperature", width: 2, height: 2) { state("temperature", label:'${currentValue}°',
state("temperature", label:'${currentValue}°', icon: "st.thermostat.ac.air-conditioning",
backgroundColors:[ backgroundColors:[
[value: 31, color: "#153591"], [value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"], [value: 44, color: "#1e9cbb"],
@@ -89,20 +86,19 @@ metadata {
) )
} }
standardTile("mode", "device.thermostatMode", inactiveLabel: false, decoration: "flat") { standardTile("mode", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
state "off", action:"switchMode", nextState:"to_heat", icon: "st.thermostat.heating-cooling-off" state "off", label:'${name}', action:"switchMode", nextState:"to_heat"
state "heat", action:"switchMode", nextState:"to_cool", icon: "st.thermostat.heat" state "heat", label:'${name}', action:"switchMode", nextState:"to_cool"
state "cool", action:"switchMode", nextState:"...", icon: "st.thermostat.cool" state "cool", label:'${name}', action:"switchMode", nextState:"..."
state "auto", action:"switchMode", nextState:"...", icon: "st.thermostat.auto" state "auto", label:'${name}', action:"switchMode", nextState:"..."
state "emergency heat", action:"switchMode", nextState:"...", icon: "st.thermostat.emergency-heat" state "emergency heat", label:'${name}', action:"switchMode", nextState:"..."
state "to_heat", action:"switchMode", nextState:"to_cool", icon: "st.thermostat.heat" state "to_heat", label: "heat", action:"switchMode", nextState:"to_cool"
state "to_cool", action:"switchMode", nextState:"...", icon: "st.thermostat.cool" state "to_cool", label: "cool", action:"switchMode", nextState:"..."
state "...", label: "...", action:"off", nextState:"off" state "...", label: "...", action:"off", nextState:"off"
} }
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") { standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
state "auto", action:"switchFanMode", nextState:"...", icon: "st.thermostat.fan-auto" // "fanAuto" state "fanAuto", label:'${name}', action:"switchFanMode"
state "on", action:"switchFanMode", nextState:"...", icon: "st.thermostat.fan-on" // "fanOn" state "fanOn", label:'${name}', action:"switchFanMode"
state "circulate", action:"switchFanMode", nextState:"...", icon: "st.thermostat.fan-circulate" // "fanCirculate" state "fanCirculate", label:'${name}', action:"switchFanMode"
state "...", label: "...", nextState:"..."
} }
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) { controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
state "setHeatingSetpoint", action:"quickSetHeat", backgroundColor:"#d04e00" state "setHeatingSetpoint", action:"quickSetHeat", backgroundColor:"#d04e00"
@@ -119,16 +115,14 @@ metadata {
standardTile("refresh", "device.thermostatMode", inactiveLabel: false, decoration: "flat") { standardTile("refresh", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
state "default", action:"polling.poll", icon:"st.secondary.refresh" state "default", action:"polling.poll", icon:"st.secondary.refresh"
} }
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
}
main "temperature" main "temperature"
details(["temperature", "mode", "fanMode", "heatSliderControl", "heatingSetpoint", "coolSliderControl", "coolingSetpoint", "refresh"]) details(["temperature", "mode", "fanMode", "heatSliderControl", "heatingSetpoint", "coolSliderControl", "coolingSetpoint", "refresh", "configure"])
} }
} }
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])
}
def parse(String description) def parse(String description)
{ {
def map = createEvent(zwaveEvent(zwave.parse(description, [0x42:1, 0x43:2, 0x31: 3]))) def map = createEvent(zwaveEvent(zwave.parse(description, [0x42:1, 0x43:2, 0x31: 3])))
@@ -285,13 +279,13 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanMod
def map = [:] def map = [:]
switch (cmd.fanMode) { switch (cmd.fanMode) {
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_AUTO_LOW: case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_AUTO_LOW:
map.value = "auto" // "fanAuto" map.value = "fanAuto"
break break
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_LOW: case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_LOW:
map.value = "on" // "fanOn" map.value = "fanOn"
break break
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_CIRCULATION: case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_CIRCULATION:
map.value = "circulate" // "fanCirculate" map.value = "fanCirculate"
break break
} }
map.name = "thermostatFanMode" map.name = "thermostatFanMode"
@@ -308,19 +302,15 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSuppo
if(cmd.auto) { supportedModes += "auto " } if(cmd.auto) { supportedModes += "auto " }
state.supportedModes = supportedModes state.supportedModes = supportedModes
// No events to be generated, return empty map
return [:]
} }
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeSupportedReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeSupportedReport cmd) {
def supportedFanModes = "" def supportedFanModes = ""
if(cmd.auto) { supportedFanModes += "auto " } // "fanAuto " if(cmd.auto) { supportedFanModes += "fanAuto " }
if(cmd.low) { supportedFanModes += "on " } // "fanOn" if(cmd.low) { supportedFanModes += "fanOn " }
if(cmd.circulation) { supportedFanModes += "circulate " } // "fanCirculate" if(cmd.circulation) { supportedFanModes += "fanCirculate " }
state.supportedFanModes = supportedFanModes state.supportedFanModes = supportedFanModes
// No events to be generated, return empty map
return [:]
} }
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
@@ -403,25 +393,11 @@ def setCoolingSetpoint(Double degrees, Integer delay = 30000) {
], delay) ], delay)
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
log.debug "ping() called"
poll()
}
def configure() { def configure() {
delayBetween([ delayBetween([
zwave.thermostatModeV2.thermostatModeSupportedGet().format(), zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format(), zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format(),
zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format(), zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()
zwave.sensorMultilevelV3.sensorMultilevelGet().format(), // current temperature
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format(),
zwave.thermostatModeV2.thermostatModeGet().format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format(),
zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format()
], 2300) ], 2300)
} }
@@ -462,11 +438,11 @@ def switchToMode(nextMode) {
def switchFanMode() { def switchFanMode() {
def currentMode = device.currentState("thermostatFanMode")?.value def currentMode = device.currentState("thermostatFanMode")?.value
def lastTriedMode = state.lastTriedFanMode ?: currentMode ?: "off" def lastTriedMode = state.lastTriedFanMode ?: currentMode ?: "off"
def supportedModes = getDataByName("supportedFanModes") ?: "auto on" // "fanAuto fanOn" def supportedModes = getDataByName("supportedFanModes") ?: "fanAuto fanOn"
def modeOrder = ["auto", "circulate", "on"] // "fanAuto", "fanCirculate", "fanOn" def modeOrder = ["fanAuto", "fanCirculate", "fanOn"]
def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] } def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] }
def nextMode = next(lastTriedMode) def nextMode = next(lastTriedMode)
while (!supportedModes?.contains(nextMode) && nextMode != "auto") { // "fanAuto" while (!supportedModes?.contains(nextMode) && nextMode != "fanAuto") {
nextMode = next(nextMode) nextMode = next(nextMode)
} }
switchToFanMode(nextMode) switchToFanMode(nextMode)
@@ -477,11 +453,11 @@ def switchToFanMode(nextMode) {
if(supportedFanModes && !supportedFanModes.contains(nextMode)) log.warn "thermostat mode '$nextMode' is not supported" if(supportedFanModes && !supportedFanModes.contains(nextMode)) log.warn "thermostat mode '$nextMode' is not supported"
def returnCommand def returnCommand
if (nextMode == "auto") { // "fanAuto" if (nextMode == "fanAuto") {
returnCommand = fanAuto() returnCommand = fanAuto()
} else if (nextMode == "on") { // "fanOn" } else if (nextMode == "fanOn") {
returnCommand = fanOn() returnCommand = fanOn()
} else if (nextMode == "circulate") { // "fanCirculate" } else if (nextMode == "fanCirculate") {
returnCommand = fanCirculate() returnCommand = fanCirculate()
} else { } else {
log.debug("no fan mode '$nextMode'") log.debug("no fan mode '$nextMode'")

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,37 +0,0 @@
# Zen Thermostat
Cloud Execution
Works with:
* [Zen Thermostat](https://www.smartthings.com/works-with-smartthings/zen/zen-thermostat)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Thermostat** - allows for the control of a thermostat device
* **Temperature Measurement** - get the temperature from a Device that reports current temperature
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - it represents that a Device has attributes
* **Health Check** - indicates ability to get device health notifications
## Device Health
Zen Thermostat with reporting interval of 5 mins.
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
* __12min__ 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.
Other troubleshooting tips are listed as follows:
* [Zen Thermostat Troubleshooting:](https://support.smartthings.com/hc/en-us/articles/204356564-Zen-Thermostat)

View File

@@ -12,9 +12,8 @@ metadata {
capability "Configuration" capability "Configuration"
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
capability "Health Check"
fingerprint profileId: "0104", endpointId: "01", inClusters: "0000,0001,0003,0004,0005,0020,0201,0202,0204,0B05", outClusters: "000A, 0019"
fingerprint profileId: "0104", endpointId: "01", inClusters: "0000,0001,0003,0004,0005,0020,0201,0202,0204,0B05", outClusters: "000A, 0019", manufacturer: "Zen Within", model: "Zen-01", deviceJoinName: "Zen Thermostat"
//attribute "temperatureUnit", "number" //attribute "temperatureUnit", "number"
@@ -468,12 +467,8 @@ def fanAuto() {
"st wattr 0x${device.deviceNetworkId} 1 0x202 0 0x30 {05}" "st wattr 0x${device.deviceNetworkId} 1 0x202 0 0x30 {05}"
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
// =============== SmartThings Default Fucntions: refresh, configure, poll =============== // =============== SmartThings Default Fucntions: refresh, configure, poll ===============
def refresh() def refresh()
@@ -507,7 +502,6 @@ def poll()
def configure() def configure()
{ {
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
log.debug "configure() - binding & attribute report" log.debug "configure() - binding & attribute report"
[ [
//Set long poll interval to 2 qs //Set long poll interval to 2 qs
@@ -517,7 +511,7 @@ def configure()
//Thermostat - Cluster 201 //Thermostat - Cluster 201
"zdo bind 0x${device.deviceNetworkId} 1 1 0x201 {${device.zigbeeId}} {}", "delay 500", "zdo bind 0x${device.deviceNetworkId} 1 1 0x201 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 0x201 0 0x29 5 300 {3200}", "zcl global send-me-a-report 0x201 0 0x29 5 300 {3200}",
"send 0x${device.deviceNetworkId} 1 1", "delay 500", "send 0x${device.deviceNetworkId} 1 1", "delay 500",
"zcl global send-me-a-report 0x201 0x0011 0x29 5 300 {3200}", "zcl global send-me-a-report 0x201 0x0011 0x29 5 300 {3200}",

View File

@@ -0,0 +1,145 @@
/**
* JSON
*
* Copyright 2015 Jesse Newland
*
* 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: "JSON API",
namespace: "jnewland",
author: "Jesse Newland",
description: "A JSON API for SmartThings",
category: "SmartThings Labs",
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",
oauth: true)
def installed() {
initialize()
}
def updated() {
unsubscribe()
initialize()
}
def initialize() {
if (!state.accessToken) {
createAccessToken()
}
}
preferences {
page(name: "copyConfig")
}
def copyConfig() {
if (!state.accessToken) {
createAccessToken()
}
dynamicPage(name: "copyConfig", title: "Config", install:true) {
section("Select devices to include in the /devices API call") {
input "switches", "capability.switch", title: "Switches", multiple: true, required: false
input "hues", "capability.colorControl", title: "Hues", multiple: true, required: false
}
section() {
paragraph "View this SmartApp's configuration to use it in other places."
href url:"https://graph.api.smartthings.com/api/smartapps/installations/${app.id}/config?access_token=${state.accessToken}", style:"embedded", required:false, title:"Config", description:"Tap, select, copy, then click \"Done\""
}
section() {
href url:"https://graph.api.smartthings.com/api/smartapps/installations/${app.id}/devices?access_token=${state.accessToken}", style:"embedded", required:false, title:"Debug", description:"View accessories JSON"
}
}
}
def renderConfig() {
def configJson = new groovy.json.JsonOutput().toJson([
description: "JSON API",
platforms: [
[
platform: "SmartThings",
name: "SmartThings",
app_id: app.id,
access_token: state.accessToken
]
],
])
def configString = new groovy.json.JsonOutput().prettyPrint(configJson)
render contentType: "text/plain", data: configString
}
def deviceCommandMap(device, type) {
device.supportedCommands.collectEntries { command->
def commandUrl = "https://graph.api.smartthings.com/api/smartapps/installations/${app.id}/${type}/${device.id}/command/${command.name}?access_token=${state.accessToken}"
[
(command.name): commandUrl
]
}
}
def authorizedDevices() {
[
switches: switches,
hues: hues
]
}
def renderDevices() {
def deviceData = authorizedDevices().collectEntries { devices->
[
(devices.key): devices.value.collect { device->
[
name: device.displayName,
commands: deviceCommandMap(device, devices.key)
]
}
]
}
def deviceJson = new groovy.json.JsonOutput().toJson(deviceData)
def deviceString = new groovy.json.JsonOutput().prettyPrint(deviceJson)
render contentType: "application/json", data: deviceString
}
def deviceCommand() {
def device = authorizedDevices()[params.type].find { it.id == params.id }
def command = params.command
if (!device) {
httpError(404, "Device not found")
} else {
if (params.value) {
device."$command"(params.value)
} else {
device."$command"()
}
}
}
mappings {
if (!params.access_token || (params.access_token && params.access_token != state.accessToken)) {
path("/devices") { action: [GET: "authError"] }
path("/config") { action: [GET: "authError"] }
path("/:type/:id/command/:command") { action: [PUT: "authError"] }
} else {
path("/devices") { action: [GET: "renderDevices"] }
path("/config") { action: [GET: "renderConfig"] }
path("/:type/:id/command/:command") { action: [PUT: "deviceCommand"] }
}
}
def authError() {
[error: "Permission denied"]
}

View File

@@ -15,13 +15,12 @@
* for the specific language governing permissions and limitations under the License. * for the specific language governing permissions and limitations under the License.
* *
*/ */
include 'localization'
definition( definition(
name: "Hue (Connect)", name: "Hue (Connect)",
namespace: "smartthings", namespace: "smartthings",
author: "SmartThings", author: "SmartThings",
description: "Allows you to connect your Philips Hue lights with SmartThings and control them from your Things area or Dashboard in the SmartThings Mobile app. Please update your Hue Bridge first, outside of the SmartThings app, using the Philips Hue app.", description: "Allows you to connect your Philips Hue lights with SmartThings and control them from your Things area or Dashboard in the SmartThings Mobile app. Adjust colors by going to the Thing detail screen for your Hue lights (tap the gear on Hue tiles).\n\nPlease update your Hue Bridge first, outside of the SmartThings app, using the Philips Hue app.",
category: "SmartThings Labs", category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png", iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png", iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png",
@@ -29,11 +28,11 @@ definition(
) )
preferences { preferences {
page(name: "mainPage", title: "", content: "mainPage", refreshTimeout: 5) page(name:"mainPage", title:"Hue Device Setup", content:"mainPage", refreshTimeout:5)
page(name: "bridgeDiscovery", title: "", content: "bridgeDiscovery", refreshTimeout: 5) page(name:"bridgeDiscovery", title:"Hue Bridge Discovery", content:"bridgeDiscovery", refreshTimeout:5)
page(name: "bridgeDiscoveryFailed", title: "", content: "bridgeDiscoveryFailed", refreshTimeout: 0) page(name:"bridgeDiscoveryFailed", title:"Bridge Discovery Failed", content:"bridgeDiscoveryFailed", refreshTimeout:0)
page(name: "bridgeBtnPush", title: "", content: "bridgeLinking", refreshTimeout: 5) page(name:"bridgeBtnPush", title:"Linking with your Hue", content:"bridgeLinking", refreshTimeout:5)
page(name: "bulbDiscovery", title: "", content: "bulbDiscovery", refreshTimeout: 5) page(name:"bulbDiscovery", title:"Hue Device Setup", content:"bulbDiscovery", refreshTimeout:5)
} }
def mainPage() { def mainPage() {
@@ -48,14 +47,15 @@ def mainPage() {
} }
} }
def bridgeDiscovery(params = [:]) { def bridgeDiscovery(params=[:])
{
def bridges = bridgesDiscovered() def bridges = bridgesDiscovered()
int bridgeRefreshCount = !state.bridgeRefreshCount ? 0 : state.bridgeRefreshCount as int int bridgeRefreshCount = !state.bridgeRefreshCount ? 0 : state.bridgeRefreshCount as int
state.bridgeRefreshCount = bridgeRefreshCount + 1 state.bridgeRefreshCount = bridgeRefreshCount + 1
def refreshInterval = 3 def refreshInterval = 3
def options = bridges ?: [] def options = bridges ?: []
def numFound = options.size() ?: "0" def numFound = options.size() ?: 0
if (numFound == 0) { if (numFound == 0) {
if (state.bridgeRefreshCount == 25) { if (state.bridgeRefreshCount == 25) {
log.trace "Cleaning old bridges memory" log.trace "Cleaning old bridges memory"
@@ -75,26 +75,25 @@ def bridgeDiscovery(params = [:]) {
ssdpSubscribe() ssdpSubscribe()
//bridge discovery request every 15 //25 seconds //bridge discovery request every 15 //25 seconds
if ((bridgeRefreshCount % 5) == 0) { if((bridgeRefreshCount % 5) == 0) {
discoverBridges() discoverBridges()
} }
//setup.xml request every 3 seconds except on discoveries //setup.xml request every 3 seconds except on discoveries
if (((bridgeRefreshCount % 3) == 0) && ((bridgeRefreshCount % 5) != 0)) { if(((bridgeRefreshCount % 3) == 0) && ((bridgeRefreshCount % 5) != 0)) {
verifyHueBridges() verifyHueBridges()
} }
return dynamicPage(name: "bridgeDiscovery", title: "Discovery Started!", nextPage: "bridgeBtnPush", refreshInterval: refreshInterval, uninstall: true) { return dynamicPage(name:"bridgeDiscovery", title:"Discovery Started!", nextPage:"bridgeBtnPush", refreshInterval:refreshInterval, uninstall: true) {
section("Please wait while we discover your Hue Bridge. Kindly note that you must first configure your Hue Bridge and Lights using the Philips Hue application. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") { section("Please wait while we discover your Hue Bridge. Kindly note that you must first configure your Hue Bridge and Lights using the Philips Hue application. " +
"Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
input "selectedHue", "enum", required:false, title:"Select Hue Bridge (${numFound} found)", multiple:false, options:options, submitOnChange: true
input(name: "selectedHue", type: "enum", required: false, title: "Select Hue Bridge ({{numFound}} found)", messageArgs: [numFound: numFound], multiple: false, options: options, submitOnChange: true)
} }
} }
} }
def bridgeDiscoveryFailed() { def bridgeDiscoveryFailed() {
return dynamicPage(name: "bridgeDiscoveryFailed", title: "Bridge Discovery Failed!", nextPage: "bridgeDiscovery") { return dynamicPage(name:"bridgeDiscoveryFailed", title: "Bridge Discovery Failed", nextPage: "bridgeDiscovery") {
section("Failed to discover any Hue Bridges. Please confirm that the Hue Bridge is connected to the same network as your SmartThings Hub, and that it has power.") { section("Failed to discover any Hue Bridges. Please confirm that the Hue Bridge is connected to the same network as your SmartThings Hub, and that it has power.") {
} }
} }
@@ -110,12 +109,12 @@ def bridgeLinking() {
def paragraphText def paragraphText
if (selectedHue) { if (selectedHue) {
if (state.refreshUsernameNeeded) { if (state.refreshUsernameNeeded) {
paragraphText = "The current Hue username is invalid. Please press the button on your Hue Bridge to relink." paragraphText = "The current Hue username is invalid.\n\nPlease press the button on your Hue Bridge to re-link. "
} else { } else {
paragraphText = "Press the button on your Hue Bridge to setup a link." paragraphText = "Press the button on your Hue Bridge to setup a link. "
} }
} else { } else {
paragraphText = "You haven't selected a Hue Bridge, please Press 'Done' and select one before clicking next." paragraphText = "You haven't selected a Hue Bridge, please Press \"Done\" and select one before clicking next."
} }
if (state.username) { //if discovery worked if (state.username) { //if discovery worked
if (state.refreshUsernameNeeded) { if (state.refreshUsernameNeeded) {
@@ -128,13 +127,13 @@ def bridgeLinking() {
paragraphText = "Linking to your hub was a success! Please click 'Next'!" paragraphText = "Linking to your hub was a success! Please click 'Next'!"
} }
if ((linkRefreshcount % 2) == 0 && !state.username) { if((linkRefreshcount % 2) == 0 && !state.username) {
sendDeveloperReq() sendDeveloperReq()
} }
return dynamicPage(name: "bridgeBtnPush", title: title, nextPage: nextPage, refreshInterval: refreshInterval) { return dynamicPage(name:"bridgeBtnPush", title:title, nextPage:nextPage, refreshInterval:refreshInterval) {
section("") { section("") {
paragraph "$paragraphText" paragraph """${paragraphText}"""
} }
} }
} }
@@ -150,18 +149,18 @@ def bulbDiscovery() {
def allLightsFound = bulbsDiscovered() ?: [:] def allLightsFound = bulbsDiscovered() ?: [:]
// List lights currently not added to the user (editable) // List lights currently not added to the user (editable)
def newLights = allLightsFound.findAll { getChildDevice(it.key) == null } ?: [:] def newLights = allLightsFound.findAll {getChildDevice(it.key) == null} ?: [:]
newLights = newLights.sort { it.value.toLowerCase() } newLights = newLights.sort {it.value.toLowerCase()}
// List lights already added to the user (not editable) // List lights already added to the user (not editable)
def existingLights = allLightsFound.findAll { getChildDevice(it.key) != null } ?: [:] def existingLights = allLightsFound.findAll {getChildDevice(it.key) != null} ?: [:]
existingLights = existingLights.sort { it.value.toLowerCase() } existingLights = existingLights.sort {it.value.toLowerCase()}
def numFound = newLights.size() ?: "0" def numFound = newLights.size() ?: 0
if (numFound == "0") if (numFound == 0)
app.updateSetting("selectedBulbs", "") app.updateSetting("selectedBulbs", "")
if ((bulbRefreshCount % 5) == 0) { if((bulbRefreshCount % 5) == 0) {
discoverHueBulbs() discoverHueBulbs()
} }
def selectedBridge = state.bridges.find { key, value -> value?.serialNumber?.equalsIgnoreCase(selectedHue) } def selectedBridge = state.bridges.find { key, value -> value?.serialNumber?.equalsIgnoreCase(selectedHue) }
@@ -179,14 +178,14 @@ def bulbDiscovery() {
} }
} }
def existingLightsSize = "${existingLights.size()}" if (bulbRefreshCount > 200 && numFound == 0) {
if (bulbRefreshCount > 200 && numFound == "0") {
// Time out after 10 minutes // Time out after 10 minutes
state.inBulbDiscovery = false state.inBulbDiscovery = false
bulbRefreshCount = 0 bulbRefreshCount = 0
return dynamicPage(name: "bulbDiscovery", title: "Light Discovery Failed!", nextPage: "", refreshInterval: 0, install: true, uninstall: true) { return dynamicPage(name:"bulbDiscovery", title:"Light Discovery Failed!", nextPage:"", refreshInterval:0, install:true, uninstall: true) {
section("Failed to discover any lights, please try again later. Click 'Done' to exit.") { section("Failed to discover any lights, please try again later. Click Done to exit.") {
paragraph title: "Previously added Hue Lights ({{existingLightsSize}} added)", messageArgs: [existingLightsSize: existingLightsSize], existingLightsDescription //input "selectedBulbs", "enum", required:false, title:"Select Hue Lights to add (${numFound} found)", multiple:true, submitOnChange: true, options:newLights
paragraph title: "Previously added Hue Lights (${existingLights.size()} added)", existingLightsDescription
} }
section { section {
href "bridgeDiscovery", title: title, description: "", state: selectedHue ? "complete" : "incomplete", params: [override: true] href "bridgeDiscovery", title: title, description: "", state: selectedHue ? "complete" : "incomplete", params: [override: true]
@@ -194,10 +193,10 @@ def bulbDiscovery() {
} }
} else { } else {
return dynamicPage(name: "bulbDiscovery", title: "Light Discovery Started!", nextPage: "", refreshInterval: refreshInterval, install: true, uninstall: true) { return dynamicPage(name:"bulbDiscovery", title:"Light Discovery Started!", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) {
section("Please wait while we discover your Hue Lights. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") { section("Please wait while we discover your Hue Lights. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
input(name: "selectedBulbs", type: "enum", required: false, title: "Select Hue Lights to add ({{numFound}} found)", messageArgs: [numFound: numFound], multiple: true, submitOnChange: true, options: newLights) input "selectedBulbs", "enum", required:false, title:"Select Hue Lights to add (${numFound} found)", multiple:true, submitOnChange: true, options:newLights
paragraph title: "Previously added Hue Lights ({{existingLightsSize}} added)", messageArgs: [existingLightsSize: existingLightsSize], existingLightsDescription paragraph title: "Previously added Hue Lights (${existingLights.size()} added)", existingLightsDescription
} }
section { section {
href "bridgeDiscovery", title: title, description: "", state: selectedHue ? "complete" : "incomplete", params: [override: true] href "bridgeDiscovery", title: title, description: "", state: selectedHue ? "complete" : "incomplete", params: [override: true]
@@ -218,19 +217,19 @@ private sendDeveloperReq() {
def token = app.id def token = app.id
def host = getBridgeIP() def host = getBridgeIP()
sendHubCommand(new physicalgraph.device.HubAction([ sendHubCommand(new physicalgraph.device.HubAction([
method : "POST", method: "POST",
path : "/api", path: "/api",
headers: [ headers: [
HOST: host HOST: host
], ],
body : [devicetype: "$token-0"]], "${selectedHue}", [callback: "usernameHandler"])) body: [devicetype: "$token-0"]], "${selectedHue}", [callback: "usernameHandler"]))
} }
private discoverHueBulbs() { private discoverHueBulbs() {
def host = getBridgeIP() def host = getBridgeIP()
sendHubCommand(new physicalgraph.device.HubAction([ sendHubCommand(new physicalgraph.device.HubAction([
method : "GET", method: "GET",
path : "/api/${state.username}/lights", path: "/api/${state.username}/lights",
headers: [ headers: [
HOST: host HOST: host
]], "${selectedHue}", [callback: "lightsHandler"])) ]], "${selectedHue}", [callback: "lightsHandler"]))
@@ -239,8 +238,8 @@ private discoverHueBulbs() {
private verifyHueBridge(String deviceNetworkId, String host) { private verifyHueBridge(String deviceNetworkId, String host) {
log.trace "Verify Hue Bridge $deviceNetworkId" log.trace "Verify Hue Bridge $deviceNetworkId"
sendHubCommand(new physicalgraph.device.HubAction([ sendHubCommand(new physicalgraph.device.HubAction([
method : "GET", method: "GET",
path : "/description.xml", path: "/description.xml",
headers: [ headers: [
HOST: host HOST: host
]], deviceNetworkId, [callback: "bridgeDescriptionHandler"])) ]], deviceNetworkId, [callback: "bridgeDescriptionHandler"]))
@@ -267,18 +266,18 @@ Map bridgesDiscovered() {
} }
Map bulbsDiscovered() { Map bulbsDiscovered() {
def bulbs = getHueBulbs() def bulbs = getHueBulbs()
def bulbmap = [:] def bulbmap = [:]
if (bulbs instanceof java.util.Map) { if (bulbs instanceof java.util.Map) {
bulbs.each { bulbs.each {
def value = "${it.value.name}" def value = "${it.value.name}"
def key = app.id + "/" + it.value.id def key = app.id +"/"+ it.value.id
bulbmap["${key}"] = value bulbmap["${key}"] = value
} }
} else { //backwards compatable } else { //backwards compatable
bulbs.each { bulbs.each {
def value = "${it.name}" def value = "${it.name}"
def key = app.id + "/" + it.id def key = app.id +"/"+ it.id
logg += "$value - $key, " logg += "$value - $key, "
bulbmap["${key}"] = value bulbmap["${key}"] = value
} }
@@ -295,7 +294,7 @@ def getHueBridges() {
} }
def getVerifiedHueBridges() { def getVerifiedHueBridges() {
getHueBridges().findAll { it?.value?.verified == true } getHueBridges().findAll{ it?.value?.verified == true }
} }
def installed() { def installed() {
@@ -332,7 +331,7 @@ def manualRefresh() {
poll() poll()
} }
def uninstalled() { def uninstalled(){
// Remove bridgedevice connection to allow uninstall of smartapp even though bridge is listed // Remove bridgedevice connection to allow uninstall of smartapp even though bridge is listed
// as user of smartapp // as user of smartapp
app.updateSetting("bridgeDevice", null) app.updateSetting("bridgeDevice", null)
@@ -372,7 +371,7 @@ private getDeviceType(hueType) {
return null return null
} }
private addChildBulb(dni, hueType, name, hub, update = false, device = null) { private addChildBulb(dni, hueType, name, hub, update=false, device = null) {
def deviceType = getDeviceType(hueType) def deviceType = getDeviceType(hueType)
if (deviceType) { if (deviceType) {
@@ -387,7 +386,7 @@ def addBulbs() {
def bulbs = getHueBulbs() def bulbs = getHueBulbs()
selectedBulbs?.each { dni -> selectedBulbs?.each { dni ->
def d = getChildDevice(dni) def d = getChildDevice(dni)
if (!d) { if(!d) {
def newHueBulb def newHueBulb
if (bulbs instanceof java.util.Map) { if (bulbs instanceof java.util.Map) {
newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni } newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni }
@@ -420,11 +419,11 @@ def addBulbs() {
def addBridge() { def addBridge() {
def vbridges = getVerifiedHueBridges() def vbridges = getVerifiedHueBridges()
def vbridge = vbridges.find { "${it.value.mac}" == selectedHue } def vbridge = vbridges.find {"${it.value.mac}" == selectedHue}
if (vbridge) { if(vbridge) {
def d = getChildDevice(selectedHue) def d = getChildDevice(selectedHue)
if (!d) { if(!d) {
// compatibility with old devices // compatibility with old devices
def newbridge = true def newbridge = true
childDevices.each { childDevices.each {
@@ -459,15 +458,15 @@ def addBridge() {
childDevice?.sendEvent(name: "idNumber", value: idNumber) childDevice?.sendEvent(name: "idNumber", value: idNumber)
if (vbridge.value.ip && vbridge.value.port) { if (vbridge.value.ip && vbridge.value.port) {
if (vbridge.value.ip.contains(".")) { if (vbridge.value.ip.contains(".")) {
childDevice.sendEvent(name: "networkAddress", value: vbridge.value.ip + ":" + vbridge.value.port) childDevice.sendEvent(name: "networkAddress", value: vbridge.value.ip + ":" + vbridge.value.port)
childDevice.updateDataValue("networkAddress", vbridge.value.ip + ":" + vbridge.value.port) childDevice.updateDataValue("networkAddress", vbridge.value.ip + ":" + vbridge.value.port)
} else { } else {
childDevice.sendEvent(name: "networkAddress", value: convertHexToIP(vbridge.value.ip) + ":" + convertHexToInt(vbridge.value.port)) childDevice.sendEvent(name: "networkAddress", value: convertHexToIP(vbridge.value.ip) + ":" + convertHexToInt(vbridge.value.port))
childDevice.updateDataValue("networkAddress", convertHexToIP(vbridge.value.ip) + ":" + convertHexToInt(vbridge.value.port)) childDevice.updateDataValue("networkAddress", convertHexToIP(vbridge.value.ip) + ":" + convertHexToInt(vbridge.value.port))
} }
} else { } else {
childDevice.sendEvent(name: "networkAddress", value: convertHexToIP(vbridge.value.networkAddress) + ":" + convertHexToInt(vbridge.value.deviceAddress)) childDevice.sendEvent(name: "networkAddress", value: convertHexToIP(vbridge.value.networkAddress) + ":" + convertHexToInt(vbridge.value.deviceAddress))
childDevice.updateDataValue("networkAddress", convertHexToIP(vbridge.value.networkAddress) + ":" + convertHexToInt(vbridge.value.deviceAddress)) childDevice.updateDataValue("networkAddress", convertHexToIP(vbridge.value.networkAddress) + ":" + convertHexToInt(vbridge.value.deviceAddress))
} }
} else { } else {
log.error "Failed to create Hue Bridge device" log.error "Failed to create Hue Bridge device"
@@ -485,14 +484,14 @@ def ssdpBridgeHandler(evt) {
def hub = evt?.hubId def hub = evt?.hubId
def parsedEvent = parseLanMessage(description) def parsedEvent = parseLanMessage(description)
parsedEvent << ["hub": hub] parsedEvent << ["hub":hub]
def bridges = getHueBridges() def bridges = getHueBridges()
log.trace bridges.toString() log.trace bridges.toString()
if (!(bridges."${parsedEvent.ssdpUSN.toString()}")) { if (!(bridges."${parsedEvent.ssdpUSN.toString()}")) {
//bridge does not exist //bridge does not exist
log.trace "Adding bridge ${parsedEvent.ssdpUSN}" log.trace "Adding bridge ${parsedEvent.ssdpUSN}"
bridges << ["${parsedEvent.ssdpUSN.toString()}": parsedEvent] bridges << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
} else { } else {
// update the values // update the values
def ip = convertHexToIP(parsedEvent.networkAddress) def ip = convertHexToIP(parsedEvent.networkAddress)
@@ -513,7 +512,7 @@ def ssdpBridgeHandler(evt) {
bridge.setDeviceNetworkId("${dniReceived}") bridge.setDeviceNetworkId("${dniReceived}")
dstate.mac = dniReceived dstate.mac = dniReceived
// Check to see if selectedHue is a valid bridge, otherwise update it // Check to see if selectedHue is a valid bridge, otherwise update it
def isSelectedValid = bridges?.find { it.value?.mac == selectedHue } def isSelectedValid = bridges?.find {it.value?.mac == selectedHue}
if (isSelectedValid == null) { if (isSelectedValid == null) {
log.warn "Correcting selectedHue in state" log.warn "Correcting selectedHue in state"
app.updateSetting("selectedHue", dniReceived) app.updateSetting("selectedHue", dniReceived)
@@ -533,7 +532,7 @@ def ssdpBridgeHandler(evt) {
dstate.ip = ip dstate.ip = ip
dstate.port = port dstate.port = port
dstate.name = "Philips hue ($ip)" dstate.name = "Philips hue ($ip)"
d.sendEvent(name: "networkAddress", value: host) d.sendEvent(name:"networkAddress", value: host)
d.updateDataValue("networkAddress", host) d.updateDataValue("networkAddress", host)
} }
if (dstate.mac != dniReceived) { if (dstate.mac != dniReceived) {
@@ -542,7 +541,7 @@ def ssdpBridgeHandler(evt) {
} }
if (selectedHue != dniReceived) { if (selectedHue != dniReceived) {
// Check to see if selectedHue is a valid bridge, otherwise update it // Check to see if selectedHue is a valid bridge, otherwise update it
def isSelectedValid = bridges?.find { it.value?.mac == selectedHue } def isSelectedValid = bridges?.find {it.value?.mac == selectedHue}
if (isSelectedValid == null) { if (isSelectedValid == null) {
log.warn "Correcting selectedHue in state" log.warn "Correcting selectedHue in state"
app.updateSetting("selectedHue", dniReceived) app.updateSetting("selectedHue", dniReceived)
@@ -557,7 +556,7 @@ void bridgeDescriptionHandler(physicalgraph.device.HubResponse hubResponse) {
def body = hubResponse.xml def body = hubResponse.xml
if (body?.device?.modelName?.text()?.startsWith("Philips hue bridge")) { if (body?.device?.modelName?.text()?.startsWith("Philips hue bridge")) {
def bridges = getHueBridges() def bridges = getHueBridges()
def bridge = bridges.find { it?.key?.contains(body?.device?.UDN?.text()) } def bridge = bridges.find {it?.key?.contains(body?.device?.UDN?.text())}
if (bridge) { if (bridge) {
def idNumber = getBridgeIdNumber(body?.device?.serialNumber?.text()) def idNumber = getBridgeIdNumber(body?.device?.serialNumber?.text())
@@ -566,10 +565,10 @@ void bridgeDescriptionHandler(physicalgraph.device.HubResponse hubResponse) {
def name = body?.device?.friendlyName?.text() def name = body?.device?.friendlyName?.text()
def index = name?.indexOf('(') def index = name?.indexOf('(')
if (index != -1) { if (index != -1) {
name = name.substring(0, index) name = name.substring(0,index)
name += " ($idNumber)" name += " ($idNumber)"
} }
bridge.value << [name: name, serialNumber: body?.device?.serialNumber?.text(), idNumber: idNumber, verified: true] bridge.value << [name:name, serialNumber:body?.device?.serialNumber?.text(), idNumber: idNumber, verified: true]
} else { } else {
log.error "/description.xml returned a bridge that didn't exist" log.error "/description.xml returned a bridge that didn't exist"
} }
@@ -612,7 +611,7 @@ def locationHandler(evt) {
def hub = evt?.hubId def hub = evt?.hubId
def parsedEvent = parseLanMessage(description) def parsedEvent = parseLanMessage(description)
parsedEvent << ["hub": hub] parsedEvent << ["hub":hub]
if (parsedEvent?.ssdpTerm?.contains("urn:schemas-upnp-org:device:basic:1")) { if (parsedEvent?.ssdpTerm?.contains("urn:schemas-upnp-org:device:basic:1")) {
//SSDP DISCOVERY EVENTS //SSDP DISCOVERY EVENTS
@@ -622,7 +621,7 @@ def locationHandler(evt) {
if (!(bridges."${parsedEvent.ssdpUSN.toString()}")) { if (!(bridges."${parsedEvent.ssdpUSN.toString()}")) {
//bridge does not exist //bridge does not exist
log.trace "Adding bridge ${parsedEvent.ssdpUSN}" log.trace "Adding bridge ${parsedEvent.ssdpUSN}"
bridges << ["${parsedEvent.ssdpUSN.toString()}": parsedEvent] bridges << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
} else { } else {
// update the values // update the values
def ip = convertHexToIP(parsedEvent.networkAddress) def ip = convertHexToIP(parsedEvent.networkAddress)
@@ -657,12 +656,12 @@ def locationHandler(evt) {
networkAddress = d.latestState('networkAddress').stringValue networkAddress = d.latestState('networkAddress').stringValue
} }
log.trace "Host: $host - $networkAddress" log.trace "Host: $host - $networkAddress"
if (host != networkAddress) { if(host != networkAddress) {
log.debug "Device's port or ip changed for device $d..." log.debug "Device's port or ip changed for device $d..."
dstate.ip = ip dstate.ip = ip
dstate.port = port dstate.port = port
dstate.name = "Philips hue ($ip)" dstate.name = "Philips hue ($ip)"
d.sendEvent(name: "networkAddress", value: host) d.sendEvent(name:"networkAddress", value: host)
d.updateDataValue("networkAddress", host) d.updateDataValue("networkAddress", host)
} }
} }
@@ -675,14 +674,14 @@ def locationHandler(evt) {
def body = new XmlSlurper().parseText(parsedEvent.body) def body = new XmlSlurper().parseText(parsedEvent.body)
if (body?.device?.modelName?.text().startsWith("Philips hue bridge")) { if (body?.device?.modelName?.text().startsWith("Philips hue bridge")) {
def bridges = getHueBridges() def bridges = getHueBridges()
def bridge = bridges.find { it?.key?.contains(body?.device?.UDN?.text()) } def bridge = bridges.find {it?.key?.contains(body?.device?.UDN?.text())}
if (bridge) { if (bridge) {
bridge.value << [name: body?.device?.friendlyName?.text(), serialNumber: body?.device?.serialNumber?.text(), verified: true] bridge.value << [name:body?.device?.friendlyName?.text(), serialNumber:body?.device?.serialNumber?.text(), verified: true]
} else { } else {
log.error "/description.xml returned a bridge that didn't exist" log.error "/description.xml returned a bridge that didn't exist"
} }
} }
} else if (headerString?.contains("json") && isValidSource(parsedEvent.mac)) { } else if(headerString?.contains("json") && isValidSource(parsedEvent.mac)) {
log.trace "description.xml response (application/json)" log.trace "description.xml response (application/json)"
def body = new groovy.json.JsonSlurper().parseText(parsedEvent.body) def body = new groovy.json.JsonSlurper().parseText(parsedEvent.body)
if (body.success != null) { if (body.success != null) {
@@ -707,7 +706,7 @@ def locationHandler(evt) {
} }
} }
def doDeviceSync() { def doDeviceSync(){
log.trace "Doing Hue Device Sync!" log.trace "Doing Hue Device Sync!"
// Check if state.updating failed to clear // Check if state.updating failed to clear
@@ -788,7 +787,7 @@ private void checkBridgeStatus() {
def isValidSource(macAddress) { def isValidSource(macAddress) {
def vbridges = getVerifiedHueBridges() def vbridges = getVerifiedHueBridges()
return (vbridges?.find { "${it.value.mac}" == macAddress }) != null return (vbridges?.find {"${it.value.mac}" == macAddress}) != null
} }
def isInBulbDiscovery() { def isInBulbDiscovery() {
@@ -802,19 +801,19 @@ private updateBulbState(messageBody, hub) {
def toRemove = [:] def toRemove = [:]
toRemove << bulbs toRemove << bulbs
messageBody.each { k, v -> messageBody.each { k,v ->
if (v instanceof Map) { if (v instanceof Map) {
if (bulbs[k] == null) { if (bulbs[k] == null) {
bulbs[k] = [:] bulbs[k] = [:]
} }
bulbs[k] << [id: k, name: v.name, type: v.type, modelid: v.modelid, hub: hub, remove: false] bulbs[k] << [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:hub, remove: false]
toRemove.remove(k) toRemove.remove(k)
} }
} }
// Remove bulbs from state that are no longer discovered // Remove bulbs from state that are no longer discovered
toRemove.each { k, v -> toRemove.each { k,v ->
log.warn "${bulbs[k].name} no longer exists on bridge, removing" log.warn "${bulbs[k].name} no longer exists on bridge, removing"
bulbs.remove(k) bulbs.remove(k)
} }
@@ -938,11 +937,12 @@ private sendBasicEvents(device, param, value) {
* *
* Example payload * Example payload
* [, * [,
*{"success":{"/lights/5/state/bri":87}}, * {"success":{"/lights/5/state/bri":87}},
*{"success":{"/lights/5/state/transitiontime":4}}, * {"success":{"/lights/5/state/transitiontime":4}},
*{"success":{"/lights/5/state/on":true}}, * {"success":{"/lights/5/state/on":true}},
*{"success":{"/lights/5/state/xy":[0.4152,0.5336]}}, * {"success":{"/lights/5/state/xy":[0.4152,0.5336]}},
*{"success":{"/lights/5/state/alert":"none"}}* ] * {"success":{"/lights/5/state/alert":"none"}}
* ]
* *
* @param body a data structure of lists and maps based on a JSON data * @param body a data structure of lists and maps based on a JSON data
* @return empty array * @return empty array
@@ -995,7 +995,7 @@ private handleCommandResponse(body) {
* *
* Example payload * Example payload
* *
*{"5":{"state": {"on":true,"bri":102,"hue":25600,"sat":254,"effect":"none","xy":[0.1700,0.7000],"ct":153,"alert":"none", * {"5":{"state": {"on":true,"bri":102,"hue":25600,"sat":254,"effect":"none","xy":[0.1700,0.7000],"ct":153,"alert":"none",
* "colormode":"xy","reachable":true}, "type": "Extended color light", "name": "Go", "modelid": "LLC020", "manufacturername": "Philips", * "colormode":"xy","reachable":true}, "type": "Extended color light", "name": "Go", "modelid": "LLC020", "manufacturername": "Philips",
* "uniqueid":"00:17:88:01:01:13:d5:11-0b", "swversion": "5.38.1.14378"}, * "uniqueid":"00:17:88:01:01:13:d5:11-0b", "swversion": "5.38.1.14378"},
* "6":{"state": {"on":true,"bri":103,"hue":14910,"sat":144,"effect":"none","xy":[0.4596,0.4105],"ct":370,"alert":"none", * "6":{"state": {"on":true,"bri":103,"hue":14910,"sat":144,"effect":"none","xy":[0.4596,0.4105],"ct":370,"alert":"none",
@@ -1069,9 +1069,9 @@ def hubVerification(bodytext) {
def body = new XmlSlurper().parseText(bodytext) def body = new XmlSlurper().parseText(bodytext)
if (body?.device?.modelName?.text().startsWith("Philips hue bridge")) { if (body?.device?.modelName?.text().startsWith("Philips hue bridge")) {
def bridges = getHueBridges() def bridges = getHueBridges()
def bridge = bridges.find { it?.key?.contains(body?.device?.UDN?.text()) } def bridge = bridges.find {it?.key?.contains(body?.device?.UDN?.text())}
if (bridge) { if (bridge) {
bridge.value << [name: body?.device?.friendlyName?.text(), serialNumber: body?.device?.serialNumber?.text(), verified: true] bridge.value << [name:body?.device?.friendlyName?.text(), serialNumber:body?.device?.serialNumber?.text(), verified: true]
} else { } else {
log.error "/description.xml returned a bridge that didn't exist" log.error "/description.xml returned a bridge that didn't exist"
} }
@@ -1107,7 +1107,7 @@ def setLevel(childDevice, percent) {
else else
level = Math.min(Math.round(percent * 254 / 100), 254) level = Math.min(Math.round(percent * 254 / 100), 254)
createSwitchEvent(childDevice, level > 0, percent) createSwitchEvent(childDevice, level > 0 ,percent)
// For Zigbee lights, if level is set to 0 ST just turns them off without changing level // For Zigbee lights, if level is set to 0 ST just turns them off without changing level
// that means that the light will still be on when on is called next time // that means that the light will still be on when on is called next time
@@ -1137,7 +1137,7 @@ def setHue(childDevice, percent) {
def id = getId(childDevice) def id = getId(childDevice)
updateInProgress() updateInProgress()
// 0 - 65535 // 0 - 65535
def level = Math.min(Math.round(percent * 65535 / 100), 65535) def level = Math.min(Math.round(percent * 65535 / 100), 65535)
// TODO should this be done by app only or should we default to on? // TODO should this be done by app only or should we default to on?
createSwitchEvent(childDevice, "on") createSwitchEvent(childDevice, "on")
put("lights/$id/state", [hue: level, on: true]) put("lights/$id/state", [hue: level, on: true])
@@ -1149,7 +1149,7 @@ def setColorTemperature(childDevice, huesettings) {
def id = getId(childDevice) def id = getId(childDevice)
updateInProgress() updateInProgress()
// 153 (6500K) to 500 (2000K) // 153 (6500K) to 500 (2000K)
def ct = hueSettings == 6500 ? 153 : Math.round(1000000 / huesettings) def ct = hueSettings == 6500 ? 153 : Math.round(1000000/huesettings)
createSwitchEvent(childDevice, "on") createSwitchEvent(childDevice, "on")
put("lights/$id/state", [ct: ct, on: true]) put("lights/$id/state", [ct: ct, on: true])
return "Setting color temperature to $ct" return "Setting color temperature to $ct"
@@ -1267,7 +1267,7 @@ private getBridgeIP() {
def d = getChildDevice(selectedHue) def d = getChildDevice(selectedHue)
if (d) { if (d) {
if (d.getDeviceDataByName("networkAddress")) if (d.getDeviceDataByName("networkAddress"))
host = d.getDeviceDataByName("networkAddress") host = d.getDeviceDataByName("networkAddress")
else else
host = d.latestState('networkAddress').stringValue host = d.latestState('networkAddress').stringValue
} }
@@ -1291,26 +1291,26 @@ private getBridgeIP() {
} }
private Integer convertHexToInt(hex) { private Integer convertHexToInt(hex) {
Integer.parseInt(hex, 16) Integer.parseInt(hex,16)
} }
def convertBulbListToMap() { def convertBulbListToMap() {
try { try {
if (state.bulbs instanceof java.util.List) { if (state.bulbs instanceof java.util.List) {
def map = [:] def map = [:]
state.bulbs?.unique { it.id }.each { bulb -> state.bulbs?.unique {it.id}.each { bulb ->
map << ["${bulb.id}": ["id": bulb.id, "name": bulb.name, "type": bulb.type, "modelid": bulb.modelid, "hub": bulb.hub, "online": bulb.online]] map << ["${bulb.id}":["id":bulb.id, "name":bulb.name, "type": bulb.type, "modelid": bulb.modelid, "hub":bulb.hub, "online": bulb.online]]
} }
state.bulbs = map state.bulbs = map
} }
} }
catch (Exception e) { catch(Exception e) {
log.error "Caught error attempting to convert bulb list to map: $e" log.error "Caught error attempting to convert bulb list to map: $e"
} }
} }
private String convertHexToIP(hex) { private String convertHexToIP(hex) {
[convertHexToInt(hex[0..1]), convertHexToInt(hex[2..3]), convertHexToInt(hex[4..5]), convertHexToInt(hex[6..7])].join(".") [convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
} }
private Boolean hasAllHubsOver(String desiredFirmware) { private Boolean hasAllHubsOver(String desiredFirmware) {
@@ -1327,7 +1327,7 @@ private List getRealHubFirmwareVersions() {
* @param childDevice device to send event for * @param childDevice device to send event for
* @param setSwitch The new switch state, "on" or "off" * @param setSwitch The new switch state, "on" or "off"
* @param setLevel Optional, switchLevel between 0-100, used if you set level to 0 for example since * @param setLevel Optional, switchLevel between 0-100, used if you set level to 0 for example since
* that should generate "off" instead of level change * that should generate "off" instead of level change
*/ */
private void createSwitchEvent(childDevice, setSwitch, setLevel = null) { private void createSwitchEvent(childDevice, setSwitch, setLevel = null) {
@@ -1358,7 +1358,7 @@ private void createSwitchEvent(childDevice, setSwitch, setLevel = null) {
private colorPointsForModel(model = null) { private colorPointsForModel(model = null) {
def result = null def result = null
switch (model) { switch (model) {
// Gamut A // Gamut A
case "LLC001": /* Monet, Renoir, Mondriaan (gen II) */ case "LLC001": /* Monet, Renoir, Mondriaan (gen II) */
case "LLC005": /* Bloom (gen II) */ case "LLC005": /* Bloom (gen II) */
case "LLC006": /* Iris (gen III) */ case "LLC006": /* Iris (gen III) */
@@ -1368,21 +1368,21 @@ private colorPointsForModel(model = null) {
case "LLC013": /* Storylight */ case "LLC013": /* Storylight */
case "LST001": /* Light Strips */ case "LST001": /* Light Strips */
case "LLC010": /* Hue Living Colors Iris + */ case "LLC010": /* Hue Living Colors Iris + */
result = [r: [x: 0.704f, y: 0.296f], g: [x: 0.2151f, y: 0.7106f], b: [x: 0.138f, y: 0.08f]]; result = [r:[x: 0.704f, y: 0.296f], g:[x: 0.2151f, y: 0.7106f], b:[x: 0.138f, y: 0.08f]];
break break
// Gamut C // Gamut C
case "LLC020": /* Hue Go */ case "LLC020": /* Hue Go */
case "LST002": /* Hue LightStrips Plus */ case "LST002": /* Hue LightStrips Plus */
result = [r: [x: 0.692f, y: 0.308f], g: [x: 0.17f, y: 0.7f], b: [x: 0.153f, y: 0.048f]]; result = [r:[x: 0.692f, y: 0.308f], g:[x: 0.17f, y: 0.7f], b:[x: 0.153f, y: 0.048f]];
break break
// Gamut B // Gamut B
case "LCT001": /* Hue A19 */ case "LCT001": /* Hue A19 */
case "LCT002": /* Hue BR30 */ case "LCT002": /* Hue BR30 */
case "LCT003": /* Hue GU10 */ case "LCT003": /* Hue GU10 */
case "LCT007": /* Hue A19 + */ case "LCT007": /* Hue A19 + */
case "LLM001": /* Color Light Module + */ case "LLM001": /* Color Light Module + */
default: default:
result = [r: [x: 0.675f, y: 0.322f], g: [x: 0.4091f, y: 0.518f], b: [x: 0.167f, y: 0.04f]]; result = [r:[x: 0.675f, y: 0.322f], g:[x: 0.4091f, y: 0.518f], b:[x: 0.167f, y: 0.04f]];
} }
return result; return result;
@@ -1401,9 +1401,9 @@ private colorPointsForModel(model = null) {
private float[] calculateXY(colorStr, model = null) { private float[] calculateXY(colorStr, model = null) {
// #ffa013 // #ffa013
def cred = Integer.valueOf(colorStr.substring(1, 3), 16) def cred = Integer.valueOf( colorStr.substring( 1, 3 ), 16 )
def cgreen = Integer.valueOf(colorStr.substring(3, 5), 16) def cgreen = Integer.valueOf( colorStr.substring( 3, 5 ), 16 )
def cblue = Integer.valueOf(colorStr.substring(5, 7), 16) def cblue = Integer.valueOf( colorStr.substring( 5, 7 ), 16 )
float red = cred / 255.0f; float red = cred / 255.0f;
float green = cgreen / 255.0f; float green = cgreen / 255.0f;
@@ -1473,6 +1473,7 @@ private float[] calculateXY(colorStr, model = null) {
// xy[0] = PHHueHelper.precision(4, xy[0]); // xy[0] = PHHueHelper.precision(4, xy[0]);
// xy[1] = PHHueHelper.precision(4, xy[1]); // xy[1] = PHHueHelper.precision(4, xy[1]);
// TODO needed, assume it just sets number of decimals? // TODO needed, assume it just sets number of decimals?
//xy[0] = PHHueHelper.precision(xy[0]); //xy[0] = PHHueHelper.precision(xy[0]);
//xy[1] = PHHueHelper.precision(xy[1]); //xy[1] = PHHueHelper.precision(xy[1]);
@@ -1488,10 +1489,10 @@ private float[] calculateXY(colorStr, model = null) {
* *
* @param points the float array contain x and the y value. [x,y] * @param points the float array contain x and the y value. [x,y]
* @param model the model of the lamp, example: "LCT001" for hue bulb. Used to calculate the color gamut. * @param model the model of the lamp, example: "LCT001" for hue bulb. Used to calculate the color gamut.
* If this value is empty the default gamut values are used. * If this value is empty the default gamut values are used.
* @return the color value in hex (#ff03d3). If xy is null OR xy is not an array of size 2, Color. BLACK will be returned * @return the color value in hex (#ff03d3). If xy is null OR xy is not an array of size 2, Color. BLACK will be returned
*/ */
private String colorFromXY(points, model) { private String colorFromXY(points, model ) {
if (points == null || model == null) { if (points == null || model == null) {
log.warn "Input color missing" log.warn "Input color missing"
@@ -1549,9 +1550,9 @@ private String colorFromXY(points, model) {
// float b = X * 0.0556f - Y * 0.2040f + Z * 1.0570f; // float b = X * 0.0556f - Y * 0.2040f + Z * 1.0570f;
// sRGB D65 conversion // sRGB D65 conversion
float r = x2 * 1.656492f - y2 * 0.354851f - z2 * 0.255038f; float r = x2 * 1.656492f - y2 * 0.354851f - z2 * 0.255038f;
float g = -x2 * 0.707196f + y2 * 1.655397f + z2 * 0.036152f; float g = -x2 * 0.707196f + y2 * 1.655397f + z2 * 0.036152f;
float b = x2 * 0.051713f - y2 * 0.121364f + z2 * 1.011530f; float b = x2 * 0.051713f - y2 * 0.121364f + z2 * 1.011530f;
if (r > b && r > g && r > 1.0f) { if (r > b && r > g && r > 1.0f) {
// red is too big // red is too big
@@ -1613,6 +1614,7 @@ private String colorFromXY(points, model) {
return "#$r1$g1$b1" return "#$r1$g1$b1"
} }
/** /**
* Calculates crossProduct of two 2D vectors / points. * Calculates crossProduct of two 2D vectors / points.
* *
@@ -1641,8 +1643,8 @@ private getClosestPointToPoints(A, B, P) {
def AP = [x: (P.x - A.x), y: (P.y - A.y)]; def AP = [x: (P.x - A.x), y: (P.y - A.y)];
def AB = [x: (B.x - A.x), y: (B.y - A.y)]; def AB = [x: (B.x - A.x), y: (B.y - A.y)];
float ab2 = AB.x * AB.x + AB.y * AB.y; float ab2 = AB.x*AB.x + AB.y*AB.y;
float ap_ab = AP.x * AB.x + AP.y * AB.y; float ap_ab = AP.x*AB.x + AP.y*AB.y;
float t = ap_ab / ab2; float t = ap_ab / ab2;
@@ -1682,9 +1684,9 @@ private float getDistanceBetweenTwoPoints(one, two) {
*/ */
private boolean checkPointInLampsReach(p, colorPoints) { private boolean checkPointInLampsReach(p, colorPoints) {
def red = colorPoints.r; def red = colorPoints.r;
def green = colorPoints.g; def green = colorPoints.g;
def blue = colorPoints.b; def blue = colorPoints.b;
def v1 = [x: (green.x - red.x), y: (green.y - red.y)]; def v1 = [x: (green.x - red.x), y: (green.y - red.y)];
def v2 = [x: (blue.x - red.x), y: (blue.y - red.y)]; def v2 = [x: (blue.x - red.x), y: (blue.y - red.y)];
@@ -1694,9 +1696,12 @@ private boolean checkPointInLampsReach(p, colorPoints) {
float s = crossProduct(q, v2) / crossProduct(v1, v2); float s = crossProduct(q, v2) / crossProduct(v1, v2);
float t = crossProduct(v1, q) / crossProduct(v1, v2); float t = crossProduct(v1, q) / crossProduct(v1, v2);
if ((s >= 0.0f) && (t >= 0.0f) && (s + t <= 1.0f)) { if ( (s >= 0.0f) && (t >= 0.0f) && (s + t <= 1.0f))
{
return true; return true;
} else { }
else
{
return false; return false;
} }
} }
@@ -1709,10 +1714,10 @@ private boolean checkPointInLampsReach(p, colorPoints) {
* *
* @return HSV representation in an array (0-100) [hue, sat, value] * @return HSV representation in an array (0-100) [hue, sat, value]
*/ */
def hexToHsv(colorStr) { def hexToHsv(colorStr){
def r = Integer.valueOf(colorStr.substring(1, 3), 16) / 255 def r = Integer.valueOf( colorStr.substring( 1, 3 ), 16 ) / 255
def g = Integer.valueOf(colorStr.substring(3, 5), 16) / 255 def g = Integer.valueOf( colorStr.substring( 3, 5 ), 16 ) / 255
def b = Integer.valueOf(colorStr.substring(5, 7), 16) / 255 def b = Integer.valueOf( colorStr.substring( 5, 7 ), 16 ) / 255
def max = Math.max(Math.max(r, g), b) def max = Math.max(Math.max(r, g), b)
def min = Math.min(Math.min(r, g), b) def min = Math.min(Math.min(r, g), b)
@@ -1722,10 +1727,10 @@ def hexToHsv(colorStr) {
def d = max - min def d = max - min
s = max == 0 ? 0 : d / max s = max == 0 ? 0 : d / max
if (max == min) { if(max == min){
h = 0 h = 0
} else { }else{
switch (max) { switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break case r: h = (g - b) / d + (g < b ? 6 : 0); break
case g: h = (b - r) / d + 2; break case g: h = (b - r) / d + 2; break
case b: h = (r - g) / d + 4; break case b: h = (r - g) / d + 4; break
@@ -1740,13 +1745,13 @@ def hexToHsv(colorStr) {
* Converts HSV/HSB color to RGB in hex. * Converts HSV/HSB color to RGB in hex.
* Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space. * Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space.
* *
* @param hue hue 0-100 * @param hue hue 0-100
* @param sat saturation 0-100 * @param sat saturation 0-100
* @param value value 0-100 (defaults to 100) * @param value value 0-100 (defaults to 100)
* @return the color in hex (#ff03d3) * @return the color in hex (#ff03d3)
*/ */
def hsvToHex(hue, sat, value = 100) { def hsvToHex(hue, sat, value = 100){
def r, g, b; def r, g, b;
def h = hue / 100 def h = hue / 100
def s = sat / 100 def s = sat / 100
@@ -1798,3 +1803,4 @@ def hsvToHex(hue, sat, value = 100) {
return "#$r1$g1$b1" return "#$r1$g1$b1"
} }

View File

@@ -1,19 +0,0 @@
'''Allows you to connect your Philips Hue lights with SmartThings and control them from your Things area or Dashboard in the SmartThings Mobile app. Please update your Hue Bridge first, outside of the SmartThings app, using the Philips Hue app.'''=يوفر لك إمكانية توصيل مصابيح Philips Hue بـ SmartThings والتحكم بها من منطقة Things أو لوحة المعلومات في تطبيق SmartThings للهواتف المحمولة. يُرجى تحديث Hue Bridge أولاً، خارج تطبيق SmartThings، باستخدام تطبيق Philips Hue.
'''Discovery Started!'''=بدأ الاكتشاف!
'''Please wait while we discover your Hue Bridge. Kindly note that you must first configure your Hue Bridge and Lights using the Philips Hue application. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.'''=يُرجى الانتظار ريثما نكتشف Hue Bridge الخاص بك. تجدر الإشارة إلى أنه عليك أوّلاً تكوين Hue Bridge والمصابيح باستخدام تطبيق Philips Hue. قد يستغرق الاكتشاف خمس دقائق أو أكثر، لذا اجلس واسترخِ! اختر جهازك أدناه بمجرد اكتشافه.
'''Select Hue Bridge ({{numFound}} found)'''=تحديد Hue Bridge (تم العثور على {{numFound}})
'''Bridge Discovery Failed!'''=فشل اكتشاف Bridge
'''Failed to discover any Hue Bridges. Please confirm that the Hue Bridge is connected to the same network as your SmartThings Hub, and that it has power.'''=فشل اكتشاف أي Hue Bridges. يُرجى التأكد من اتصال Hue Bridge بالشبكة نفسها التي يتصل بها موزع SmartThings الخاص بك، ومن أنه متصل بمصدر طاقة أيضاً.
'''Linking with your Hue'''=الارتباط بجهاز Hue الخاص بك
'''The current Hue username is invalid. Please press the button on your Hue Bridge to relink.'''=اسم مستخدم Hue الحالي غير صالح. يُرجى الضغط على الزر الموجود على Hue Bridge الخاص بك لإعادة الارتباط.
'''Press the button on your Hue Bridge to setup a link.'''=اضغط على الزر الموجود على Hue Bridge الخاص بك لإعداد رابط.
'''You haven't selected a Hue Bridge, please Press 'Done' and select one before clicking next.'''=لم تحدد Hue Bridge، يُرجى الضغط على 'تم' وتحديد واحد قبل النقر فوق التالي.
'''Success!'''=نجحت العملية!
'''Linking to your hub was a success! Please click 'Next'!'''=نجح الارتباط بالموزع الخاص بك! يُرجى النقر فوق ”التالي“!
'''Find bridges'''=بحث عن أجهزة bridges
'''Light Discovery Failed!'''=فشل اكتشاف المصباح!
'''Failed to discover any lights, please try again later. Click 'Done' to exit.'''=فشل اكتشاف أي مصابيح، يُرجى المحاولة مرة أخرى لاحقاً. انقر فوق تم للخروج.
'''Select Hue Lights to add ({{numFound}} found)'''=حدد مصابيح Hue التي تريد إضافتها (تم العثور على {{numFound}})
'''Previously added Hue Lights ({{existingLightsSize}} added)'''=مصابيح Hue المضافة مُسبقاً (تمت إضافة {{existingLightsSize}})
'''Light Discovery Started!'''=بدأ اكتشاف المصباح!
'''Please wait while we discover your Hue Lights. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.'''=يُرجى الانتظار ريثما نكتشف مصابيح Hue الخاصة بك. قد يستغرق الاكتشاف خمس دقائق أو أكثر، لذا اجلس واسترخِ! اختر جهازك أدناه بمجرد اكتشافه.

View File

@@ -1,19 +0,0 @@
'''Allows you to connect your Philips Hue lights with SmartThings and control them from your Things area or Dashboard in the SmartThings Mobile app. Please update your Hue Bridge first, outside of the SmartThings app, using the Philips Hue app.'''=Позволява да свържете Philips Hue lights (лампи) със SmartThings и да ги управлявате от областта Things (Уреди) или Dashboard (Табло) в приложението SmartThings Mobile. Първо актуализирайте своя Hue Bridge (Мост) извън приложението SmartThings, като използвате приложението Philips Hue.
'''Discovery Started!'''=Откриването е стартирано!
'''Please wait while we discover your Hue Bridge. Kindly note that you must first configure your Hue Bridge and Lights using the Philips Hue application. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.'''=Изчакайте, докато намерим вашия Hue Bridge (Мост). Обърнете внимание, че първо трябва да конфигурирате своя Hue Bridge (Мост) и Lights (Лампи) с помощта на приложението Philips Hue. Намирането може да отнеме пет минути или повече, така че седнете и се отпуснете! Изберете устройството си по-долу, след като бъде открито.
'''Select Hue Bridge ({{numFound}} found)'''=Избор на Hue Bridge (Мост) ({{numFound}} са открити)
'''Bridge Discovery Failed!'''=Откриването на Bridge (Мост) е неуспешно!
'''Failed to discover any Hue Bridges. Please confirm that the Hue Bridge is connected to the same network as your SmartThings Hub, and that it has power.'''=Неуспешно откриване на Hue Bridges (Мост). Уверете се, че Hue Bridge (Мост) е свързан към същата мрежа като концентратора на SmartThings, както и че има захранване.
'''Linking with your Hue'''=Свързване с Hue
'''The current Hue username is invalid. Please press the button on your Hue Bridge to re-link.'''=Текущото потребителско име за Hue е невалидно. Натиснете бутона на вашия Hue Bridge (Мост) за повторно свързване.
'''Press the button on your Hue Bridge to setup a link.'''=Натиснете бутона на вашия Hue Bridge (Мост), за да установите връзка.
'''You haven't selected a Hue Bridge, please Press 'Done' and select one before clicking next.'''=Не сте избрали Hue Bridge (Мост), натиснете „Done“ (Готово) и изберете един, преди да щракнете върху Next (Напред).
'''Success!'''=Успех!
'''Linking to your hub was a success! Please click 'Next'!'''=Свързването с вашия концентратор е успешно. Щракнете върху „Next“ (Напред)!
'''Find bridges'''=Откриване на мостове
'''Light Discovery Failed!'''=Откриването на лампата е неуспешно!
'''Failed to discover any lights, please try again later. Click 'Done' to exit.'''=Неуспешно откриване на лампи, опитайте отново по-късно. Щракнете върху Done (Готово) за изход.
'''Select Hue Lights to add ({{numFound}} found)'''=Изберете Hue Lights (Лампи) за добавяне ({{numFound}} са открити)
'''Previously added Hue Lights ({{existingLightsSize}} added)'''=По-рано добавени Hue Lights (Лампи) ({{existingLightsSize}} са добавени)
'''Light Discovery Started!'''=Откриването на лампи е стартирано!
'''Please wait while we discover your Hue Lights. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.'''=Изчакайте, докато намерим вашите Hue Lights (Лампи). Намирането може да отнеме пет минути или повече, така че седнете и се отпуснете! Изберете устройството си по-долу, след като бъде открито.

Some files were not shown because too many files have changed in this diff Show More