Compare commits

...

83 Commits

Author SHA1 Message Date
Vinay Rao
60f6e9c02c Merge pull request #2064 from SmartThingsCommunity/staging
Rolling down staging to master
2017-05-31 13:56:22 -07:00
Vinay Rao
d3731b49fe Merge pull request #2062 from SmartThingsCommunity/production
Rolling down production to staging
2017-05-31 11:44:22 -07:00
Vinay Rao
da139056e1 Merge pull request #2047 from dkirker/ICP-1076
ICP-1076 Fix Aeon Door/Window Sensor 6 initial value of null
2017-05-31 11:24:20 -07:00
Donald Kirker
d864c5e3b3 ICP-1076 Fix Aeon Door/Window Sensor 6 initial value of null 2017-05-31 11:00:43 -07:00
Vinay Rao
7064ce972a Merge pull request #2048 from dkirker/ICP-1016
ICP-1016 Fix default value for states for Aeon Siren Gen5
2017-05-30 11:53:51 -07:00
Vinay Rao
936ee59242 Merge pull request #2056 from jackchi/zwave-lock-1hr-ping
[DHF-7] [ICP-1084] Adds scheduled 1 hr ping for offline devices
2017-05-30 00:27:24 -07:00
jackchi
79a6a6472e [DHF-7] [ICP-1084] Adds scheduled 1 hr ping for offline devices; updates checkInterval to 1 hour 2017-05-29 11:02:48 -07:00
bflorian
919111ed22 Merge pull request #2051 from bflorian/MSA-1951-1-staging
MSA-1951 Added Inovelli 2-Channel Smart Plug
2017-05-26 13:55:20 -04:00
Bob Florian
fc1f1508ad MSA-1951 Added Inovelli 2-Channel Smart Plug 2017-05-26 13:38:45 -04:00
Donald Kirker
7f3cd0cdaa ICP-1016 Fix default value for states for Aeon Siren Gen5 2017-05-26 01:39:05 -07:00
Vinay Rao
423c25df53 Merge pull request #2045 from workingmonk/hotfix/siren
ICP-1056 Updating the icon and ocf device type for fortrezz siren
2017-05-25 17:17:48 -07:00
Vinay Rao
df8e435fcc ICP-1056 Updating the icon and ocf device type for fortrezz siren 2017-05-25 17:09:54 -07:00
Vinay Rao
144314d9ae Merge pull request #2042 from twack/ocf-update-fortrezz-siren
ICP-1056 ocf-update-fortrezz-siren
2017-05-25 11:04:17 -07:00
Vinay Rao
a1f39849ed Merge pull request #2043 from SmartThingsCommunity/staging
Rolling down staging to master
2017-05-25 10:58:53 -07:00
Vinay Rao
8eed22ca0c Merge pull request #2041 from parijatdas/aeon-multisensor
[CHF-616] Health check Aeon Multi sensor motion detector
2017-05-25 10:58:25 -07:00
twack
d626c5f2a1 ocf-update-fortrezz-siren 2017-05-25 07:57:19 -07:00
Parijat Das
1dae5d3936 Added health check implementation for Aeon MultiSensor 2017-05-25 18:56:38 +05:30
Vinay Rao
807ff53c6d Merge pull request #2036 from SmartThingsCommunity/master
Rolling up master to staging
2017-05-23 13:52:46 -07:00
Vinay Rao
f95319ce59 Merge pull request #2035 from SmartThingsCommunity/staging
Rolling down staging to master
2017-05-23 13:51:00 -07:00
Vinay Rao
453dbbdde3 Merge pull request #2034 from SmartThingsCommunity/staging
Rolling up staging to production
2017-05-23 13:49:56 -07:00
Vinay Rao
52427802a8 Merge pull request #2033 from SmartThingsCommunity/production
Rolling down production to staging
2017-05-23 13:49:12 -07:00
Vinay Rao
72bb22a4b8 ICP-1051 Moving samjin outlet to smartpower outlet DTH (#2032)
* ICP-1051 Moving samjin outlet to smartpower outlet DTH
2017-05-23 12:19:09 -07:00
Duncan McKee
e817f5c415 Merge pull request #1748 from mckeed/DVCSMP-2489
DVCSMP-2489 Everspring ST814 and ST815 Multilevel Sensors
2017-05-23 13:35:39 -04:00
Duncan McKee
10964873cd Merge pull request #2001 from mckeed/DVCSMP-2493
DVCSMP-2493 Notify Multi-Channel Control app when root device is deleted
2017-05-23 13:33:55 -04:00
Zach Varberg
20f086fe69 Merge pull request #2023 from varzac/fix-multisensor-npe
[DVCSMP-2668] Fix NPE for smartsense multi
2017-05-23 09:08:47 -05:00
Vinay Rao
21f7a00cc9 Merge pull request #2026 from unixbeast/DVCSMP-2672
DVCSMP-2672 updating read attribute for valve capability
2017-05-22 17:59:00 -07:00
Dave Hastings
06faa988c8 DVCSMP-2672 updating read attribute for valve capability
updating tile for fortrezz
2017-05-22 17:57:54 -07:00
Vinay Rao
fe5f5c35b2 Merge pull request #2025 from SmartThingsCommunity/staging
Rolling down staging to master
2017-05-22 17:44:28 -07:00
Vinay Rao
2c4cd8d922 Merge pull request #2003 from unixbeast/icp_781
ICP-781 Fixing DTH for valve capability
2017-05-22 15:23:57 -07:00
Dave Hastings
772cd7005a ICP-781 Fixing DTH for valve capability
Making suggested fixes

making fixes

fixing to correctly use createEvent

fixing DTH

Also adding the fortrezz water valve

refactoring a bit

adding back in debug messages

updating ocf device type

adding zigbee water valve

refactor
2017-05-22 15:22:18 -07:00
Vinay Rao
afb4755447 Merge pull request #2022 from dkirker/ICP-951
ICP-951 Add deviceJoinName for Aeon Panic Button
2017-05-22 11:53:42 -07:00
Vinay Rao
49f35e48da Merge pull request #2018 from jackchi/zwave-lock-wwst-naming
[ICP-975] Proper WWST Z-Wave Lock names
2017-05-22 11:50:33 -07:00
Donald Kirker
93d8e96efc ICP-951 Add deviceJoinName for Aeon Panic Button
Also properly report 1 button for Aeon Panic Button
2017-05-22 11:45:27 -07:00
jackchi
6fbaf15f42 [CP-975] Proper WWST Z-Wave Lock names 2017-05-22 11:41:54 -07:00
Zach Varberg
97c9ec7a95 Fix NPE for smartsense multi
There was a common NPE caused by assuming there would be additional
attributes reported with one acceleration value.  This corrects it to
instead properly handle the case where there weren't additional
attributes.

This resolves: https://smartthings.atlassian.net/browse/DVCSMP-2668
2017-05-22 11:52:13 -05:00
Aaron Miller
d7b448b699 Merge pull request #2016 from aaron-miller/DVCSMP-2665
DVCSMP-2665 Prevent 'Smart Nightlight' from over scheduling
2017-05-22 09:24:22 -05:00
Aaron Miller
9285536f73 Merge pull request #2013 from aaron-miller/DVCSMP-2659
DVCSMP-2659 Reduce Hello Home Phrase Detector Logs
2017-05-22 09:23:22 -05:00
Aaron Miller
e7713caec9 DVCSMP-2665 Prevent 'Smart Nightlight' from over scheduling 2017-05-19 14:09:08 -05:00
Vinay Rao
5b2a46300d Merge pull request #1539 from skt123/ct100
[CHF-481] Health Check Implementation for CT100 Programmable Thermostat.
2017-05-18 23:49:06 -07:00
Vinay Rao
c8b4b7be1c Merge pull request #2014 from jackchi/wwst-proper-names
[DVCSMP-2664] WWST Proper Naming
2017-05-18 16:00:39 -07:00
jackchi
20f1493788 [DVCSMP-2664] WWST Proper Naming 2017-05-18 14:47:46 -07:00
Aaron Miller
f0de2f1a19 DVCSMP-2659 Reduce Hello Home Phrase Detector Logs 2017-05-18 09:56:17 -05:00
Vinay Rao
1263a6e2e1 Merge pull request #2002 from twack/ocf-update-aeon-siren
ICP-950 ocf-update-aeon-siren
2017-05-18 07:52:00 -07:00
sushant.k1
d41162afe4 [CHF-481]
Added Health Check Implementation for CT100 Programmable Thermostat.
2017-05-18 18:36:57 +05:30
Vinay Rao
19d9406b6a Merge pull request #2010 from parijatdas/aeon-multisensor-6
[CHF-610] Health Check Aeon MultiSensor 6
2017-05-17 22:54:30 -07:00
Vinay Rao
a6d52ab9ac Merge pull request #1996 from SmartThingsCommunity/dth-ux-remaining-staging
[DVCSMP-2607] Standardize remaining SmartThingsPublic ON/CLOSED/TAMPERED & ACTIVE/INACTIVE state colors
2017-05-17 22:54:07 -07:00
Jack Chi
01c2968f91 Merge pull request #1834 from parijatdas/zwave_water_valve
[CHF-569] Health Check zwave-water-valve
2017-05-17 17:05:10 -07:00
jackchi
483a25e900 [DVCSMP-2607] Standardize remaining SmartThingsPublic ON/CLOSED/TAMPERED & OPEN state colors 2017-05-17 16:19:40 -07:00
Vinay Rao
0d9a08e922 Merge pull request #2007 from SmartThingsCommunity/master
Rolling up master to staging
2017-05-16 15:47:08 -07:00
Vinay Rao
40b75ce665 Merge pull request #2006 from SmartThingsCommunity/staging
Rolling down staging to master
2017-05-16 15:37:10 -07:00
Vinay Rao
a4d9cd51a3 Merge pull request #2005 from SmartThingsCommunity/staging
Rolling up staging to production
2017-05-16 14:37:45 -07:00
Vinay Rao
9b01a7d8be Merge pull request #2004 from SmartThingsCommunity/production
Rolling down production to staging
2017-05-16 14:37:15 -07:00
Parijat Das
12bb6c0492 Added health-check for Z-wave Water Valve 2017-05-16 12:26:48 +05:30
Parijat Das
9e3a6e830f Added health-check for Aeon Labs Multisensor 6 2017-05-16 12:16:01 +05:30
twack
92e1586fa6 ocf-update-aeon-siren 2017-05-15 20:13:47 -07:00
Vinay Rao
7cf8bb1917 Merge pull request #1998 from larsfinander/DVCSMP-2656_OpenT2T_Update_to_5_5_submission_staging
DVCSMP-2656 OpenT2T: Update to 5/15 submission
2017-05-15 12:31:34 -07:00
Lars Finander
d4fd778a64 DVCSMP-2656 OpenT2T: Update to 5/15 submission 2017-05-15 13:25:44 -06:00
Jack Chi
eb870e5f31 Merge pull request #1943 from parijatdas/smartalert_siren
[CHF-590] Fixed typo error
2017-05-15 10:47:25 -07:00
Vinay Rao
d60657e466 Merge pull request #1992 from dkirker/production
PROB-1615: Add SYLVANIA Smart 10-Year A19 bulb fingerprint
2017-05-11 15:08:13 -07:00
Donald Kirker
d8dc70ae9e PROB-1615 Add SYLVANIA Smart 10-Year A19 bulb fingerprint 2017-05-11 14:03:24 -07:00
Vinay Rao
a99e050c6b Merge pull request #1975 from jackchi/device-ux-remaining
[DVCSMP-2607] Standardize remaining SmartThingsPublic DTH colors
2017-05-11 13:35:42 -07:00
jackchi
5bf7caca0d [DVCSMP-2607] Standardize remaining SmartThingsPublic ON/CLOSED/TAMPERED & OPEN state colors 2017-05-11 12:23:38 -07:00
Vinay Rao
3457bbad42 Merge pull request #1991 from tslagle13/gideon-change
[MSA-1968] - Publish gideon smarthome changes
2017-05-11 11:12:30 -07:00
tslagle13
c6c4b09fbb [MSA-1968] - Publish gideon smarthome changes
small change to sensor readings
2017-05-11 11:06:44 -07:00
Aaron Miller
3eddd68532 Merge pull request #1978 from aaron-miller/DVCSMP-2612
[DVCSMP-2612] Unschedule execution for Left It Open when door is closed
2017-05-11 08:51:36 -05:00
Aaron Miller
8d79379bba Merge pull request #1927 from aaron-miller/DVCSMP-2595
[DVCSMP-2595] Set scheduled executions for Lights off with no motion SA to overwrite
2017-05-10 13:29:03 -05:00
Vinay Rao
7e25d32c70 Merge pull request #1990 from SmartThingsCommunity/master
Rolling up master to staging
2017-05-09 16:04:19 -05:00
Vinay Rao
dd4da29bcd Merge pull request #1989 from SmartThingsCommunity/staging
Rolling down staging to master
2017-05-09 16:03:53 -05:00
Vinay Rao
abc5683ed3 Merge pull request #1988 from SmartThingsCommunity/staging
Rolling up staging to production
2017-05-09 13:46:13 -05:00
Vinay Rao
a3e9f1d2c1 Merge pull request #1984 from larsfinander/DVCSMP-2613_OpenT2T_Update_5_1_submission_staging
DVCSMP-2613OpenT2T: Update to 5/1 submission
2017-05-08 09:02:19 -07:00
Lars Finander
8bfc3f0c1c DVCSMP-2613OpenT2T: Update to 5/1 submission 2017-05-08 09:56:53 -06:00
Aaron Miller
b6136bf1d5 [DVCSMP-2612] Unschedule execution for Left It Open when door is closed 2017-05-05 13:22:46 -05:00
Vinay Rao
68f5cda945 Merge pull request #1977 from ccurtiST/PROB-1347
PROB-1347 Lux values showing as ${unit} in recently tab of Aeon Multipurpose
2017-05-05 11:06:46 -07:00
Christopher Curti
da42ee63fb Replaced ${unit}', unit:"lux" with lux', unit: "" to fix issue with seeing ${unit} in the recently tab of Aeon multisensor illuminance values. Tested all three DTHs and lux was displayed rather then ${unit} 2017-05-05 09:31:44 -07:00
Vinay Rao
c58132a69e Merge pull request #1974 from SmartThingsCommunity/staging
Rolling down staging to master
2017-05-03 11:54:21 -07:00
Vinay Rao
93544c4f60 Merge pull request #1973 from SmartThingsCommunity/production
Rolling down production to staging
2017-05-03 11:53:58 -07:00
Vinay Rao
7527fdd1bb Merge pull request #1967 from tpmanley/bugfix/color-temp-exception
DVCSMP-2606 Fix recent regression with setting color temperature
2017-05-03 11:23:02 -07:00
Tom Manley
b552bcc6f0 Fix recent regression with setting color temperature
This fixes a recently introduced bug that caused an exception while
attempting to set the color temperature on any of these three DTHs.

https://smartthings.atlassian.net/browse/DVCSMP-2606
2017-05-02 22:24:25 -05:00
Vinay Rao
f069ea3087 Merge pull request #1965 from SmartThingsCommunity/staging
Rolling down staging to master
2017-05-02 16:14:39 -07:00
Parijat Das
1d629cfc9a Fixed typo in README url 2017-04-25 11:50:10 +05:30
Aaron Miller
5b7a7097b8 [DVCSMP-2595] Set scheduled executions for Lights off with no motion SA to overwrite 2017-04-20 13:20:55 -05:00
Duncan McKee
52c57f66fb DVCSMP-2493 Notify Multi-Channel Control app when root device is deleted 2017-03-06 13:31:32 -05:00
Duncan McKee
91c358c3a6 Everspring ST814 and ST815 Multilevel Sensors 2017-03-05 18:50:55 -05:00
62 changed files with 1377 additions and 346 deletions

View File

@@ -38,9 +38,9 @@ metadata {
tiles (scale: 2){
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL", icon: "st.Lighting.light18") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', icon:"st.switches.light.on", backgroundColor:"#79b821"
attributeState "turningOn", label:'${name}', icon:"st.switches.light.on", backgroundColor:"#00A0DC"
attributeState "turningOff", label:'${name}', icon:"st.switches.light.off", backgroundColor:"#ffffff"
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
@@ -52,20 +52,20 @@ metadata {
}
standardTile("motion", "device.motion", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
}
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state "temperature", label:'${currentValue}°', unit:"F", icon:"", // would be better if the units would switch to the desired units of the system (imperial or metric)
backgroundColors:[
[value: 0, color: "#1010ff"], // blue=cold
[value: 65, color: "#a0a0f0"],
[value: 70, color: "#e0e050"],
[value: 75, color: "#f0d030"], // yellow
[value: 80, color: "#fbf020"],
[value: 85, color: "#fbdc01"],
[value: 90, color: "#fb3a01"],
[value: 95, color: "#fb0801"] // red=hot
[value: 0, color: "#153591"], // blue=cold
[value: 65, color: "#44b621"], // green
[value: 70, color: "#44b621"], // green
[value: 75, color: "#f1d801"], // yellow
[value: 80, color: "#f1d801"], // yellow
[value: 85, color: "#f1d801"], // yellow
[value: 90, color: "#d04e00"], // red
[value: 95, color: "#bc2323"] // red=hot
]
}

View File

@@ -0,0 +1,266 @@
/**
*
* Inovelli 2-Channel Smart Plug
*
* github: Eric Maycock (erocm123)
* Date: 2017-04-27
* Copyright Eric Maycock
*
* Includes all configuration parameters and ease of advanced configuration.
*
* 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: "Inovelli 2-Channel Smart Plug", namespace: "erocm123", author: "Eric Maycock") {
capability "Actuator"
capability "Sensor"
capability "Switch"
capability "Polling"
capability "Refresh"
capability "Health Check"
fingerprint manufacturer: "015D", prod: "0221", model: "251C"
}
simulator {}
preferences {}
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 "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff"
}
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh"
}
main(["switch"])
details(["switch",
childDeviceTiles("all"), "refresh"
])
}
}
def parse(String description) {
def result = []
def cmd = zwave.parse(description)
if (cmd) {
result += zwaveEvent(cmd)
logging("Parsed ${cmd} to ${result.inspect()}", 1)
} else {
logging("Non-parsed event: ${description}", 2)
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) {
logging("BasicReport ${cmd} - ep ${ep}", 2)
if (ep) {
def event
childDevices.each {
childDevice ->
if (childDevice.deviceNetworkId == "$device.deviceNetworkId-ep$ep") {
childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off")
}
}
if (cmd.value) {
event = [createEvent([name: "switch", value: "on"])]
} else {
def allOff = true
childDevices.each {
n ->
if (n.currentState("switch").value != "off") allOff = false
}
if (allOff) {
event = [createEvent([name: "switch", value: "off"])]
} else {
event = [createEvent([name: "switch", value: "on"])]
}
}
return event
}
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
logging("BasicSet ${cmd}", 2)
def result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital")
def cmds = []
cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1)
cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
return [result, response(commands(cmds))] // returns the result of reponse()
}
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, ep = null) {
logging("SwitchBinaryReport ${cmd} - ep ${ep}", 2)
if (ep) {
def event
def childDevice = childDevices.find {
it.deviceNetworkId == "$device.deviceNetworkId-ep$ep"
}
if (childDevice) childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off")
if (cmd.value) {
event = [createEvent([name: "switch", value: "on"])]
} else {
def allOff = true
childDevices.each {
n->
if (n.currentState("switch").value != "off") allOff = false
}
if (allOff) {
event = [createEvent([name: "switch", value: "off"])]
} else {
event = [createEvent([name: "switch", value: "on"])]
}
}
return event
} else {
def result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital")
def cmds = []
cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1)
cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
return [result, response(commands(cmds))] // returns the result of reponse()
}
}
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
logging("MultiChannelCmdEncap ${cmd}", 2)
def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1])
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer)
}
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
logging("ManufacturerSpecificReport ${cmd}", 2)
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
logging("msr: $msr", 2)
updateDataValue("MSR", msr)
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
// This will capture any commands not handled by other instances of zwaveEvent
// and is recommended for development so you can see every command the device sends
logging("Unhandled Event: ${cmd}", 2)
}
def on() {
logging("on()", 1)
commands([
zwave.switchAllV1.switchAllOn(),
encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
])
}
def off() {
logging("off()", 1)
commands([
zwave.switchAllV1.switchAllOff(),
encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
])
}
void childOn(String dni) {
logging("childOn($dni)", 1)
def cmds = []
cmds << new physicalgraph.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0xFF), channelNumber(dni))))
cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))))
sendHubCommand(cmds, 1000)
}
void childOff(String dni) {
logging("childOff($dni)", 1)
def cmds = []
cmds << new physicalgraph.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0x00), channelNumber(dni))))
cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))))
sendHubCommand(cmds, 1000)
}
void childRefresh(String dni) {
logging("childRefresh($dni)", 1)
def cmds = []
cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))))
sendHubCommand(cmds, 1000)
}
def poll() {
logging("poll()", 1)
commands([
encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
encap(zwave.switchBinaryV1.switchBinaryGet(), 2),
])
}
def refresh() {
logging("refresh()", 1)
commands([
encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
encap(zwave.switchBinaryV1.switchBinaryGet(), 2),
])
}
def ping() {
logging("ping()", 1)
refresh()
}
def installed() {
logging("installed()", 1)
command(zwave.manufacturerSpecificV1.manufacturerSpecificGet())
createChildDevices()
}
def updated() {
logging("updated()", 1)
if (!childDevices) {
createChildDevices()
} else if (device.label != state.oldLabel) {
childDevices.each {
if (it.label == "${state.oldLabel} (CH${channelNumber(it.deviceNetworkId)})") {
def newLabel = "${device.displayName} (CH${channelNumber(it.deviceNetworkId)})"
it.setLabel(newLabel)
}
}
state.oldLabel = device.label
}
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "needUpdate", value: device.currentValue("needUpdate"), displayed: false, isStateChange: true)
}
def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) {
logging("${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'", 2)
}
private encap(cmd, endpoint) {
if (endpoint) {
zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd)
} else {
cmd
}
}
private command(physicalgraph.zwave.Command cmd) {
if (state.sec) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
} else {
cmd.format()
}
}
private commands(commands, delay = 1000) {
delayBetween(commands.collect {
command(it)
}, delay)
}
private channelNumber(String dni) {
dni.split("-ep")[-1] as Integer
}
private void createChildDevices() {
state.oldLabel = device.label
for (i in 1..2) {
addChildDevice("Switch Child Device", "${device.deviceNetworkId}-ep${i}", null, [completedSetup: true, label: "${device.displayName} (CH${i})",
isComponent: true, componentName: "ep$i", componentLabel: "Channel $i"
])
}
}
private def logging(message, level) {
if (logLevel != "0") {
switch (logLevel) {
case "1":
if (level > 1) log.debug "$message"
break
case "99":
log.debug "$message"
break
}
}
}

View File

@@ -0,0 +1,49 @@
/**
* Switch Child Device
*
* Copyright 2017 Eric Maycock
*
* 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: "Switch Child Device", namespace: "erocm123", author: "Eric Maycock") {
capability "Switch"
capability "Actuator"
capability "Sensor"
capability "Refresh"
}
tiles {
multiAttributeTile(name:"switch", type: "lighting", width: 3, 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"
}
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
}
}
void on() {
parent.childOn(device.deviceNetworkId)
}
void off() {
parent.childOff(device.deviceNetworkId)
}
void refresh() {
parent.childRefresh(device.deviceNetworkId)
}

View File

@@ -39,8 +39,8 @@ metadata {
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
attributeState("active", label:'tamper active', backgroundColor:"#00A0DC")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#CCCCCC")
}
}

View File

@@ -37,8 +37,8 @@ metadata {
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
attributeState("active", label:'tamper active', backgroundColor:"#00A0DC")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#CCCCCC")
}
}

View File

@@ -34,8 +34,8 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.motion", key:"PRIMARY_CONTROL") {
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#cccccc")
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {

View File

@@ -95,12 +95,12 @@ metadata {
multiAttributeTile(name:"doorCtrl", type:"generic", width:6, height:4) {tileAttribute("device.doorState", key: "PRIMARY_CONTROL")
{
attributeState "unknown", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", nextState:"Sent"
attributeState "open", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#0000ff" , nextState:"Sent"
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffa81e"
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#79b821", nextState:"Sent"
attributeState "closing", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffa81e"
attributeState "jammed", label: '${name}', action:"closeDoorHiI", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
attributeState "forced close", label: 'forced\rclose', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff8000", nextState:"Sent"
attributeState "open", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#00A0DC" , nextState:"Sent"
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#00A0DC"
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffffff", nextState:"Sent"
attributeState "closing", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffffff"
attributeState "jammed", label: '${name}', action:"closeDoorHiI", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
attributeState "forced close", label: 'forced\rclose', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff8000", nextState:"Sent"
attributeState "fault", label: 'FAULT', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
attributeState "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
@@ -135,13 +135,13 @@ metadata {
}
standardTile("autoClose", "device.autoCloseEnable", width: 2, height: 2){
state "on", label: 'Auto', action:"autoCloseOff", icon: "st.doors.garage.garage-closing", backgroundColor: "#79b821", nextState:"Sent"
state "on", label: 'Auto', action:"autoCloseOff", icon: "st.doors.garage.garage-closing", backgroundColor: "#00A0DC", nextState:"Sent"
state "off", label: 'Auto', action:"autoCloseOn", icon: "st.doors.garage.garage-closing", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
standardTile("autoOpen", "device.autoOpenEnable", width: 2, height: 2){
state "on", label: 'Auto', action:"autoOpenOff", icon: "st.doors.garage.garage-opening", backgroundColor: "#79b821", nextState:"Sent"
state "on", label: 'Auto', action:"autoOpenOff", icon: "st.doors.garage.garage-opening", backgroundColor: "#00A0DC", nextState:"Sent"
state "off", label: 'Auto', action:"autoOpenOn", icon: "st.doors.garage.garage-opening", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
@@ -189,13 +189,13 @@ metadata {
standardTile("aux1", "device.Aux1", width: 2, height: 2, canChangeIcon: true) {
state "off", label:'Aux 1', action:"Aux1On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent"
state "on", label:'Aux 1', action:"Aux1Off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"Sent"
state "on", label:'Aux 1', action:"Aux1Off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
standardTile("aux2", "device.Aux2", width: 2, height: 2, canChangeIcon: true) {
state "off", label:'Aux 2', action:"Aux2On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent"
state "on", label:'Aux 2', action:"Aux2Off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"Sent"
state "on", label:'Aux 2', action:"Aux2Off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}

View File

@@ -21,6 +21,7 @@ metadata {
capability "Battery"
fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x80,0x84,0x85"
fingerprint mfr: "0086", prod: "0001", model: "0026", deviceJoinName: "Aeon Panic Button"
}
simulator {
@@ -130,5 +131,12 @@ def updated() {
}
def initialize() {
sendEvent(name: "numberOfButtons", value: 4)
def zwMap = getZwaveInfo()
def buttons = 4 // Default for Key Fob
// Only one button for Aeon Panic Button
if (zwMap && zwMap.mfr == "0086" && zwMap.prod == "0001" && zwMap.model == "0026") {
buttons = 1
}
sendEvent(name: "numberOfButtons", value: buttons)
}

View File

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

View File

@@ -0,0 +1,43 @@
# Aeon Multisensor 6
Cloud Execution
Works with:
* [Aeon Labs MultiSensor 6](https://www.smartthings.com/products/aeon-labs-multisensor-6)
## 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
* **Ultraviolet Index** - gives the ability to get the ultraviolet index from devices that report 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 6 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 6 Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206157226)

View File

@@ -22,6 +22,7 @@ metadata {
capability "Configuration"
capability "Sensor"
capability "Battery"
capability "Health Check"
attribute "tamper", "enum", ["detected", "clear"]
attribute "batteryStatus", "string"
@@ -29,6 +30,7 @@ metadata {
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A"
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0x5A"
fingerprint mfr:"0086", prod:"0102", model:"0064", deviceJoinName: "Aeon Labs MultiSensor 6"
}
simulator {
@@ -103,7 +105,7 @@ metadata {
}
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
state "illuminance", label:'${currentValue} ${unit}', unit:"lux"
state "illuminance", label:'${currentValue} lux', unit:""
}
valueTile("ultravioletIndex", "device.ultravioletIndex", inactiveLabel: false, width: 2, height: 2) {
@@ -127,7 +129,14 @@ metadata {
}
}
def installed(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
log.debug "Updated with settings: ${settings}"
log.debug "${device.displayName} is now ${device.latestValue("powerSupply")}"
@@ -326,6 +335,13 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
createEvent(descriptionText: cmd.toString(), isStateChange: false)
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
secure(zwave.batteryV1.batteryGet())
}
def configure() {
// This sensor joins as a secure device if you double-click the button to include it
log.debug "${device.displayName} is configuring its settings"
@@ -410,4 +426,4 @@ private command(physicalgraph.zwave.Command cmd) {
private commands(commands, delay=200) {
log.info "sending commands: ${commands}"
delayBetween(commands.collect{ command(it) }, delay)
}
}

View File

@@ -86,7 +86,7 @@ metadata {
state "humidity", label:'${currentValue}% humidity', unit:""
}
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
state "luminosity", label:'${currentValue} ${unit}', unit:"lux"
state "luminosity", label:'${currentValue} lux', unit:""
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
@@ -282,5 +282,4 @@ private secure(physicalgraph.zwave.Command cmd) {
private secureSequence(commands, delay=200) {
delayBetween(commands.collect{ secure(it) }, delay)
}
}

View File

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

View File

@@ -0,0 +1,48 @@
# Aeon Multisensor
Cloud Execution
Works with:
* [Aeotec MultiSensor (DSB05-ZWUS)](https://www.smartthings.com/products/aeotec-multisensor-5)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
* [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 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
## Battery Specification
Four AAA 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:
* [Aeon MultiSensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206157226-How-to-connect-Aeon-Labs-MultiSensors)

View File

@@ -20,6 +20,7 @@ metadata {
capability "Illuminance Measurement"
capability "Sensor"
capability "Battery"
capability "Health Check"
fingerprint deviceId: "0x2001", inClusters: "0x30,0x31,0x80,0x84,0x70,0x85,0x72,0x86"
}
@@ -79,7 +80,7 @@ metadata {
state "humidity", label:'${currentValue}% humidity', unit:""
}
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
state "luminosity", label:'${currentValue} ${unit}', unit:"lux"
state "luminosity", label:'${currentValue} lux', unit:""
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
@@ -93,6 +94,16 @@ metadata {
}
}
def installed(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
// Parse incoming device messages to generate events
def parse(String description)
{
@@ -179,6 +190,13 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
[:]
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
secure(zwave.batteryV1.batteryGet())
}
def configure() {
delayBetween([
// send binary sensor report instead of basic set for motion
@@ -193,4 +211,4 @@ def configure() {
// set data reporting period to 5 minutes
zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 300).format()
])
}
}

View File

@@ -16,7 +16,7 @@
* Date: 2014-07-15
*/
metadata {
definition (name: "Aeon Siren", namespace: "smartthings", author: "SmartThings") {
definition (name: "Aeon Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.smoke") {
capability "Actuator"
capability "Alarm"
capability "Switch"
@@ -61,6 +61,8 @@ metadata {
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
response(secure(zwave.basicV1.basicGet()))
}
def updated() {
@@ -163,4 +165,4 @@ private secure(physicalgraph.zwave.Command cmd) {
* */
def ping() {
secure(zwave.basicV1.basicGet())
}
}

View File

@@ -9,6 +9,7 @@ metadata {
capability "Configuration"
capability "Refresh"
capability "Sensor"
capability "Health Check"
attribute "thermostatFanState", "string"
@@ -18,6 +19,7 @@ metadata {
command "quickSetHeat"
fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60"
fingerprint mfr:"0098", prod:"6401", model:"0107", deviceJoinName: "2Gig CT100 Programmable Thermostat"
}
// simulator metadata
@@ -106,6 +108,16 @@ 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 installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def parse(String description)
{
def result = []
@@ -439,6 +451,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"
refresh()
}
def configure() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),

View File

@@ -0,0 +1,163 @@
/**
* 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.
*
* Everspring ST815 Illuminance Sensor
*
* Author: SmartThings
* Date: 2017-3-4
*/
metadata {
definition (name: "Everspring Illuminance Sensor", namespace: "smartthings", author: "SmartThings") {
capability "Illuminance Measurement"
capability "Battery"
capability "Configuration"
capability "Sensor"
capability "Health Check"
fingerprint mfr:"0060", prod:"0007", model:"0001"
}
simulator {
for( int i = 0; i <= 100; i += 20 ) {
status "illuminace ${i} lux": new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
scaledSensorValue: i, precision: 0, sensorType: 3, scale: 1).incomingMessage()
}
for( int i = 0; i <= 100; i += 20 ) {
status "battery ${i}%": new physicalgraph.zwave.Zwave().batteryV1.batteryReport(
batteryLevel: i).incomingMessage()
}
status "wakeup": "command: 8407, payload: "
}
tiles(scale: 2) {
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
[value: 32, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 92, color: "#d04e00"],
[value: 98, color: "#bc2323"]
]
}
valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) {
state "humidity", label:'${currentValue}% humidity', unit:""
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
main( ["temperature", "humidity"] )
details( ["temperature", "humidity", "battery"] )
}
}
def updated() {
state.configured = false
}
def parse(String description) {
def result = []
def cmd = zwave.parse(description, [0x20: 1, 0x31: 2, 0x70: 1, 0x71: 1, 0x80: 1, 0x84: 2, 0x85: 2])
if (cmd) {
result = zwaveEvent(cmd)
}
if (result instanceof List) {
log.debug "Parsed '$description' to ${result.collect { it.respondsTo("toHubAction") ? it.toHubAction() : it }}"
} else {
log.debug "Parsed '$description' to ${result}"
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
def result = [
createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)
]
if (state.configured) {
result << response(zwave.batteryV1.batteryGet())
} else {
result << response(configure())
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.alarmv1.AlarmReport cmd) {
if (cmd.alarmType == 1 && cmd.alarmType == 0xFF) {
return createEvent(descriptionText: "${device.displayName} battery is low", isStateChange: true)
} else if (cmd.alarmType == 2 && cmd.alarmLevel == 1) {
return createEvent(descriptionText: "${device.displayName} powered up", isStateChange: false)
}
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd) {
def map = [:]
switch( cmd.sensorType ) {
case 3:
// luminance
map.value = cmd.scaledSensorValue.toInteger().toString()
map.unit = "lux"
map.name = "illuminance"
break;
}
return createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} has a low battery"
map.isStateChange = true
} else {
map.value = cmd.batteryLevel
}
def response_cmds = []
if (!currentTemperature) {
response_cmds << zwave.sensorMultilevelV2.sensorMultilevelGet().format()
response_cmds << "delay 1000"
}
response_cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
return [createEvent(map), response(response_cmds)]
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.debug "Unhandled: ${cmd.toString()}"
return [:]
}
def configure() {
state.configured = true
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
delayBetween([
// Auto report time interval in minutes
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 2, scaledConfigurationValue: 20).format(),
// Auto report lux change threshold
zwave.configurationV1.configurationSet(parameterNumber: 6, size: 2, scaledConfigurationValue: 30).format(),
// Get battery report triggers WakeUpNMI
zwave.batteryV1.batteryGet().format()
])
}

View File

@@ -0,0 +1,188 @@
/**
* 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.
*
* Everspring ST814 Temperature/Humidity Sensor
*
* Author: SmartThings
* Date: 2017-3-4
*/
metadata {
definition (name: "Everspring ST814", namespace: "smartthings", author: "SmartThings") {
capability "Temperature Measurement"
capability "Relative Humidity Measurement"
capability "Battery"
capability "Configuration"
capability "Sensor"
capability "Health Check"
fingerprint mfr:"0060", prod:"0006", model:"0001"
}
simulator {
for( int i = 0; i <= 100; i += 20 ) {
status "temperature ${i}F": new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1).incomingMessage()
}
for( int i = 0; i <= 100; i += 20 ) {
status "humidity ${i}%": new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
scaledSensorValue: i, precision: 0, sensorType: 5).incomingMessage()
}
for( int i = 0; i <= 100; i += 20 ) {
status "battery ${i}%": new physicalgraph.zwave.Zwave().batteryV1.batteryReport(
batteryLevel: i).incomingMessage()
}
status "wakeup": "command: 8407, payload: "
}
tiles(scale: 2) {
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
[value: 32, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 92, color: "#d04e00"],
[value: 98, color: "#bc2323"]
]
}
valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) {
state "humidity", label:'${currentValue}% humidity', unit:""
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
main( ["temperature", "humidity"] )
details( ["temperature", "humidity", "battery"] )
}
}
def updated() {
state.configured = false
}
def parse(String description) {
def result = []
def cmd = zwave.parse(description, [0x20: 1, 0x31: 2, 0x70: 1, 0x71: 1, 0x80: 1, 0x84: 2, 0x85: 2])
if (cmd) {
result = zwaveEvent(cmd)
}
if (result instanceof List) {
log.debug "Parsed '$description' to ${result.collect { it.respondsTo("toHubAction") ? it.toHubAction() : it }}"
} else {
log.debug "Parsed '$description' to ${result}"
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
def result = [
createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)
]
if (state.configured) {
result << response(zwave.batteryV1.batteryGet())
} else {
result << response(configure())
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.alarmv1.AlarmReport cmd) {
if (cmd.alarmType == 1 && cmd.alarmType == 0xFF) {
return createEvent(descriptionText: "${device.displayName} battery is low", isStateChange: true)
} else if (cmd.alarmType == 2 && cmd.alarmLevel == 1) {
return createEvent(descriptionText: "${device.displayName} powered up", isStateChange: false)
}
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd) {
def map = [:]
switch( cmd.sensorType ) {
case 1:
/* temperature */
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
break
case 5:
/* humidity */
map.value = cmd.scaledSensorValue.toInteger().toString()
map.unit = "%"
map.name = "humidity"
break
}
return createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} has a low battery"
map.isStateChange = true
} else {
map.value = cmd.batteryLevel
}
def response_cmds = []
if (!currentTemperature) {
response_cmds << zwave.sensorMultilevelV2.sensorMultilevelGet().format()
response_cmds << "delay 1000"
}
response_cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
return [createEvent(map), response(response_cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
def result = null
def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x31: 2, 0x70: 1, 0x71: 1, 0x80: 1, 0x84: 2, 0x85: 2])
log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")
if (encapsulatedCommand) {
result = zwaveEvent(encapsulatedCommand)
}
result
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.debug "Unhandled: ${cmd.toString()}"
return [:]
}
def configure() {
state.configured = true
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
delayBetween([
// Auto report time interval in minutes
zwave.configurationV1.configurationSet(parameterNumber: 6, size: 2, scaledConfigurationValue: 20).format(),
// Auto report temperature change threshold
zwave.configurationV1.configurationSet(parameterNumber: 7, size: 1, scaledConfigurationValue: 2).format(),
// Auto report humidity change threshold
zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: 5).format(),
// Get battery report triggers WakeUpNMI
zwave.batteryV1.batteryGet().format()
])
}

View File

@@ -68,8 +68,8 @@
tiles {
standardTile("contact", "device.contact", width: 2, height: 2) {
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
}
valueTile("temperature", "device.temperature", inactiveLabel: false) {
state "temperature", label:'${currentValue}°',
@@ -86,7 +86,7 @@
}
standardTile("tamper", "device.alarm") {
state("secure", label:'secure', icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#00a0dc")
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""

View File

@@ -107,8 +107,8 @@
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
}
standardTile("acceleration", "device.acceleration") {
state("active", label:'vibration', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
state("inactive", label:'still', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
state("active", label:'vibration', icon:"st.motion.acceleration.active", backgroundColor:"#00a0dc")
state("inactive", label:'still', icon:"st.motion.acceleration.inactive", backgroundColor:"#cccccc")
}

View File

@@ -12,13 +12,13 @@
*
*/
metadata {
definition (name: "Fortrezz Water Valve", namespace: "smartthings", author: "SmartThings") {
definition (name: "Fortrezz Water Valve", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.watervalve") {
capability "Actuator"
capability "Health Check"
capability "Valve"
capability "Refresh"
capability "Sensor"
fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70"
fingerprint mfr:"0084", prod:"0213", model:"0215", deviceJoinName: "FortrezZ Water Valve"
}
@@ -34,19 +34,22 @@ metadata {
}
// tile definitions
tiles {
standardTile("contact", "device.contact", width: 2, height: 2, canChangeIcon: true) {
state "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
state "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
state "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
state "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
tiles(scale: 2) {
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.valve", key: "PRIMARY_CONTROL") {
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
attributeState "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
}
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
standardTile("refresh", "device.valve", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
}
main "contact"
details(["contact","refresh"])
main "valve"
details(["valve","refresh"])
}
}
@@ -62,22 +65,23 @@ def updated(){
def parse(String description) {
log.trace description
def result = null
def cmd = zwave.parse(description)
if (cmd) {
result = createEvent(zwaveEvent(cmd))
return zwaveEvent(cmd)
}
log.debug "Parse returned ${result?.descriptionText}"
return result
log.debug "Could not parse message"
return null
}
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
def value = cmd.value ? "closed" : "open"
[name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]
return [createEventWithDebug([name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]),
createEventWithDebug([name: "valve", value: value, descriptionText: "$device.displayName valve is $value"])]
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
[:] // Handles all Z-Wave commands we aren't interested in
return createEvent([:]) // Handles all Z-Wave commands we aren't interested in
}
def open() {
@@ -98,3 +102,9 @@ def ping() {
def refresh() {
zwave.switchBinaryV1.switchBinaryGet().format()
}
def createEventWithDebug(eventMap) {
def event = createEvent(eventMap)
log.debug "Event created with ${event?.descriptionText}"
return event
}

View File

@@ -62,8 +62,8 @@ metadata {
state "off", label: '${name}', action: "on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
}
standardTile("contact", "device.contact", inactiveLabel: false) {
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"

View File

@@ -4,7 +4,7 @@ Cloud Execution
Works with:
* [FortrezZ Siren Strobe Alarm](https://www.smartthings.com/works-with-smartthings/other/fortrezz-water-valve)
* [FortrezZ Siren Strobe Alarm](https://www.smartthings.com/products/fortrezz-siren-strobe-alarm)
## Table of contents

View File

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

View File

@@ -44,9 +44,9 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", 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"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {

View File

@@ -29,6 +29,7 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200", deviceJoinName: "Outlet"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200-Sgb", deviceJoinName: "Outlet"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-RZHAC", deviceJoinName: "Outlet"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 000F, 0B04", outClusters: "0019", manufacturer: "SmartThings", model: "outletv4", deviceJoinName: "Outlet"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019"
}

View File

@@ -56,8 +56,8 @@ metadata {
state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#00A0DC")
}
standardTile("contact", "device.contact") {
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
}
standardTile("acceleration", "device.acceleration", decoration: "flat") {
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC")

View File

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

View File

@@ -87,8 +87,8 @@ metadata {
state("closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc")
}
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
state("active", label: 'Active', icon: "st.motion.acceleration.active", backgroundColor: "#53a7c0")
state("inactive", label: 'Inactive', icon: "st.motion.acceleration.inactive", backgroundColor: "#ffffff")
state("active", label: 'Active', icon: "st.motion.acceleration.active", backgroundColor: "#00a0dc")
state("inactive", label: 'Inactive', icon: "st.motion.acceleration.inactive", backgroundColor: "#cccccc")
}
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label: '${currentValue}°',
@@ -178,7 +178,7 @@ private List<Map> handleAcceleration(descMap) {
result += parseAxis(descMap.additionalAttrs)
}
} else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012) {
def addAttrs = descMap.additionalAttrs
def addAttrs = descMap.additionalAttrs ?: []
addAttrs << ["attrInt": descMap.attrInt, "value": descMap.value]
result += parseAxis(addAttrs)
}

View File

@@ -22,16 +22,16 @@ metadata {
tiles {
standardTile("contact", "device.contact", width: 2, height: 2) {
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821", action: "open")
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e", action: "close")
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC", action: "open")
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13", action: "close")
}
standardTile("freezerDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
}
standardTile("mainDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
}
standardTile("control", "device.contact", width: 1, height: 1, decoration: "flat") {
state("closed", label:'${name}', icon:"st.contact.contact.closed", action: "open")

View File

@@ -25,8 +25,8 @@ metadata {
tiles(scale: 2) {
standardTile("contact", "device.contact", width: 4, height: 4) {
state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#79b821")
state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#ffa81e")
state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#00A0DC")
state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#e86d13")
}
childDeviceTile("freezerDoor", "freezerDoor", height: 2, width: 2, childTileName: "freezerDoor")
childDeviceTile("mainDoor", "mainDoor", height: 2, width: 2, childTileName: "mainDoor")

View File

@@ -27,7 +27,7 @@ metadata {
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", 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"
}
}
@@ -35,7 +35,7 @@ metadata {
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOn", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute("device.level", key: "SECONDARY_CONTROL") {
@@ -59,7 +59,7 @@ metadata {
tileAttribute("device.switch", key: "SECONDARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'…', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOn", label:'…', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'…', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute("device.level", key: "VALUE_CONTROL") {

View File

@@ -40,11 +40,11 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#ff0000"
attributeState "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#cccccc"
}
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
attributeState "currentIP", label: ''

View File

@@ -46,8 +46,8 @@
}
standardTile("motion", "device.motion", width: 2, height: 2) {
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#CCCCCC")
state("offline", label:'${name}', icon:"st.motion.motion.inactive", backgroundColor:"#ff0000")
}

View File

@@ -38,11 +38,11 @@
tiles(scale: 2) {
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ff0000"
attributeState "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#cccccc"
}
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
attributeState "currentIP", label: ''
@@ -50,11 +50,11 @@
}
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
state "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ff0000"
state "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#cccccc"
}
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {

View File

@@ -25,6 +25,7 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart A19 Soft White"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM 10 Year", deviceJoinName: "SYLVANIA Smart 10-Year A19"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FF00", outClusters: "0019", manufacturer: "MRVL", model: "MZ100", deviceJoinName: "Wemo Bulb"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05", outClusters: "0019", manufacturer: "OSRAM SYLVANIA", model: "iQBR30", deviceJoinName: "Sylvania Ultra iQ"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY PAR38 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart PAR38 Soft White"

View File

@@ -34,7 +34,7 @@ import physicalgraph.zigbee.zcl.DataType
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226/246 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226/246 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
}
tiles(scale: 2) {

View File

@@ -46,9 +46,9 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {

View File

@@ -27,7 +27,6 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "0003, 000A, 0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE ZigBee Plug-In Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE ZigBee In-Wall Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 000F, 0B04", outClusters: "0019", manufacturer: "SmartThings", model: "outletv4", deviceJoinName: "Outlet"
}
tiles(scale: 2) {

View File

@@ -41,9 +41,9 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
}

View File

@@ -39,7 +39,7 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
tileAttribute ("device.valve", key: "PRIMARY_CONTROL") {
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
@@ -83,6 +83,9 @@ def parse(String description) {
}
}
sendEvent(event)
//handle valve attribute
event.name = "valve"
sendEvent(event)
}
else {
def descMap = zigbee.parseDescriptionAsMap(description)

View File

@@ -45,9 +45,9 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
@@ -71,6 +71,11 @@ metadata {
}
}
// Globals
private getMOVE_TO_COLOR_TEMPERATURE_COMMAND() { 0x0A }
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
@@ -146,7 +151,7 @@ def setColorTemperature(value) {
def tempInMired = (1000000 / value) as Integer
def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4))
zigbee.command(COLOR_CONTROL_CLUSTER, 0x0A, "$finalHex 0000") +
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_COLOR_TEMPERATURE_COMMAND, "$finalHex 0000") +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE)
}

View File

@@ -49,9 +49,9 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {

View File

@@ -66,6 +66,11 @@ metadata {
}
}
// Globals
private getMOVE_TO_COLOR_TEMPERATURE_COMMAND() { 0x0A }
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
@@ -152,7 +157,7 @@ def setColorTemperature(value) {
def tempInMired = (1000000 / value) as Integer
def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4))
zigbee.command(COLOR_CONTROL_CLUSTER, 0x0A, "$finalHex 0000") +
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_COLOR_TEMPERATURE_COMMAND, "$finalHex 0000") +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE)
}

View File

@@ -68,6 +68,11 @@ metadata {
}
}
// Globals
private getMOVE_TO_COLOR_TEMPERATURE_COMMAND() { 0x0A }
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
@@ -147,7 +152,7 @@ def setColorTemperature(value) {
def tempInMired = (1000000 / value) as Integer
def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4))
zigbee.command(COLOR_CONTROL_CLUSTER, 0x0A, "$finalHex 0000") +
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_COLOR_TEMPERATURE_COMMAND, "$finalHex 0000") +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE)
}

View File

@@ -75,6 +75,10 @@ def parse(String description) {
return result
}
def uninstalled() {
sendEvent(name: "epEvent", value: "delete all", isStateChange: true, displayed: false, descriptionText: "Delete endpoint devices")
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
[ createEvent(descriptionText: "${device.displayName} woke up", isStateChange:true),
response(["delay 2000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]) ]

View File

@@ -30,9 +30,15 @@ metadata {
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)"
fingerprint mfr:"014A", prod:"0001", model:"0002", deviceJoinName: "Ecolink Door/Window Sensor"
fingerprint mfr:"0086", prod:"0102", model:"0070", deviceJoinName: "Aeon Labs Door/Window Sensor 6"
fingerprint mfr:"0086", prod:"0102", model:"0059", deviceJoinName: "Aeon Labs Recessed Door Sensor"
fingerprint mfr:"014A", prod:"0001", model:"0002", deviceJoinName: "Ecolink Door/Window Sensor"
fingerprint mfr:"014A", prod:"0001", model:"0003", deviceJoinName: "Ecolink Tilt Sensor"
fingerprint mfr:"011A", prod:"0601", model:"0903", deviceJoinName: "Enerwave Magnetic Door/Window Sensor"
fingerprint mfr:"014F", prod:"2001", model:"0102", deviceJoinName: "Nortek GoControl Door/Window Sensor"
fingerprint mfr:"0063", prod:"4953", model:"3031", deviceJoinName: "Jasco Hinge Pin Door Sensor"
fingerprint mfr:"019A", prod:"0003", model:"0003", deviceJoinName: "Sensative Strips"
}
// simulator metadata
@@ -107,9 +113,9 @@ def updated() {
def configure() {
commands([
zwave.manufacturerSpecificV2.manufacturerSpecificGet(),
zwave.batteryV1.batteryGet()
], 6000)
zwave.sensorBinaryV2.sensorBinaryGet(sensorType: zwave.sensorBinaryV2.SENSOR_TYPE_DOOR_WINDOW),
zwave.manufacturerSpecificV2.manufacturerSpecificGet()
], 1000)
}
def sensorValueEvent(value) {
@@ -184,11 +190,17 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
cmds << command(zwave.manufacturerSpecificV2.manufacturerSpecificGet())
cmds << "delay 1200"
}
if (device.currentValue("contact") == null) { // Incase our initial request didn't make it
cmds << command(zwave.sensorBinaryV2.sensorBinaryGet(sensorType: zwave.sensorBinaryV2.SENSOR_TYPE_DOOR_WINDOW))
}
if (!state.lastbat || now() - state.lastbat > 53*60*60*1000) {
cmds << command(zwave.batteryV1.batteryGet())
} else {
} else { // If we check the battery state we will send NoMoreInfo in the handler for BatteryReport so that we definitely get the report
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
}
[event, response(cmds)]
}

View File

@@ -26,7 +26,24 @@ metadata {
fingerprint deviceId: "0x4003", inClusters: "0x98"
fingerprint deviceId: "0x4004", inClusters: "0x98"
fingerprint mfr:"0129", prod:"0002", model:"0000", deviceJoinName: "Yale Key Free Touchscreen Deadbolt"
fingerprint mfr:"0090", prod:"0001", model:"0236", deviceJoinName: "KwikSet SmartCode 910 Deadbolt Door Lock"
fingerprint mfr:"0090", prod:"0003", model:"0238", deviceJoinName: "KwikSet SmartCode 910 Deadbolt Door Lock"
fingerprint mfr:"0090", prod:"0001", model:"0001", deviceJoinName: "KwikSet SmartCode 910 Contemporary Deadbolt Door Lock"
fingerprint mfr:"0090", prod:"0003", model:"0339", deviceJoinName: "KwikSet SmartCode 912 Lever Door Lock"
fingerprint mfr:"0090", prod:"0003", model:"4006", deviceJoinName: "KwikSet SmartCode 914 Deadbolt Door Lock" //backlit version
fingerprint mfr:"0090", prod:"0003", model:"0440", deviceJoinName: "KwikSet SmartCode 914 Deadbolt Door Lock"
fingerprint mfr:"0090", prod:"0001", model:"0642", deviceJoinName: "KwikSet SmartCode 916 Touchscreen Deadbolt Door Lock"
fingerprint mfr:"0090", prod:"0003", model:"0642", deviceJoinName: "KwikSet SmartCode 916 Touchscreen Deadbolt Door Lock"
fingerprint mfr:"003B", prod:"6341", model:"0544", deviceJoinName: "Schlage Camelot Touchscreen Deadbolt Door Lock"
fingerprint mfr:"003B", prod:"6341", model:"5044", deviceJoinName: "Schlage Century Touchscreen Deadbolt Door Lock"
fingerprint mfr:"003B", prod:"634B", model:"504C", deviceJoinName: "Schlage Connected Keypad Lever Door Lock"
fingerprint mfr:"0129", prod:"0002", model:"0800", deviceJoinName: "Yale Touchscreen Deadbolt Door Lock" // YRD120
fingerprint mfr:"0129", prod:"0002", model:"0000", deviceJoinName: "Yale Touchscreen Deadbolt Door Lock" // YRD220, YRD240
fingerprint mfr:"0129", prod:"0002", model:"FFFF", deviceJoinName: "Yale Touchscreen Lever Door Lock" // YRD220
fingerprint mfr:"0129", prod:"0004", model:"0800", deviceJoinName: "Yale Push Button Deadbolt Door Lock" // YRD110
fingerprint mfr:"0129", prod:"0004", model:"0000", deviceJoinName: "Yale Push Button Deadbolt Door Lock" // YRD210
fingerprint mfr:"0129", prod:"0001", model:"0000", deviceJoinName: "Yale Push Button Lever Door Lock" // YRD210
fingerprint mfr:"0129", prod:"8002", model:"0600", deviceJoinName: "Yale Assure Lock with Bluetooth"
}
simulator {
@@ -69,13 +86,13 @@ import physicalgraph.zwave.commands.doorlockv1.*
import physicalgraph.zwave.commands.usercodev1.*
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
// Device-Watch pings if no device events received for 1 hour (checkInterval)
sendEvent(name: "checkInterval", value: 1 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
// Device-Watch pings if no device events received for 1 hour (checkInterval)
sendEvent(name: "checkInterval", value: 1 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
try {
if (!state.init) {
state.init = true
@@ -135,6 +152,10 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupported
def zwaveEvent(DoorLockOperationReport cmd) {
def result = []
unschedule("followupStateCheck")
unschedule("stateCheck")
def map = [ name: "lock" ]
if (cmd.doorLockMode == 0xFF) {
map.value = "locked"
@@ -348,7 +369,7 @@ def zwaveEvent(UserCodeReport cmd) {
code = state["set$name"] ?: decrypt(state[name]) ?: "****"
state.remove("set$name".toString())
} else {
map = [ name: "codeReport", value: cmd.userIdentifier, data: [ code: code ] ]
map = [ name: "codeReport", value: cmd.userIdentifier, data: [ code: code ], isStateChange: true ]
map.descriptionText = "$device.displayName code $cmd.userIdentifier is set"
map.displayed = (cmd.userIdentifier != state.requestCode && cmd.userIdentifier != state.pollCode)
map.isStateChange = true
@@ -439,11 +460,12 @@ def zwaveEvent(physicalgraph.zwave.commands.timev1.TimeGet cmd) {
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
// The old Schlage locks use group 1 for basic control - we don't want that, so unsubscribe from group 1
def result = [ createEvent(name: "lock", value: cmd.value ? "unlocked" : "locked") ]
result << response(zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId))
if (state.assoc != zwaveHubNodeId) {
result << response(zwave.associationV1.associationGet(groupingIdentifier:2))
}
result
def cmds = [
zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format(),
"delay 1200",
zwave.associationV1.associationGet(groupingIdentifier:2).format()
]
[result, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
@@ -513,11 +535,18 @@ def unlockwtimeout() {
lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT)
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
runIn(30, followupStateCheck)
secure(zwave.doorLockV1.doorLockOperationGet())
}
def followupStateCheck() {
runEvery1Hour(stateCheck)
stateCheck()
}
def stateCheck() {
sendHubCommand(new physicalgraph.device.HubAction(secure(zwave.doorLockV1.doorLockOperationGet())))
}
def refresh() {

View File

@@ -29,7 +29,7 @@ metadata {
fingerprint mfr: "0060", prod: "0001", model: "0002", deviceJoinName: "Everspring Motion Sensor" // Everspring SP814
fingerprint mfr: "0060", prod: "0001", model: "0003", deviceJoinName: "Everspring Motion Sensor" // Everspring HSP02
fingerprint mfr: "011A", prod: "0601", model: "0901", deviceJoinName: "Enerwave Motion Sensor" // Enerwave ZWN-BPC
fingerprint mfr: "0063", prod: "4953", model: "3133", deviceJoinName: "GE Smart Motion Sensor"
fingerprint mfr: "0063", prod: "4953", model: "3133", deviceJoinName: "GE Portable Smart Motion Sensor"
}
simulator {

View File

@@ -37,8 +37,8 @@ metadata {
tiles {
standardTile("motion", "device.motion", width: 3, height: 2) {
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#CCCCCC"
}
valueTile("temperature", "device.temperature", inactiveLabel: false) {

View File

@@ -16,7 +16,7 @@
* Date: 2014-07-15
*/
metadata {
definition (name: "Z-Wave Siren", namespace: "smartthings", author: "SmartThings") {
definition (name: "Z-Wave Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.smoke") {
capability "Actuator"
capability "Alarm"
capability "Battery"

View File

@@ -22,6 +22,7 @@ metadata {
attribute "alarmState", "string"
fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86"
fingerprint mfr:"0138", prod:"0001", model:"0001", deviceJoinName: "First Alert Smoke Detector"
fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)"
}

View File

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

View File

@@ -0,0 +1,38 @@
# Z-Wave Water Valve
Cloud Execution
Works with:
* [Leak Intelligence Leak Gopher Water Shutoff Valve](https://www.smartthings.com/works-with-smartthings/other/leak-intelligence-leak-gopher-water-shutoff-valve)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Health Check** - indicates ability to get device health notifications
* **Valve** - allows for the control of a valve device
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
## Device Health
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Leak Intelligence Leak Gopher Water Shutoff Valve Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/209631423-Leak-Gopher-Z-Wave-Valve-Control)

View File

@@ -12,14 +12,16 @@
*
*/
metadata {
definition (name: "Z-Wave Water Valve", namespace: "smartthings", author: "SmartThings") {
definition (name: "Z-Wave Water Valve", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.watervalve") {
capability "Actuator"
capability "Health Check"
capability "Valve"
capability "Polling"
capability "Refresh"
capability "Sensor"
fingerprint deviceId: "0x1006", inClusters: "0x25"
fingerprint mfr:"0173", prod:"0003", model:"0002", deviceJoinName: "Leak Intelligence Leak Gopher Water Shutoff Valve"
}
// simulator metadata
@@ -35,7 +37,7 @@ metadata {
// tile definitions
tiles(scale: 2) {
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
tileAttribute ("device.valve", key: "PRIMARY_CONTROL") {
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
@@ -43,7 +45,7 @@ metadata {
}
}
standardTile("refresh", "device.contact", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
standardTile("refresh", "device.valve", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
}
@@ -53,24 +55,32 @@ metadata {
}
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
response(refresh())
}
def parse(String description) {
log.trace "parse description : $description"
def result = null
def cmd = zwave.parse(description, [0x20: 1])
if (cmd) {
result = createEvent(zwaveEvent(cmd))
return zwaveEvent(cmd)
}
log.debug "Parse returned ${result?.descriptionText}"
return result
log.debug "Could not parse message"
return null
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown"
[name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]
def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown"
return [createEventWithDebug([name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]),
createEventWithDebug([name: "valve", value: value, descriptionText: "$device.displayName valve is $value"])]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { //TODO should show MSR when device is discovered
@@ -80,20 +90,22 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
log.debug "productTypeId: ${cmd.productTypeId}"
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
updateDataValue("MSR", msr)
[descriptionText: "$device.displayName MSR: $msr", isStateChange: false]
return createEventWithDebug([descriptionText: "$device.displayName MSR: $msr", isStateChange: false])
}
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
[descriptionText: cmd.toString(), isStateChange: true, displayed: true]
return createEventWithDebug([descriptionText: cmd.toString(), isStateChange: true, displayed: true])
}
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown"
[name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]
return [createEventWithDebug([name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]),
createEventWithDebug([name: "valve", value: value, descriptionText: "$device.displayName valve is $value"])]
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
[:] // Handles all Z-Wave commands we aren't interested in
return createEvent([:]) // Handles all Z-Wave commands we aren't interested in
}
def open() {
@@ -114,6 +126,13 @@ def poll() {
zwave.switchBinaryV1.switchBinaryGet().format()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() {
log.debug "refresh() is called"
def commands = [zwave.switchBinaryV1.switchBinaryGet().format()]
@@ -122,3 +141,9 @@ def refresh() {
}
delayBetween(commands,100)
}
def createEventWithDebug(eventMap) {
def event = createEvent(eventMap)
log.debug "Event created with ${event?.descriptionText}"
return event
}

View File

@@ -765,7 +765,6 @@ def turnOffSwitch() {
} else {
device.off();
return [Device_id: params.id, result_action: "200"]
}
}
@@ -789,6 +788,7 @@ def getTempSensorsStatus(id) {
return []
} else {
def bat = getBatteryStatus(device.id)
return [temperature: device.currentValue('temperature')] + bat
def scale = [Scale: location.temperatureScale]
return [temperature: device.currentValue('temperature')] + bat + scale
}
}
}

View File

@@ -15,66 +15,66 @@ definition(
)
preferences {
section("Light switches to turn off") {
input "switches", "capability.switch", title: "Choose light switches", multiple: true
}
section("Turn off when there is no motion and presence") {
input "motionSensor", "capability.motionSensor", title: "Choose motion sensor"
input "presenceSensors", "capability.presenceSensor", title: "Choose presence sensors", multiple: true
}
section("Delay before turning off") {
input "delayMins", "number", title: "Minutes of inactivity?"
}
section("Light switches to turn off") {
input "switches", "capability.switch", title: "Choose light switches", multiple: true
}
section("Turn off when there is no motion and presence") {
input "motionSensor", "capability.motionSensor", title: "Choose motion sensor"
input "presenceSensors", "capability.presenceSensor", title: "Choose presence sensors", multiple: true
}
section("Delay before turning off") {
input "delayMins", "number", title: "Minutes of inactivity?"
}
}
def installed() {
subscribe(motionSensor, "motion", motionHandler)
subscribe(presenceSensors, "presence", presenceHandler)
subscribe(motionSensor, "motion", motionHandler)
subscribe(presenceSensors, "presence", presenceHandler)
}
def updated() {
unsubscribe()
subscribe(motionSensor, "motion", motionHandler)
subscribe(presenceSensors, "presence", presenceHandler)
unsubscribe()
subscribe(motionSensor, "motion", motionHandler)
subscribe(presenceSensors, "presence", presenceHandler)
}
def motionHandler(evt) {
log.debug "handler $evt.name: $evt.value"
if (evt.value == "inactive") {
runIn(delayMins * 60, scheduleCheck, [overwrite: false])
}
log.debug "handler $evt.name: $evt.value"
if (evt.value == "inactive") {
runIn(delayMins * 60, scheduleCheck, [overwrite: true])
}
}
def presenceHandler(evt) {
log.debug "handler $evt.name: $evt.value"
if (evt.value == "not present") {
runIn(delayMins * 60, scheduleCheck, [overwrite: false])
}
log.debug "handler $evt.name: $evt.value"
if (evt.value == "not present") {
runIn(delayMins * 60, scheduleCheck, [overwrite: true])
}
}
def isActivePresence() {
// check all the presence sensors, make sure none are present
def noPresence = presenceSensors.find{it.currentPresence == "present"} == null
!noPresence
// check all the presence sensors, make sure none are present
def noPresence = presenceSensors.find{it.currentPresence == "present"} == null
!noPresence
}
def scheduleCheck() {
log.debug "scheduled check"
def motionState = motionSensor.currentState("motion")
log.debug "scheduled check"
def motionState = motionSensor.currentState("motion")
if (motionState.value == "inactive") {
def elapsed = now() - motionState.rawDateCreated.time
def threshold = 1000 * 60 * delayMins - 1000
if (elapsed >= threshold) {
if (!isActivePresence()) {
log.debug "Motion has stayed inactive since last check ($elapsed ms) and no presence: turning lights off"
switches.off()
} else {
log.debug "Presence is active: do nothing"
}
} else {
log.debug "Motion has not stayed inactive long enough since last check ($elapsed ms): do nothing"
def elapsed = now() - motionState.rawDateCreated.time
def threshold = 1000 * 60 * delayMins - 1000
if (elapsed >= threshold) {
if (!isActivePresence()) {
log.debug "Motion has stayed inactive since last check ($elapsed ms) and no presence: turning lights off"
switches.off()
} else {
log.debug "Presence is active: do nothing"
}
} else {
log.debug "Motion has not stayed inactive long enough since last check ($elapsed ms): do nothing"
}
} else {
log.debug "Motion is active: do nothing"
log.debug "Motion is active: do nothing"
}
}
}

View File

@@ -1,3 +1,7 @@
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
/**
* OpenT2T SmartApp Test
*
@@ -39,7 +43,7 @@ definition(
* garageDoors | door | open, close | unknown, closed, open, closing, opening
* cameras | image | take | <String>
* thermostats | thermostat | setHeatingSetpoint, | temperature, heatingSetpoint, coolingSetpoint,
* | | setCoolingSetpoint, | thermostatSetpoint, thermostatMode,
* | | setCoolingSetpoint, | thermostatSetpoint, thermostatMode,
* | | off, heat, cool, auto,| thermostatFanMode, thermostatOperatingState
* | | emergencyHeat, |
* | | setThermostatMode, |
@@ -55,7 +59,7 @@ preferences {
input "contactSensors", "capability.contactSensor", title: "Which Contact Sensors", multiple: true, required: false, hideWhenEmpty: true
input "garageDoors", "capability.garageDoorControl", title: "Which Garage Doors?", multiple: true, required: false, hideWhenEmpty: true
input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false, hideWhenEmpty: true
input "cameras", "capability.videoCapture", title: "Which Cameras?", multiple: true, required: false, hideWhenEmpty: true
input "cameras", "capability.videoCapture", title: "Which Cameras?", multiple: true, required: false, hideWhenEmpty: true
input "motionSensors", "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false, hideWhenEmpty: true
input "presenceSensors", "capability.presenceSensor", title: "Which Presence Sensors", multiple: true, required: false, hideWhenEmpty: true
input "switches", "capability.switch", title: "Which Switches and Lights?", multiple: true, required: false, hideWhenEmpty: true
@@ -66,44 +70,49 @@ preferences {
def getInputs() {
def inputList = []
inputList += contactSensors?: []
inputList += garageDoors?: []
inputList += locks?: []
inputList += cameras?: []
inputList += motionSensors?: []
inputList += presenceSensors?: []
inputList += switches?: []
inputList += thermostats?: []
inputList += waterSensors?: []
inputList += contactSensors ?: []
inputList += garageDoors ?: []
inputList += locks ?: []
inputList += cameras ?: []
inputList += motionSensors ?: []
inputList += presenceSensors ?: []
inputList += switches ?: []
inputList += thermostats ?: []
inputList += waterSensors ?: []
return inputList
}
//API external Endpoints
mappings {
path("/devices") {
action: [
action:
[
GET: "getDevices"
]
}
path("/devices/:id") {
action: [
action:
[
GET: "getDevice"
]
}
path("/update/:id") {
action: [
action:
[
PUT: "updateDevice"
]
}
path("/deviceSubscription") {
action: [
POST: "registerDeviceChange",
action:
[
POST : "registerDeviceChange",
DELETE: "unregisterDeviceChange"
]
}
path("/locationSubscription") {
action: [
POST: "registerDeviceGraph",
action:
[
POST : "registerDeviceGraph",
DELETE: "unregisterDeviceGraph"
]
}
@@ -116,14 +125,21 @@ def installed() {
def updated() {
log.debug "Updating with settings: ${settings}"
if(state.deviceSubscriptionMap == null){
//Initialize state variables if didn't exist.
if (state.deviceSubscriptionMap == null) {
state.deviceSubscriptionMap = [:]
log.debug "deviceSubscriptionMap created."
}
if( state.locationSubscriptionMap == null){
if (state.locationSubscriptionMap == null) {
state.locationSubscriptionMap = [:]
log.debug "locationSubscriptionMap created."
}
if (state.verificationKeyMap == null) {
state.verificationKeyMap = [:]
log.debug "verificationKeyMap created."
}
unsubscribe()
registerAllDeviceSubscriptions()
}
@@ -132,9 +148,11 @@ def initialize() {
log.debug "Initializing with settings: ${settings}"
state.deviceSubscriptionMap = [:]
log.debug "deviceSubscriptionMap created."
registerAllDeviceSubscriptions()
state.locationSubscriptionMap = [:]
log.debug "locationSubscriptionMap created."
state.verificationKeyMap = [:]
log.debug "verificationKeyMap created."
registerAllDeviceSubscriptions()
}
/*** Subscription Functions ***/
@@ -148,7 +166,7 @@ def registerAllDeviceSubscriptions() {
def registerChangeHandler(myList) {
myList.each { myDevice ->
def theAtts = myDevice.supportedAttributes
theAtts.each {att ->
theAtts.each { att ->
subscribe(myDevice, att.name, deviceEventHandler)
log.info "Registering for ${myDevice.displayName}.${att.name}"
}
@@ -160,31 +178,38 @@ def registerDeviceChange() {
def subscriptionEndpt = params.subscriptionURL
def deviceId = params.deviceId
def myDevice = findDevice(deviceId)
if( myDevice == null ){
if (myDevice == null) {
httpError(404, "Cannot find device with device ID ${deviceId}.")
}
def theAtts = myDevice.supportedAttributes
try {
theAtts.each {att ->
theAtts.each { att ->
subscribe(myDevice, att.name, deviceEventHandler)
}
log.info "Subscribing for ${myDevice.displayName}"
if(subscriptionEndpt != null){
if(state.deviceSubscriptionMap[deviceId] == null){
if (subscriptionEndpt != null) {
if (state.deviceSubscriptionMap[deviceId] == null) {
state.deviceSubscriptionMap.put(deviceId, [subscriptionEndpt])
log.info "Added subscription URL: ${subscriptionEndpt} for ${myDevice.displayName}"
} else if (!state.deviceSubscriptionMap[deviceId].contains(subscriptionEndpt)){
} else if (!state.deviceSubscriptionMap[deviceId].contains(subscriptionEndpt)) {
state.deviceSubscriptionMap[deviceId] << subscriptionEndpt
log.info "Added subscription URL: ${subscriptionEndpt} for ${myDevice.displayName}"
}
if (params.key != null) {
state.verificationKeyMap[subscriptionEndpt] = params.key
log.info "Added verification key: ${params.key} for ${subscriptionEndpt}"
}
}
} catch (e) {
httpError(500, "something went wrong: $e")
}
log.info "Current subscription map is ${state.deviceSubscriptionMap}"
log.info "Current verification key map is ${state.verificationKeyMap}"
return ["succeed"]
}
@@ -194,18 +219,19 @@ def unregisterDeviceChange() {
def deviceId = params.deviceId
def myDevice = findDevice(deviceId)
if( myDevice == null ){
if (myDevice == null) {
httpError(404, "Cannot find device with device ID ${deviceId}.")
}
try {
if(subscriptionEndpt != null && subscriptionEndpt != "undefined"){
if (state.deviceSubscriptionMap[deviceId]?.contains(subscriptionEndpt)){
if(state.deviceSubscriptionMap[deviceId].size() == 1){
if (subscriptionEndpt != null && subscriptionEndpt != "undefined") {
if (state.deviceSubscriptionMap[deviceId]?.contains(subscriptionEndpt)) {
if (state.deviceSubscriptionMap[deviceId].size() == 1) {
state.deviceSubscriptionMap.remove(deviceId)
} else {
state.deviceSubscriptionMap[deviceId].remove(subscriptionEndpt)
}
state.verificationKeyMap.remove(subscriptionEndpt)
log.info "Removed subscription URL: ${subscriptionEndpt} for ${myDevice.displayName}"
}
} else {
@@ -217,25 +243,33 @@ def unregisterDeviceChange() {
}
log.info "Current subscription map is ${state.deviceSubscriptionMap}"
log.info "Current verification key map is ${state.verificationKeyMap}"
}
//Endpoints function: Subscribe to device additiona/removal updated in a location
def registerDeviceGraph() {
def subscriptionEndpt = params.subscriptionURL
if (subscriptionEndpt != null && subscriptionEndpt != "undefined"){
if (subscriptionEndpt != null && subscriptionEndpt != "undefined") {
subscribe(location, "DeviceCreated", locationEventHandler, [filterEvents: false])
subscribe(location, "DeviceUpdated", locationEventHandler, [filterEvents: false])
subscribe(location, "DeviceDeleted", locationEventHandler, [filterEvents: false])
if(state.locationSubscriptionMap[location.id] == null){
if (state.locationSubscriptionMap[location.id] == null) {
state.locationSubscriptionMap.put(location.id, [subscriptionEndpt])
log.info "Added subscription URL: ${subscriptionEndpt} for Location ${location.name}"
} else if (!state.locationSubscriptionMap[location.id].contains(subscriptionEndpt)){
} else if (!state.locationSubscriptionMap[location.id].contains(subscriptionEndpt)) {
state.locationSubscriptionMap[location.id] << subscriptionEndpt
log.info "Added subscription URL: ${subscriptionEndpt} for Location ${location.name}"
}
if (params.key != null) {
state.verificationKeyMap[subscriptionEndpt] = params.key
log.info "Added verification key: ${params.key} for ${subscriptionEndpt}"
}
log.info "Current location subscription map is ${state.locationSubscriptionMap}"
log.info "Current verification key map is ${state.verificationKeyMap}"
return ["succeed"]
} else {
httpError(400, "missing input parameter: subscriptionURL")
@@ -247,16 +281,17 @@ def unregisterDeviceGraph() {
def subscriptionEndpt = params.subscriptionURL
try {
if(subscriptionEndpt != null && subscriptionEndpt != "undefined"){
if (state.locationSubscriptionMap[location.id]?.contains(subscriptionEndpt)){
if(state.locationSubscriptionMap[location.id].size() == 1){
if (subscriptionEndpt != null && subscriptionEndpt != "undefined") {
if (state.locationSubscriptionMap[location.id]?.contains(subscriptionEndpt)) {
if (state.locationSubscriptionMap[location.id].size() == 1) {
state.locationSubscriptionMap.remove(location.id)
} else {
state.locationSubscriptionMap[location.id].remove(subscriptionEndpt)
}
state.verificationKeyMap.remove(subscriptionEndpt)
log.info "Removed subscription URL: ${subscriptionEndpt} for Location ${location.name}"
}
}else{
} else {
httpError(400, "missing input parameter: subscriptionURL")
}
} catch (e) {
@@ -264,28 +299,40 @@ def unregisterDeviceGraph() {
}
log.info "Current location subscription map is ${state.locationSubscriptionMap}"
log.info "Current verification key map is ${state.verificationKeyMap}"
}
//When events are triggered, send HTTP post to web socket servers
def deviceEventHandler(evt) {
def evt_device = evt.device
def evt_deviceType = getDeviceType(evt_device)
def deviceInfo
def evtDevice = evt.device
def evtDeviceType = getDeviceType(evtDevice)
def deviceData = [];
def params = [ body: [deviceName: evt_device.displayName, deviceId: evt_device.id, locationId: location.id] ]
if(evt.data != null){
if (evt.data != null) {
def evtData = parseJson(evt.data)
log.info "Received event for ${evt_device.displayName}, data: ${evtData}, description: ${evt.descriptionText}"
log.info "Received event for ${evtDevice.displayName}, data: ${evtData}, description: ${evt.descriptionText}"
}
if (evtDeviceType == "thermostat") {
deviceData = [name: evtDevice.displayName, id: evtDevice.id, status: evtDevice.status, deviceType: evtDeviceType, manufacturer: evtDevice.manufacturerName, model: evtDevice.modelName, attributes: deviceAttributeList(evtDevice, evtDeviceType), locationMode: getLocationModeInfo(), locationId: location.id]
} else {
deviceData = [name: evtDevice.displayName, id: evtDevice.id, status: evtDevice.status, deviceType: evtDeviceType, manufacturer: evtDevice.manufacturerName, model: evtDevice.modelName, attributes: deviceAttributeList(evtDevice, evtDeviceType), locationId: location.id]
}
def params = [body: deviceData]
//send event to all subscriptions urls
log.debug "Current subscription urls for ${evt_device.displayName} is ${state.deviceSubscriptionMap[evt_device.id]}"
state.deviceSubscriptionMap[evt_device.id].each {
log.debug "Current subscription urls for ${evtDevice.displayName} is ${state.deviceSubscriptionMap[evtDevice.id]}"
state.deviceSubscriptionMap[evtDevice.id].each {
params.uri = "${it}"
if (state.verificationKeyMap[it] != null) {
def key = state.verificationKeyMap[it]
params.header = [Signature: ComputHMACValue(key, groovy.json.JsonOutput.toJson(params.body))]
}
log.trace "POST URI: ${params.uri}"
log.trace "Header: ${params.header}"
log.trace "Payload: ${params.body}"
try{
try {
httpPostJson(params) { resp ->
log.trace "response status code: ${resp.status}"
log.trace "response data: ${resp.data}"
@@ -298,20 +345,27 @@ def deviceEventHandler(evt) {
def locationEventHandler(evt) {
log.info "Received event for location ${location.name}/${location.id}, Event: ${evt.name}, description: ${evt.descriptionText}, apiServerUrl: ${apiServerUrl("")}"
switch(evt.name){
switch (evt.name) {
case "DeviceCreated":
case "DeviceDeleted":
def evt_device = evt.device
def evt_deviceType = getDeviceType(evt_device)
log.info "DeviceName: ${evt_device.displayName}, DeviceID: ${evt_device.id}, deviceType: ${evt_deviceType}"
def evtDevice = evt.device
def evtDeviceType = getDeviceType(evtDevice)
def params = [body: [eventType: evt.name, deviceId: evtDevice.id, locationId: location.id]]
def params = [ body: [ eventType:evt.name, deviceId: evt_device.id, locationId: location.id ] ]
if (evt.name == "DeviceDeleted" && state.deviceSubscriptionMap[deviceId] != null) {
state.deviceSubscriptionMap.remove(evtDevice.id)
}
state.locationSubscriptionMap[location.id].each {
params.uri = "${it}"
if (state.verificationKeyMap[it] != null) {
def key = state.verificationKeyMap[it]
params.header = [Signature: ComputHMACValue(key, groovy.json.JsonOutput.toJson(params.body))]
}
log.trace "POST URI: ${params.uri}"
log.trace "Header: ${params.header}"
log.trace "Payload: ${params.body}"
try{
try {
httpPostJson(params) { resp ->
log.trace "response status code: ${resp.status}"
log.trace "response data: ${resp.data}"
@@ -326,6 +380,23 @@ def locationEventHandler(evt) {
}
}
private ComputHMACValue(key, data) {
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA1")
Mac mac = Mac.getInstance("HmacSHA1")
mac.init(secretKeySpec)
byte[] digest = mac.doFinal(data.getBytes("UTF-8"))
return byteArrayToString(digest)
} catch (InvalidKeyException e) {
log.error "Invalid key exception while converting to HMac SHA1"
}
}
private def byteArrayToString(byte[] data) {
BigInteger bigInteger = new BigInteger(1, data)
String hash = bigInteger.toString(16)
return hash
}
/*** Device Query/Update Functions ***/
@@ -334,10 +405,10 @@ def getDevices() {
def deviceData = []
inputs?.each {
def deviceType = getDeviceType(it)
if(deviceType == "thermostat") {
deviceData << [name: it.displayName, id: it.id, status:it.status, deviceType:deviceType, manufacturer:it.manufacturerName, model:it.modelName, attributes: deviceAttributeList(it, deviceType), locationMode: getLocationModeInfo()]
if (deviceType == "thermostat") {
deviceData << [name: it.displayName, id: it.id, status: it.status, deviceType: deviceType, manufacturer: it.manufacturerName, model: it.modelName, attributes: deviceAttributeList(it, deviceType), locationMode: getLocationModeInfo()]
} else {
deviceData << [name: it.displayName, id: it.id, status:it.status, deviceType:deviceType, manufacturer:it.manufacturerName, model:it.modelName, attributes: deviceAttributeList(it, deviceType)]
deviceData << [name: it.displayName, id: it.id, status: it.status, deviceType: deviceType, manufacturer: it.manufacturerName, model: it.modelName, attributes: deviceAttributeList(it, deviceType)]
}
}
@@ -350,10 +421,10 @@ def getDevice() {
def it = findDevice(params.id)
def deviceType = getDeviceType(it)
def device
if(deviceType == "thermostat") {
device = [name: it.displayName, id: it.id, status:it.status, deviceType:deviceType, manufacturer:it.manufacturerName, model:it.modelName, attributes: deviceAttributeList(it,deviceType), locationMode: getLocationModeInfo()]
if (deviceType == "thermostat") {
device = [name: it.displayName, id: it.id, status: it.status, deviceType: deviceType, manufacturer: it.manufacturerName, model: it.modelName, attributes: deviceAttributeList(it, deviceType), locationMode: getLocationModeInfo()]
} else {
device = [name: it.displayName, id: it.id, status:it.status, deviceType:deviceType, manufacturer:it.manufacturerName, model:it.modelName, attributes: deviceAttributeList(it, deviceType)]
device = [name: it.displayName, id: it.id, status: it.status, deviceType: deviceType, manufacturer: it.manufacturerName, model: it.modelName, attributes: deviceAttributeList(it, deviceType)]
}
log.debug "getDevice, return: ${device}"
@@ -366,18 +437,18 @@ void updateDevice() {
request.JSON.each {
def command = it.key
def value = it.value
if (command){
if (command) {
def commandList = mapDeviceCommands(command, value)
command = commandList[0]
value = commandList[1]
if (command == "setAwayMode") {
log.info "Setting away mode to ${value}"
if (location.modes?.find {it.name == value}) {
if (location.modes?.find { it.name == value }) {
location.setMode(value)
}
}else if (command == "thermostatSetpoint"){
switch(device.currentThermostatMode){
} else if (command == "thermostatSetpoint") {
switch (device.currentThermostatMode) {
case "cool":
log.info "Update: ${device.displayName}, [${command}, ${value}]"
device.setCoolingSetpoint(value)
@@ -391,7 +462,7 @@ void updateDevice() {
httpError(501, "this mode: ${device.currentThermostatMode} does not allow changing thermostat setpoint.")
break
}
}else if (!device) {
} else if (!device) {
log.error "updateDevice, Device not found"
httpError(404, "Device not found")
} else if (!device.hasCommand(command)) {
@@ -401,11 +472,11 @@ void updateDevice() {
if (command == "setColor") {
log.info "Update: ${device.displayName}, [${command}, ${value}]"
device."$command"(hex: value)
} else if(value.isNumber()) {
} else if (value.isNumber()) {
def intValue = value as Integer
log.info "Update: ${device.displayName}, [${command}, ${intValue}(int)]"
device."$command"(intValue)
} else if (value){
} else if (value) {
log.info "Update: ${device.displayName}, [${command}, ${value}]"
device."$command"(value)
} else {
@@ -432,17 +503,16 @@ private getDeviceType(device) {
log.debug "supported commands: [${device}, ${device.supportedCommands}]"
//Loop through the device capability list to determine the device type.
capabilities.each {capability ->
switch(capability.name.toLowerCase())
{
capabilities.each { capability ->
switch (capability.name.toLowerCase()) {
case "switch":
deviceType = "switch"
//If the device also contains "Switch Level" capability, identify it as a "light" device.
if (capabilities.any{it.name.toLowerCase() == "switch level"}){
if (capabilities.any { it.name.toLowerCase() == "switch level" }) {
//If the device also contains "Power Meter" capability, identify it as a "dimmerSwitch" device.
if (capabilities.any{it.name.toLowerCase() == "power meter"}){
if (capabilities.any { it.name.toLowerCase() == "power meter" }) {
deviceType = "dimmerSwitch"
return deviceType
} else {
@@ -489,24 +559,24 @@ private deviceAttributeList(device, deviceType) {
allAttributes.each { attribute ->
try {
def currentState = device.currentState(attribute.name)
if(currentState != null ){
switch(attribute.name){
if (currentState != null) {
switch (attribute.name) {
case 'temperature':
attributeList.putAll([ (attribute.name): currentState.value, 'temperatureScale':location.temperatureScale ])
attributeList.putAll([(attribute.name): currentState.value, 'temperatureScale': location.temperatureScale])
break;
default:
attributeList.putAll([(attribute.name): currentState.value ])
attributeList.putAll([(attribute.name): currentState.value])
break;
}
if( deviceType == "genericSensor" ){
if (deviceType == "genericSensor") {
def key = attribute.name + "_lastUpdated"
attributeList.putAll([ (key): currentState.isoDate ])
attributeList.putAll([(key): currentState.isoDate])
}
} else {
attributeList.putAll([ (attribute.name): null ]);
attributeList.putAll([(attribute.name): null]);
}
} catch(e) {
attributeList.putAll([ (attribute.name): null ]);
} catch (e) {
attributeList.putAll([(attribute.name): null]);
}
}
return attributeList
@@ -579,8 +649,7 @@ private mapDeviceCommands(command, value) {
if (value == 1 || value == "1" || value == "lock") {
resultCommand = "lock"
resultValue = ""
}
else if (value == 0 || value == "0" || value == "unlock") {
} else if (value == 0 || value == "0" || value == "unlock") {
resultCommand = "unlock"
resultValue = ""
}
@@ -589,5 +658,5 @@ private mapDeviceCommands(command, value) {
break
}
return [resultCommand,resultValue]
return [resultCommand, resultValue]
}

View File

@@ -27,84 +27,82 @@ definition(
preferences {
section("Monitor this door or window") {
input "contact", "capability.contactSensor"
}
section("And notify me if it's open for more than this many minutes (default 10)") {
input "openThreshold", "number", description: "Number of minutes", required: false
}
section("Delay between notifications (default 10 minutes") {
input "frequency", "number", title: "Number of minutes", description: "", required: false
section("Monitor this door or window") {
input "contact", "capability.contactSensor"
}
section("And notify me if it's open for more than this many minutes (default 10)") {
input "openThreshold", "number", description: "Number of minutes", required: false
}
section("Delay between notifications (default 10 minutes") {
input "frequency", "number", title: "Number of minutes", description: "", required: false
}
section("Via text message at this number (or via push notification if not specified") {
input("recipients", "contact", title: "Send notifications to") {
input "phone", "phone", title: "Phone number (optional)", required: false
}
section("Via text message at this number (or via push notification if not specified") {
input("recipients", "contact", title: "Send notifications to") {
input "phone", "phone", title: "Phone number (optional)", required: false
}
}
}
}
def installed() {
log.trace "installed()"
subscribe()
log.trace "installed()"
subscribe()
}
def updated() {
log.trace "updated()"
unsubscribe()
subscribe()
log.trace "updated()"
unsubscribe()
subscribe()
}
def subscribe() {
subscribe(contact, "contact.open", doorOpen)
subscribe(contact, "contact.closed", doorClosed)
subscribe(contact, "contact.open", doorOpen)
subscribe(contact, "contact.closed", doorClosed)
}
def doorOpen(evt)
{
log.trace "doorOpen($evt.name: $evt.value)"
def t0 = now()
def delay = (openThreshold != null && openThreshold != "") ? openThreshold * 60 : 600
runIn(delay, doorOpenTooLong, [overwrite: false])
log.debug "scheduled doorOpenTooLong in ${now() - t0} msec"
def doorOpen(evt) {
log.trace "doorOpen($evt.name: $evt.value)"
def delay = (openThreshold != null && openThreshold != "") ? openThreshold * 60 : 600
runIn(delay, doorOpenTooLong, [overwrite: true])
}
def doorClosed(evt)
{
log.trace "doorClosed($evt.name: $evt.value)"
def doorClosed(evt) {
log.trace "doorClosed($evt.name: $evt.value)"
unschedule(doorOpenTooLong)
}
def doorOpenTooLong() {
def contactState = contact.currentState("contact")
def freq = (frequency != null && frequency != "") ? frequency * 60 : 600
def contactState = contact.currentState("contact")
def freq = (frequency != null && frequency != "") ? frequency * 60 : 600
if (contactState.value == "open") {
def elapsed = now() - contactState.rawDateCreated.time
def threshold = ((openThreshold != null && openThreshold != "") ? openThreshold * 60000 : 60000) - 1000
if (elapsed >= threshold) {
log.debug "Contact has stayed open long enough since last check ($elapsed ms): calling sendMessage()"
sendMessage()
runIn(freq, doorOpenTooLong, [overwrite: false])
} else {
log.debug "Contact has not stayed open long enough since last check ($elapsed ms): doing nothing"
}
} else {
log.warn "doorOpenTooLong() called but contact is closed: doing nothing"
}
if (contactState.value == "open") {
def elapsed = now() - contactState.rawDateCreated.time
def threshold = ((openThreshold != null && openThreshold != "") ? openThreshold * 60000 : 60000) - 1000
if (elapsed >= threshold) {
log.debug "Contact has stayed open long enough since last check ($elapsed ms): calling sendMessage()"
sendMessage()
runIn(freq, doorOpenTooLong, [overwrite: false])
} else {
log.debug "Contact has not stayed open long enough since last check ($elapsed ms): doing nothing"
}
} else {
log.warn "doorOpenTooLong() called but contact is closed: doing nothing"
}
}
void sendMessage()
{
def minutes = (openThreshold != null && openThreshold != "") ? openThreshold : 10
def msg = "${contact.displayName} has been left open for ${minutes} minutes."
log.info msg
if (location.contactBookEnabled) {
sendNotificationToContacts(msg, recipients)
}
else {
if (phone) {
sendSms phone, msg
} else {
sendPush msg
}
void sendMessage() {
def minutes = (openThreshold != null && openThreshold != "") ? openThreshold : 10
def msg = "${contact.displayName} has been left open for ${minutes} minutes."
log.info msg
if (location.contactBookEnabled) {
sendNotificationToContacts(msg, recipients)
} else {
if (phone) {
sendSms phone, msg
} else {
sendPush msg
}
}
}

View File

@@ -98,7 +98,7 @@ def motionHandler(evt) {
else {
state.motionStopTime = now()
if(delayMinutes) {
runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: false])
runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: true])
} else {
turnOffMotionAfterDelay()
}

View File

@@ -125,19 +125,19 @@
if(allOk) {
if(everyoneIsAway() && (state.sunMode == "sunrise")) {
log.info("Home is Empty Setting New Away Mode")
log.debug("Home is Empty Setting New Away Mode")
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
runIn(delay, "setAway")
}
if(everyoneIsAway() && (state.sunMode == "sunset")) {
log.info("Home is Empty Setting New Away Mode")
log.debug("Home is Empty Setting New Away Mode")
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
runIn(delay, "setAway")
}
else {
log.info("Home is Occupied Setting New Home Mode")
log.debug("Home is Occupied Setting New Home Mode")
setHome()
@@ -152,7 +152,7 @@
log.debug("Checking if everyone is away")
if(everyoneIsAway()) {
log.info("Nobody is home, running away sequence")
log.debug("Nobody is home, running away sequence")
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
runIn(delay, "setAway")
}
@@ -161,7 +161,7 @@
else {
def lastTime = state[evt.deviceId]
if (lastTime == null || now() - lastTime >= 1 * 60000) {
log.info("Someone is home, running home sequence")
log.debug("Someone is home, running home sequence")
setHome()
}
state[evt.deviceId] = now()
@@ -175,14 +175,14 @@
if(everyoneIsAway()) {
if(state.sunMode == "sunset") {
def message = "Performing \"${awayNight}\" for you as requested."
log.info(message)
log.debug(message)
sendAway(message)
location.helloHome.execute(settings.awayNight)
}
else if(state.sunMode == "sunrise") {
def message = "Performing \"${awayDay}\" for you as requested."
log.info(message)
log.debug(message)
sendAway(message)
location.helloHome.execute(settings.awayDay)
}
@@ -192,19 +192,19 @@
}
else {
log.info("Somebody returned home before we set to '${newAwayMode}'")
log.debug("Somebody returned home before we set to '${newAwayMode}'")
}
}
//set home mode when house is occupied
def setHome() {
sendOutOfDateNotification()
log.info("Setting Home Mode!!")
log.debug("Setting Home Mode!!")
if(anyoneIsHome()) {
if(state.sunMode == "sunset"){
if (location.mode != "${homeModeNight}"){
def message = "Performing \"${homeNight}\" for you as requested."
log.info(message)
log.debug(message)
sendHome(message)
location.helloHome.execute(settings.homeNight)
}
@@ -213,7 +213,7 @@
if(state.sunMode == "sunrise"){
if (location.mode != "${homeModeDay}"){
def message = "Performing \"${homeDay}\" for you as requested."
log.info(message)
log.debug(message)
sendHome(message)
location.helloHome.execute(settings.homeDay)
}
@@ -329,4 +329,4 @@
sendNotification("Your version of Hello, Home Phrase Director is currently out of date. Please look for the new version of Hello, Home Phrase Director now called 'Routine Director' in the marketplace.")
state.lastTime = (new Date() + 31).getTime()
}
}
}