Compare commits

...

42 Commits

Author SHA1 Message Date
Jorge Alirio Mejia Cañas
9e7e892f41 MSA-1864: mediaRenderer connect 2017-03-29 07:03:46 -07:00
Vinay Rao
00fc9e1ab3 Merge pull request #1844 from SmartThingsCommunity/staging
Rolling down staging to master
2017-03-28 14:14:54 -07:00
Vinay Rao
3b2d955c55 Merge pull request #1843 from SmartThingsCommunity/revert-1818-spruce_controller
Revert "[CHF-577] Added Health Check Implementation for Spruce Controller."
2017-03-28 14:14:11 -07:00
Vinay Rao
44facec5df Revert "[CHF-577] Added Health Check Implementation for Spruce Controller." 2017-03-28 14:13:37 -07:00
Jack Chi
59bfdc9b06 Merge pull request #1835 from parijatdas/fibaro_door_window_sensor
[CHF-563] Health Check fibaro-door-window-sensor
2017-03-28 10:47:55 -07:00
Jack Chi
e274f2d3fe Merge pull request #1839 from pchomal/smartsense_moisture_hc
[CHF-560] Health Check Smartsense Moisture
2017-03-28 10:46:53 -07:00
Jack Chi
5e23c8e700 Merge pull request #1836 from parijatdas/zwave_motion_sensor
[CHF-564] Health Check zwave-motion-sensor
2017-03-28 10:45:05 -07:00
piyush.c
10c1d6f715 [CHF-560] Health Check Smartsense Moisture 2017-03-28 22:06:51 +05:30
Terry Gauchat
2fb3294ce1 To Bose Soundtouch DTHs, added Capability "Sensor" & Capability "Actuator" (#1800)
* To Bose Soundtouch DTH, added Capability "Sensor" & Capability "Actuator" per http://docs.smartthings.com/en/latest/device-type-developers-guide/overview.html?highlight=sensor%20actuator#actuator-and-sensor.

* Replaced Tabs with Spaces for capability Sensor / Actuator lines per request of @WorkingMonk.
2017-03-27 16:16:57 -07:00
Parijat Das
693f2c1060 Added health-check for Zwave Motion Sensor 2017-03-27 15:29:33 -07:00
Parijat Das
74ae369143 Added health-check for Fibaro Door Window Sensor 2017-03-27 15:05:39 -07:00
Jack Chi
afa7784999 Merge pull request #1833 from pchomal/zigbee_switch_hc
[CHF-558] Health Check ZigBee Switch
2017-03-27 14:16:25 -07:00
piyush.c
0e9abb0cd2 [CHF-558] Health Check ZigBee Switch 2017-03-28 00:31:55 +05:30
Jack Chi
123de9aae4 Merge pull request #1818 from skt123/spruce_controller
[CHF-577] Added Health Check Implementation for Spruce Controller.
2017-03-27 11:53:43 -07:00
bflorian
e91907c30a Merge pull request #1810 from bflorian/DVCSMP-2528-lifx
DVCSMP-2528 Added app setting for OAuth callback URL
2017-03-27 11:22:55 -07:00
sushant.k1
237e226697 [CHF-577] Added Health Check Implementation for Spruce Controller. 2017-03-27 23:41:15 +05:30
Jack Chi
3b48629546 Merge pull request #1819 from skt123/econet_vent
[CHF-571] Added Health Check Implementation for EcoNet Vent.
2017-03-27 10:44:35 -07:00
Jack Chi
d28414c1e8 Merge pull request #1817 from pchomal/zwave_door_window_sensor_hc
[CHF-562] Health Check zwave-door-window-sensor
2017-03-27 10:43:46 -07:00
Jack Chi
f79db67153 Merge pull request #1815 from pchomal/keen_home_smart_vent_hc
[CHF-568] Health Check keen-home-smart-vent
2017-03-27 10:43:00 -07:00
piyush.c
8c7cb54934 [CHF-562] Health Check zwave-door-window-sensor 2017-03-27 23:04:22 +05:30
Tyler Lange
213d71da09 Merge pull request #1832 from CosmicPuppy/ActionTiles-Tyco-CapabilitySensor-Patch
To Tyco Door-Window Sensor DTH: added Capability "Sensor"
2017-03-27 09:05:42 -07:00
piyush.c
b7288b5beb [CHF-568] Health Check keen-home-smart-vent 2017-03-27 14:36:20 +05:30
CosmicPuppy
364154e8a7 To Tyco Door-Window Sensor DTH, added Capability "Sensor" per http://docs.smartthings.com/en/latest/device-type-developers-guide/overview.html?highlight=sensor%20actuator#actuator-and-sensor. 2017-03-27 01:08:16 -07:00
Jack Chi
c51e035ff2 Merge pull request #1816 from skt123/zen_thermostat
[CHF-572] Added Health Check Implementation for Zen Thermostat.
2017-03-24 14:18:49 -07:00
Jack Chi
23cfae20b3 Merge pull request #1829 from pchomal/plantlink_hc
[CHF-561] Fixing Typo Error in Plant Link Readme
2017-03-24 14:16:40 -07:00
sushant.k1
5e7ded1f73 [CHF-572] Added Health Check Implementation for Zen Thermostat. 2017-03-24 18:25:45 +05:30
sushant.k1
36b4d48056 [CHF-571] Added Health Check Implementation for EcoNet Vent. 2017-03-24 17:32:05 +05:30
piyush.c
03b9f08eed [CHF-561] Fixing Typo Error in Plant Link Readme 2017-03-24 17:23:29 +05:30
bflorian
fbdaeea9ae Merge pull request #1811 from bflorian/DVCSMP-2399-zooz-zen20
DVCSMP-2399 Added Zooz ZEN20 DTH
2017-03-23 14:38:34 -07:00
Jack Chi
9fa9dee606 Merge pull request #1823 from parijatdas/logitech_harmony_hub
[CHF-574] Health check logitech-harmony-hub-c2c
2017-03-23 10:47:38 -07:00
Jack Chi
122a7d4146 Merge pull request #1827 from pchomal/plantlink_hc
[CHF-561] Health Check Plant Link Sensor
2017-03-23 09:44:32 -07:00
piyush.c
32eb95f7d7 [CHF-561] Health Check Plant Link Sensor 2017-03-23 16:09:27 +05:30
bflorian
343ec9d856 DVCSMP-2399 Added Zooz ZEN20 DTH 2017-03-22 20:00:54 -07:00
Parijat Das
cbd15ae9cc Added health-check for Logitech Harmony Hub 2017-03-22 16:57:11 -07:00
Jack Chi
78a509e8f5 Merge pull request #1555 from skt123/micro_smart_switch
[CHF-493] Added Health Check Implementation for Micro Smart Switch 2E.
2017-03-22 10:06:11 -07:00
Ryan Applegate
42d31f29cc Merge pull request #1820 from rappleg/FixSmartSenseMultiBackgroundColor
DVCSMP-2533 Fix backgroundColor on SmartSense Multi
2017-03-22 11:28:03 -05:00
rappleg
9b4f6974de DVCSMP-2533 Fix backgroundColor on SmartSense Multi 2017-03-22 11:21:04 -05:00
Sushant
ea5344f9c8 Merge branch 'master' into micro_smart_switch 2017-03-22 15:22:13 +05:30
sushant.k1
b5e1d652fd [CHF-493] Added Health Check Implementation for Micro Smart Switch 2E. 2017-03-22 15:17:55 +05:30
Jack Chi
a03e8f20c5 Merge pull request #1537 from pchomal/zwave_thermostat
[CHF-480] Health Check implementation for Z-Wave Thermostat
2017-03-21 18:01:13 -07:00
bflorian
ce52af0376 DVCSMP-2528 Added app setting for OAuth callback URL 2017-03-21 14:15:20 -07:00
piyush.c
648dee90b6 [CHF-480]
Health Check implementation for Z-Wave Thermostat
2016-12-20 12:57:13 +05:30
38 changed files with 1191 additions and 15 deletions

View File

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

View File

@@ -0,0 +1,39 @@
# 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,6 +11,7 @@ metadata {
capability "Sensor"
capability "Temperature Measurement"
capability "Battery"
capability "Health Check"
command "getLevel"
command "getOnOff"
@@ -20,10 +21,8 @@ metadata {
command "setZigBeeIdTile"
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"
fingerprint endpoint: "1", profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0006,0008,0020,0402,0403,0B05,FC01,FC02", outClusters: "0019", manufacturer: "Keen Home Inc", model: "SV01-410-DV-1.0", deviceJoinName: "Keen Home Smart Vent"
}
// simulator metadata
@@ -466,15 +465,27 @@ def refresh() {
getBattery()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return refresh()
}
def 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
setZigBeeIdTile()
def configCmds = [
// bind reporting clusters to hub
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 500",
//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 0x0008 {${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",
@@ -510,5 +521,5 @@ def configure() {
// "send 0x${device.deviceNetworkId} 1 1", "delay 1500",
]
return configCmds + refresh()
return configCmds + zigbee.onOffConfig() + refresh()
}

View File

@@ -28,6 +28,8 @@ metadata {
capability "Refresh"
capability "Music Player"
capability "Health Check"
capability "Sensor"
capability "Actuator"
/**
* Define all commands, ie, if you have a custom action not

View File

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

View File

@@ -0,0 +1,43 @@
# 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,11 +26,13 @@ metadata {
capability "Sensor"
capability "Polling"
capability "Configuration"
capability "Health Check"
command "open"
command "close"
fingerprint deviceId: "0x1100", inClusters: "0x26,0x72,0x86,0x77,0x80,0x20"
fingerprint mfr:"0157", prod:"0100", model:"0100", deviceJoinName: "EcoNet Controls Z-Wave Vent"
}
simulator {
@@ -85,6 +87,8 @@ def parse(String description) {
//send the command to stop polling
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")
}
@@ -169,6 +173,13 @@ def setLevel(value, duration) {
setLevel(value)
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() {
delayBetween([
zwave.switchMultilevelV1.switchMultilevelGet().format(),

View File

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

View File

@@ -0,0 +1,40 @@
# 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,7 +39,8 @@
capability "Contact Sensor"
capability "Sensor"
capability "Battery"
capability "Configuration"
capability "Configuration"
capability "Health Check"
command "resetParams2StDefaults"
command "listCurrentParams"
@@ -266,6 +267,9 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
*/
def configure() {
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 = []
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

View File

@@ -7,6 +7,7 @@ metadata {
definition (name: "Logitech Harmony Hub C2C", namespace: "smartthings", author: "SmartThings") {
capability "Media Controller"
capability "Refresh"
capability "Health Check"
command "activityoff"
command "alloff"
@@ -38,6 +39,16 @@ metadata {
}
}
def installed() {
log.debug "installed()"
sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "cloud", scheme:"untracked"]), displayed: false)
}
def updated() {
log.debug "updated()"
sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "cloud", scheme:"untracked"]), displayed: false)
}
def startActivity(String activityId) {
log.debug "Executing 'Start Activity'"
log.trace parent.activity("$device.deviceNetworkId-$activityId","start")
@@ -58,6 +69,10 @@ def poll() {
log.trace parent.poll()
}
def ping() {
refresh()
}
def refresh() {
log.debug "Executing 'Refresh'"
log.trace parent.poll()

View File

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

View File

@@ -0,0 +1,35 @@
# 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,8 +21,10 @@ metadata {
capability "Relative Humidity Measurement"
capability "Battery"
capability "Sensor"
capability "Health Check"
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 {
@@ -48,6 +50,11 @@ 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
def parse(String description) {
log.debug "Parse description $description"

View File

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

View File

@@ -0,0 +1,36 @@
# 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,9 +17,11 @@ metadata {
capability "Sensor"
capability "Battery"
capability "Temperature Measurement"
capability "Health Check"
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 mfr:"0084", prod:"0063", model:"010C", deviceJoinName: "FortrezZ Moisture Sensor"
}
simulator {
@@ -89,6 +91,11 @@ def parse(String description) {
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)
{
[descriptionText: "${device.displayName} woke up", isStateChange: false]

View File

@@ -52,7 +52,7 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"contact", type: "generic", width: 6, height: 4){
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:"#e86d13"
attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00a0dc"
}
}

View File

@@ -23,6 +23,7 @@ metadata {
capability "Refresh"
capability "Temperature Measurement"
capability "Health Check"
capability "Sensor"
command "enrollResponse"

View File

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

View File

@@ -0,0 +1,35 @@
# 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

@@ -18,6 +18,7 @@ metadata {
capability "Configuration"
capability "Refresh"
capability "Switch"
capability "Health Check"
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"
@@ -75,11 +76,20 @@ def on() {
zigbee.on()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return refresh()
}
def refresh() {
zigbee.onOffRefresh() + zigbee.onOffConfig()
}
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."
zigbee.onOffRefresh() + zigbee.onOffConfig()
}

View File

@@ -0,0 +1,41 @@
/**
* 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

@@ -0,0 +1,210 @@
/**
* 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"
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
}
}
//////////////////////
// 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")}
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

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

View File

@@ -0,0 +1,36 @@
# 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,12 +22,14 @@ metadata {
capability "Sensor"
capability "Battery"
capability "Configuration"
capability "Health Check"
fingerprint deviceId: "0x2001", inClusters: "0x30,0x80,0x84,0x85,0x86,0x72"
fingerprint deviceId: "0x07", inClusters: "0x30"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x98"
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 mfr:"0086", prod:"0002", model:"001D", deviceJoinName: "Aeon Labs Door/Window Sensor (Gen 5)"
}
// simulator metadata
@@ -78,6 +80,8 @@ def parse(String description) {
}
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 = []
if (!state.MSR) {
cmds = [

View File

@@ -22,10 +22,12 @@ metadata {
capability "Configuration"
capability "Sensor"
capability "Light"
capability "Health Check"
command "reset"
fingerprint inClusters: "0x25,0x32"
fingerprint mfr:"0086", prod:"0003", model:"0012", deviceJoinName: "Aeon Labs Micro Smart Switch 2E"
}
// simulator metadata
@@ -73,6 +75,8 @@ 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])
try {
if (!state.MSR) {
response(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format())
@@ -179,6 +183,14 @@ def poll() {
])
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
log.debug "ping() called"
refresh()
}
def refresh() {
delayBetween([
zwave.switchBinaryV1.switchBinaryGet().format(),

View File

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

View File

@@ -0,0 +1,39 @@
# 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,6 +21,7 @@ metadata {
capability "Motion Sensor"
capability "Sensor"
capability "Battery"
capability "Health Check"
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
@@ -50,6 +51,11 @@ 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 result = null
if (description.startsWith("Err")) {

View File

@@ -20,6 +20,7 @@ metadata {
capability "Configuration"
capability "Polling"
capability "Sensor"
capability "Health Check"
attribute "thermostatFanState", "string"
@@ -30,6 +31,7 @@ metadata {
fingerprint deviceId: "0x08"
fingerprint inClusters: "0x43,0x40,0x44,0x31"
fingerprint mfr:"0039", prod:"0011", model:"0001", deviceJoinName: "Honeywell Z-Wave Thermostat"
}
// simulator metadata
@@ -123,6 +125,11 @@ 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 map = createEvent(zwaveEvent(zwave.parse(description, [0x42:1, 0x43:2, 0x31: 3])))
@@ -393,6 +400,14 @@ def setCoolingSetpoint(Double degrees, Integer delay = 30000) {
], delay)
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
log.debug "ping() called"
poll()
}
def configure() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),

View File

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

View File

@@ -0,0 +1,37 @@
# 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,8 +12,9 @@ metadata {
capability "Configuration"
capability "Refresh"
capability "Sensor"
fingerprint profileId: "0104", endpointId: "01", inClusters: "0000,0001,0003,0004,0005,0020,0201,0202,0204,0B05", outClusters: "000A, 0019"
capability "Health Check"
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"
@@ -467,8 +468,12 @@ def fanAuto() {
"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 ===============
def refresh()
@@ -502,6 +507,7 @@ def poll()
def configure()
{
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
log.debug "configure() - binding & attribute report"
[
//Set long poll interval to 2 qs
@@ -511,7 +517,7 @@ def configure()
//Thermostat - Cluster 201
"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",
"zcl global send-me-a-report 0x201 0x0011 0x29 5 300 {3200}",

View File

@@ -0,0 +1,445 @@
/**
* MediaRenderer Service Manager v 2.0.1
*
* Author: SmartThings - Ulises Mujica
*/
definition(
name: "MediaRenderer (Connect)",
namespace: "mujica",
author: "SmartThings - Ulises Mujica",
description: "Allows you to control your Media Renderer from the SmartThings app. Perform basic functions like play, pause, stop, change track, and check artist and song name from the Things screen.",
category: "SmartThings Labs",
singleInstance: true,
iconUrl: "https://graph.api.smartthings.com/api/devices/icons/st.secondary.smartapps-tile?displaySize=2x",
iconX2Url: "https://graph.api.smartthings.com/api/devices/icons/st.secondary.smartapps-tile?displaySize=2x"
)
preferences {
page(name: "MainPage", title: "Search and config your Media Renderers", install:true, uninstall: true){
section("") {
href(name: "discover",title: "Discovery process",required: false,page: "mediaRendererDiscovery",description: "tap to start searching")
}
section("Options", hideable: true, hidden: true) {
input("refreshMRInterval", "number", title:"Enter refresh players interval (min)",defaultValue:"15", required:false)
}
}
page(name: "mediaRendererDiscovery", title:"Discovery Started!")
}
def mediaRendererDiscovery()
{
log.trace "mediaRendererDiscovery() state.subscribe ${state.subscribe}"
if(canInstallLabs())
{
int mediaRendererRefreshCount = !state.mediaRendererRefreshCount ? 0 : state.mediaRendererRefreshCount as int
state.mediaRendererRefreshCount = mediaRendererRefreshCount + 1
def refreshInterval = 5
def options = mediaRenderersDiscovered() ?: []
def numFound = options.size() ?: 0
if(!state.subscribe) {
subscribe(location, null, locationHandler, [filterEvents:false])
state.subscribe = true
}
//mediaRenderer discovery request every 5 //25 seconds
if((mediaRendererRefreshCount % 8) == 0) {
discoverMediaRenderers()
}
//setup.xml request every 3 seconds except on discoveries
if(((mediaRendererRefreshCount % 1) == 0) && ((mediaRendererRefreshCount % 8) != 0)) {
verifyMediaRendererPlayer()
}
return dynamicPage(name:"mediaRendererDiscovery", title:"Discovery Started!", nextPage:"", refreshInterval:refreshInterval) {
section("Please wait while we discover your MediaRenderer. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
input "selectedMediaRenderer", "enum", required:false, title:"Select Media Renderer (${numFound} found)", multiple:true, options:options
}
}
}
else
{
def upgradeNeeded = """To use SmartThings Labs, your Hub should be completely up to date.
To update your Hub, access Location Settings in the Main Menu (tap the gear next to your location name), select your Hub, and choose "Update Hub"."""
return dynamicPage(name:"mediaRendererDiscovery", title:"Upgrade needed!", nextPage:"", install:false, uninstall: true) {
section("Upgrade") {
paragraph "$upgradeNeeded"
}
}
}
}
private discoverMediaRenderers()
{
sendHubCommand(new physicalgraph.device.HubAction("lan discovery urn:schemas-upnp-org:device:MediaRenderer:1", physicalgraph.device.Protocol.LAN))
}
private verifyMediaRendererPlayer() {
def devices = getMediaRendererPlayer().findAll { it?.value?.verified != true }
devices.each {
verifyMediaRenderer((it?.value?.ip + ":" + it?.value?.port), it?.value?.ssdpPath)
}
}
private verifyMediaRenderer(String deviceNetworkId, String ssdpPath) {
String ip = getHostAddress(deviceNetworkId)
if(!ssdpPath){
ssdpPath = "/"
}
log.trace "verifyMediaRenderer($deviceNetworkId, $ssdpPath, $ip)"
sendHubCommand(new physicalgraph.device.HubAction("""GET $ssdpPath HTTP/1.1\r\nHOST: $ip\r\n\r\n""", physicalgraph.device.Protocol.LAN, "${deviceNetworkId}"))
}
Map mediaRenderersDiscovered() {
def vmediaRenderers = getVerifiedMediaRendererPlayer()
def map = [:]
vmediaRenderers.each {
def value = "${it.value.name}"
def key = it.value.ip + ":" + it.value.port
map["${key}"] = value
}
map
}
def getMediaRendererPlayer()
{
state.mediaRenderers = state.mediaRenderers ?: [:]
}
def getVerifiedMediaRendererPlayer()
{
getMediaRendererPlayer().findAll{ it?.value?.verified == true }
}
def installed() {
log.trace "installed()"
//initialize()
}
def updated() {
log.trace "updated()"
if (selectedMediaRenderer) {
addMediaRenderer()
}
unsubscribe()
state.subscribe = false
unschedule()
scheduleTimer()
scheduleActions()
refreshAll()
syncDevices()
}
def uninstalled() {
def devices = getChildDevices()
devices.each {
deleteChildDevice(it.deviceNetworkId)
}
}
def initialize() {
// remove location subscription aftwards
log.trace "initialize()"
//scheduledRefreshHandler()
}
def scheduledRefreshHandler(){
}
def scheduledTimerHandler() {
timerAll()
}
def scheduledActionsHandler() {
syncDevices()
//runIn(60, scheduledRefreshHandler)
}
private scheduleTimer() {
def cron = "0 0/3 * * * ?"
schedule(cron, scheduledTimerHandler)
}
private scheduleActions() {
def minutes = Math.max(settings.refreshMRInterval.toInteger(),1)
def cron = "0 0/${minutes} * * * ?"
schedule(cron, scheduledActionsHandler)
}
private syncDevices() {
log.debug "syncDevices()"
if(!state.subscribe) {
subscribe(location, null, locationHandler, [filterEvents:false])
log.trace "subscribe($location, null, locationHandler, [filterEvents:false])"
state.subscribe = true
}
discoverMediaRenderers()
}
private timerAll(){
childDevices*.poll()
}
private refreshAll(){
childDevices*.refresh()
}
def addMediaRenderer() {
def players = getVerifiedMediaRendererPlayer()
def runSubscribe = false
selectedMediaRenderer.each { dni ->
def d = getChildDevice(dni)
if(!d) {
def newPlayer = players.find { (it.value.ip + ":" + it.value.port) == dni }
if (newPlayer){
d = addChildDevice("mujica", "DLNA Player", dni, newPlayer?.value.hub, [label:"${newPlayer?.value.name} Speaker","data":["model":newPlayer?.value.model,"avtcurl":newPlayer?.value.avtcurl,"avteurl":newPlayer?.value.avteurl,"rccurl":newPlayer?.value.rccurl,"rceurl":newPlayer?.value.rceurl,"udn":newPlayer?.value.udn,"dni":dni]])
}
runSubscribe = true
}
}
}
def locationHandler(evt) {
def description = evt.description
def hub = evt?.hubId
def parsedEvent = parseEventMessage(description)
def msg = parseLanMessage(description)
if (msg?.headers?.sid)
{
childDevices*.each { childDevice ->
if(childDevice.getDataValue('subscriptionId') == ((msg?.headers?.sid ?:"") - "uuid:")|| childDevice.getDataValue('subscriptionId1') == ((msg?.headers?.sid ?:"") - "uuid:")){
childDevice.parse(description)
}
}
}
parsedEvent << ["hub":hub]
if (parsedEvent?.ssdpTerm?.contains("urn:schemas-upnp-org:device:MediaRenderer:1"))
{ //SSDP DISCOVERY EVENTS
log.debug "MediaRenderer device found" + parsedEvent
def mediaRenderers = getMediaRendererPlayer()
if (!(mediaRenderers."${parsedEvent.ssdpUSN.toString()}"))
{ //mediaRenderer does not exist
mediaRenderers << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
}
else
{ // update the values
def d = mediaRenderers."${parsedEvent.ssdpUSN.toString()}"
boolean deviceChangedValues = false
if(d.ip != parsedEvent.ip || d.port != parsedEvent.port) {
d.ip = parsedEvent.ip
d.port = parsedEvent.port
deviceChangedValues = true
}
if (deviceChangedValues) {
def children = getChildDevices()
children.each {
if (parsedEvent.ssdpUSN.toString().contains(it.getDataValue("udn"))) {
it.setDeviceNetworkId((parsedEvent.ip + ":" + parsedEvent.port)) //could error if device with same dni already exists
it.updateDataValue("dni", (parsedEvent.ip + ":" + parsedEvent.port))
it.refresh()
log.trace "Updated Device IP"
}
}
}
}
}
else if (parsedEvent.headers && parsedEvent.body)
{ // MEDIARENDER RESPONSES
def headerString = new String(parsedEvent?.headers?.decodeBase64())
def bodyString = new String(parsedEvent.body.decodeBase64())
def type = (headerString =~ /Content-Type:.*/) ? (headerString =~ /Content-Type:.*/)[0] : null
def body
def device
if (bodyString?.contains("xml"))
{ // description.xml response (application/xml)
body = new XmlSlurper().parseText(bodyString)
log.trace "MEDIARENDER RESPONSES ${body?.device?.modelName?.text()}"
// Avoid add sonos devices
device = body?.device
body?.device?.deviceList?.device?.each{
if (it?.deviceType?.text().contains("urn:schemas-upnp-org:device:MediaRenderer:1")) {
device = it
}
}
if ( device?.deviceType?.text().contains("urn:schemas-upnp-org:device:MediaRenderer:1"))
{
def avtcurl = ""
def avteurl = ""
def rccurl = ""
def rceurl = ""
device?.serviceList?.service?.each{
if (it?.serviceType?.text().contains("AVTransport")) {
avtcurl = it?.controlURL?.text().startsWith("/")? it?.controlURL.text() : "/" + it?.controlURL.text()
avteurl = it?.eventSubURL?.text().startsWith("/")? it?.eventSubURL.text() : "/" + it?.eventSubURL.text()
}
else if (it?.serviceType?.text().contains("RenderingControl")) {
rccurl = it?.controlURL?.text().startsWith("/")? it?.controlURL?.text() : "/" + it?.controlURL?.text()
rceurl = it?.eventSubURL?.text().startsWith("/")? it?.eventSubURL?.text() : "/" + it?.eventSubURL?.text()
}
}
def mediaRenderers = getMediaRendererPlayer()
def player = mediaRenderers.find {it?.key?.contains(device?.UDN?.text())}
if (player)
{
player.value << [name:device?.friendlyName?.text(),model:device?.modelName?.text(), serialNumber:device?.UDN?.text(), verified: true,avtcurl:avtcurl,avteurl:avteurl,rccurl:rccurl,rceurl:rceurl,udn:device?.UDN?.text()]
}
}
}
else if(type?.contains("json"))
{ //(application/json)
body = new groovy.json.JsonSlurper().parseText(bodyString)
}
}
}
private def parseEventMessage(Map event) {
//handles mediaRenderer attribute events
return event
}
private def parseEventMessage(String description) {
def event = [:]
def parts = description.split(',')
parts.each { part ->
part = part.trim()
if (part.startsWith('devicetype:')) {
def valueString = part.split(":")[1].trim()
event.devicetype = valueString
}
else if (part.startsWith('mac:')) {
def valueString = part.split(":")[1].trim()
if (valueString) {
event.mac = valueString
}
}
else if (part.startsWith('networkAddress:')) {
def valueString = part.split(":")[1].trim()
if (valueString) {
event.ip = valueString
}
}
else if (part.startsWith('deviceAddress:')) {
def valueString = part.split(":")[1].trim()
if (valueString) {
event.port = valueString
}
}
else if (part.startsWith('ssdpPath:')) {
def valueString = part.split(":")[1].trim()
if (valueString) {
event.ssdpPath = valueString
}
}
else if (part.startsWith('ssdpUSN:')) {
part -= "ssdpUSN:"
def valueString = part.trim()
if (valueString) {
event.ssdpUSN = valueString
}
}
else if (part.startsWith('ssdpTerm:')) {
part -= "ssdpTerm:"
def valueString = part.trim()
if (valueString) {
event.ssdpTerm = valueString
}
}
else if (part.startsWith('headers')) {
part -= "headers:"
def valueString = part.trim()
if (valueString) {
event.headers = valueString
}
}
else if (part.startsWith('body')) {
part -= "body:"
def valueString = part.trim()
if (valueString) {
event.body = valueString
}
}
}
if (event.devicetype == "04" && event.ssdpPath =~ /[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}/ && !event.ssdpUSN && !event.ssdpTerm){
def matcher = event.ssdpPath =~ /[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}/
def ssdpUSN = matcher[0]
event.ssdpUSN = "uuid:$ssdpUSN::urn:schemas-upnp-org:device:MediaRenderer:1"
event.ssdpTerm = "urn:schemas-upnp-org:device:MediaRenderer:1"
}
event
}
/////////CHILD DEVICE METHODS
def parse(childDevice, description) {
def parsedEvent = parseEventMessage(description)
if (parsedEvent.headers && parsedEvent.body) {
def headerString = new String(parsedEvent.headers.decodeBase64())
def bodyString = new String(parsedEvent.body.decodeBase64())
def body = new groovy.json.JsonSlurper().parseText(bodyString)
} else {
return []
}
}
private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16)
}
private String convertHexToIP(hex) {
[convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
}
private getHostAddress(d) {
def parts = d.split(":")
def ip = convertHexToIP(parts[0])
def port = convertHexToInt(parts[1])
return ip + ":" + port
}
private Boolean canInstallLabs()
{
return hasAllHubsOver("000.011.00603")
}
private Boolean hasAllHubsOver(String desiredFirmware)
{
return realHubFirmwareVersions.every { fw -> fw >= desiredFirmware }
}
private List getRealHubFirmwareVersions()
{
return location.hubs*.firmwareVersionString.findAll { it }
}

View File

@@ -19,8 +19,15 @@ definition(
singleInstance: true) {
appSetting "clientId"
appSetting "clientSecret"
appSetting "serverUrl" // See note below
}
// NOTE regarding OAuth settings. On NA01 (i.e. graph.api), NA01S, and NA01D the serverUrl app setting can be left
// Blank. For other shards is should be set to the callback URL registered with LIFX, which is:
//
// Production -- https://graph.api.smartthings.com
// Staging -- https://graph-na01s-useast1.smartthingsgdev.com
// Development -- https://graph-na01d-useast1.smartthingsgdev.com
preferences {
page(name: "Credentials", title: "LIFX", content: "authPage", install: true)
@@ -35,8 +42,8 @@ mappings {
path("/test") { action: [ GET: "oauthSuccess" ] }
}
def getServerUrl() { return "https://graph.api.smartthings.com" }
def getCallbackUrl() { return "https://graph.api.smartthings.com/oauth/callback"}
def getServerUrl() { return appSettings.serverUrl ?: apiServerUrl }
def getCallbackUrl() { return "${getServerUrl()}/oauth/callback" }
def apiURL(path = '/') { return "https://api.lifx.com/v1${path}" }
def getSecretKey() { return appSettings.secretKey }
def getClientId() { return appSettings.clientId }

View File

@@ -511,6 +511,10 @@ def pollResponse(response, data) {
if (ResponseValues) {
def map = [:]
ResponseValues.hubs.each {
// Device-Watch relies on the Logitech Harmony Cloud to get the Device state.
def isAlive = it.value.status
def d = getChildDevice("harmony-${it.key}")
d?.sendEvent(name: "DeviceWatch-DeviceStatus", value: isAlive!=504? "online":"offline", displayed: false, isStateChange: true)
if (it.value.message == "OK") {
map["${it.key}"] = "${it.value.response.data.currentAvActivity},${it.value.response.data.activityStatus}"
def hub = getChildDevice("harmony-${it.key}")