mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-28 21:04:16 +00:00
Compare commits
85 Commits
MSA-1956-3
...
PROD_2017.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4c2a3ffd7 | ||
|
|
3c83bfb53b | ||
|
|
b65acdb91f | ||
|
|
4067e6e7e2 | ||
|
|
4c6d1eddb2 | ||
|
|
10d2097ebe | ||
|
|
d3728d95b2 | ||
|
|
b645872d8f | ||
|
|
d3731b49fe | ||
|
|
da139056e1 | ||
|
|
d864c5e3b3 | ||
|
|
74a35eeddb | ||
|
|
7064ce972a | ||
|
|
936ee59242 | ||
|
|
79a6a6472e | ||
|
|
919111ed22 | ||
|
|
fc1f1508ad | ||
|
|
7f3cd0cdaa | ||
|
|
423c25df53 | ||
|
|
df8e435fcc | ||
|
|
144314d9ae | ||
|
|
8eed22ca0c | ||
|
|
d626c5f2a1 | ||
|
|
1dae5d3936 | ||
|
|
807ff53c6d | ||
|
|
f95319ce59 | ||
|
|
453dbbdde3 | ||
|
|
52427802a8 | ||
|
|
72bb22a4b8 | ||
|
|
e817f5c415 | ||
|
|
10964873cd | ||
|
|
20f086fe69 | ||
|
|
21f7a00cc9 | ||
|
|
06faa988c8 | ||
|
|
fe5f5c35b2 | ||
|
|
2c4cd8d922 | ||
|
|
772cd7005a | ||
|
|
afb4755447 | ||
|
|
49f35e48da | ||
|
|
93d8e96efc | ||
|
|
6fbaf15f42 | ||
|
|
97c9ec7a95 | ||
|
|
d7b448b699 | ||
|
|
9285536f73 | ||
|
|
e7713caec9 | ||
|
|
5b2a46300d | ||
|
|
c8b4b7be1c | ||
|
|
20f1493788 | ||
|
|
f0de2f1a19 | ||
|
|
1263a6e2e1 | ||
|
|
d41162afe4 | ||
|
|
19d9406b6a | ||
|
|
a6d52ab9ac | ||
|
|
01c2968f91 | ||
|
|
483a25e900 | ||
|
|
0d9a08e922 | ||
|
|
40b75ce665 | ||
|
|
a4d9cd51a3 | ||
|
|
9b01a7d8be | ||
|
|
12bb6c0492 | ||
|
|
9e3a6e830f | ||
|
|
92e1586fa6 | ||
|
|
7cf8bb1917 | ||
|
|
d4fd778a64 | ||
|
|
eb870e5f31 | ||
|
|
d60657e466 | ||
|
|
d8dc70ae9e | ||
|
|
a99e050c6b | ||
|
|
5bf7caca0d | ||
|
|
3457bbad42 | ||
|
|
c6c4b09fbb | ||
|
|
3eddd68532 | ||
|
|
8d79379bba | ||
|
|
7e25d32c70 | ||
|
|
dd4da29bcd | ||
|
|
abc5683ed3 | ||
|
|
a3e9f1d2c1 | ||
|
|
8bfc3f0c1c | ||
|
|
b6136bf1d5 | ||
|
|
68f5cda945 | ||
|
|
da42ee63fb | ||
|
|
1d629cfc9a | ||
|
|
5b7a7097b8 | ||
|
|
52c57f66fb | ||
|
|
91c358c3a6 |
@@ -38,9 +38,9 @@ metadata {
|
|||||||
tiles (scale: 2){
|
tiles (scale: 2){
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL", icon: "st.Lighting.light18") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL", icon: "st.Lighting.light18") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#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 "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"
|
attributeState "turningOff", label:'${name}', icon:"st.switches.light.off", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
||||||
@@ -52,20 +52,20 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("motion", "device.motion", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
|
standardTile("motion", "device.motion", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
|
||||||
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC"
|
||||||
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
state "temperature", label:'${currentValue}°', unit:"F", icon:"", // would be better if the units would switch to the desired units of the system (imperial or metric)
|
state "temperature", label:'${currentValue}°', unit:"F", icon:"", // would be better if the units would switch to the desired units of the system (imperial or metric)
|
||||||
backgroundColors:[
|
backgroundColors:[
|
||||||
[value: 0, color: "#1010ff"], // blue=cold
|
[value: 0, color: "#153591"], // blue=cold
|
||||||
[value: 65, color: "#a0a0f0"],
|
[value: 65, color: "#44b621"], // green
|
||||||
[value: 70, color: "#e0e050"],
|
[value: 70, color: "#44b621"], // green
|
||||||
[value: 75, color: "#f0d030"], // yellow
|
[value: 75, color: "#f1d801"], // yellow
|
||||||
[value: 80, color: "#fbf020"],
|
[value: 80, color: "#f1d801"], // yellow
|
||||||
[value: 85, color: "#fbdc01"],
|
[value: 85, color: "#f1d801"], // yellow
|
||||||
[value: 90, color: "#fb3a01"],
|
[value: 90, color: "#d04e00"], // red
|
||||||
[value: 95, color: "#fb0801"] // red=hot
|
[value: 95, color: "#bc2323"] // red=hot
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,268 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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", deviceJoinName: "Show Home 2-Channel Smart Plug"
|
||||||
|
fingerprint manufacturer: "0312", prod: "B221", model: "251C", deviceJoinName: "Inovelli 2-Channel Smart Plug"
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -39,8 +39,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
||||||
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
|
attributeState("active", label:'tamper active', backgroundColor:"#00A0DC")
|
||||||
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
|
attributeState("inactive", label:'tamper inactive', backgroundColor:"#CCCCCC")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
||||||
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
|
attributeState("active", label:'tamper active', backgroundColor:"#00A0DC")
|
||||||
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
|
attributeState("inactive", label:'tamper inactive', backgroundColor:"#CCCCCC")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
|
multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
|
||||||
tileAttribute("device.motion", key:"PRIMARY_CONTROL") {
|
tileAttribute("device.motion", key:"PRIMARY_CONTROL") {
|
||||||
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
|
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#cccccc")
|
||||||
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
|
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
|
||||||
}
|
}
|
||||||
|
|
||||||
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
||||||
|
|||||||
@@ -95,10 +95,10 @@ metadata {
|
|||||||
multiAttributeTile(name:"doorCtrl", type:"generic", width:6, height:4) {tileAttribute("device.doorState", key: "PRIMARY_CONTROL")
|
multiAttributeTile(name:"doorCtrl", type:"generic", width:6, height:4) {tileAttribute("device.doorState", key: "PRIMARY_CONTROL")
|
||||||
{
|
{
|
||||||
attributeState "unknown", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", nextState:"Sent"
|
attributeState "unknown", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", nextState:"Sent"
|
||||||
attributeState "open", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#0000ff" , 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: "#ffa81e"
|
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#00A0DC"
|
||||||
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#79b821", nextState:"Sent"
|
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: "#ffa81e"
|
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 "jammed", label: '${name}', action:"closeDoorHiI", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
|
||||||
attributeState "forced close", label: 'forced\rclose', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff8000", nextState:"Sent"
|
attributeState "forced close", label: 'forced\rclose', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff8000", nextState:"Sent"
|
||||||
attributeState "fault", label: 'FAULT', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
|
attributeState "fault", label: 'FAULT', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
|
||||||
@@ -135,13 +135,13 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("autoClose", "device.autoCloseEnable", width: 2, height: 2){
|
standardTile("autoClose", "device.autoCloseEnable", width: 2, height: 2){
|
||||||
state "on", label: 'Auto', action:"autoCloseOff", icon: "st.doors.garage.garage-closing", backgroundColor: "#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 "off", label: 'Auto', action:"autoCloseOn", icon: "st.doors.garage.garage-closing", nextState:"Sent"
|
||||||
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("autoOpen", "device.autoOpenEnable", width: 2, height: 2){
|
standardTile("autoOpen", "device.autoOpenEnable", width: 2, height: 2){
|
||||||
state "on", label: 'Auto', action:"autoOpenOff", icon: "st.doors.garage.garage-opening", backgroundColor: "#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 "off", label: 'Auto', action:"autoOpenOn", icon: "st.doors.garage.garage-opening", nextState:"Sent"
|
||||||
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
||||||
}
|
}
|
||||||
@@ -189,13 +189,13 @@ metadata {
|
|||||||
|
|
||||||
standardTile("aux1", "device.Aux1", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("aux1", "device.Aux1", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "off", label:'Aux 1', action:"Aux1On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent"
|
state "off", label:'Aux 1', action:"Aux1On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent"
|
||||||
state "on", label:'Aux 1', action:"Aux1Off", icon:"st.switches.switch.on", backgroundColor:"#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"
|
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("aux2", "device.Aux2", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("aux2", "device.Aux2", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "off", label:'Aux 2', action:"Aux2On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent"
|
state "off", label:'Aux 2', action:"Aux2On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent"
|
||||||
state "on", label:'Aux 2', action:"Aux2Off", icon:"st.switches.switch.on", backgroundColor:"#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"
|
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ metadata {
|
|||||||
capability "Battery"
|
capability "Battery"
|
||||||
|
|
||||||
fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x80,0x84,0x85"
|
fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x80,0x84,0x85"
|
||||||
|
fingerprint mfr: "0086", prod: "0001", model: "0026", deviceJoinName: "Aeon Panic Button"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -130,5 +131,12 @@ def updated() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def initialize() {
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
43
devicetypes/smartthings/aeon-multisensor-6.src/README.md
Normal file
43
devicetypes/smartthings/aeon-multisensor-6.src/README.md
Normal 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)
|
||||||
@@ -22,6 +22,7 @@ metadata {
|
|||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
attribute "tamper", "enum", ["detected", "clear"]
|
attribute "tamper", "enum", ["detected", "clear"]
|
||||||
attribute "batteryStatus", "string"
|
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", outClusters: "0x5A"
|
||||||
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,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 {
|
simulator {
|
||||||
@@ -103,7 +105,7 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
|
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) {
|
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() {
|
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 "Updated with settings: ${settings}"
|
||||||
log.debug "${device.displayName} is now ${device.latestValue("powerSupply")}"
|
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)
|
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() {
|
def configure() {
|
||||||
// This sensor joins as a secure device if you double-click the button to include it
|
// This sensor joins as a secure device if you double-click the button to include it
|
||||||
log.debug "${device.displayName} is configuring its settings"
|
log.debug "${device.displayName} is configuring its settings"
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ metadata {
|
|||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Health Check"
|
capability "Health Check"
|
||||||
|
|
||||||
command "configureAfterSecure"
|
|
||||||
|
|
||||||
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A"
|
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A"
|
||||||
fingerprint mfr:"0086", prod:"0102", model:"004A", deviceJoinName: "Aeon Labs MultiSensor (Gen 5)"
|
fingerprint mfr:"0086", prod:"0102", model:"004A", deviceJoinName: "Aeon Labs MultiSensor (Gen 5)"
|
||||||
}
|
}
|
||||||
@@ -86,17 +84,17 @@ metadata {
|
|||||||
state "humidity", label:'${currentValue}% humidity', unit:""
|
state "humidity", label:'${currentValue}% humidity', unit:""
|
||||||
}
|
}
|
||||||
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
|
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) {
|
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
}
|
}
|
||||||
standardTile("configureAfterSecure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "configure", label:'', action:"configureAfterSecure", icon:"st.secondary.configure"
|
state "configure", label:'', action:"configure", icon:"st.secondary.configure"
|
||||||
}
|
}
|
||||||
|
|
||||||
main(["motion", "temperature", "humidity", "illuminance"])
|
main(["motion", "temperature", "humidity", "illuminance"])
|
||||||
details(["motion", "temperature", "humidity", "illuminance", "battery", "configureAfterSecure"])
|
details(["motion", "temperature", "humidity", "illuminance", "battery", "configure"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,8 +129,8 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
|
|||||||
|
|
||||||
if (!isConfigured()) {
|
if (!isConfigured()) {
|
||||||
// we're still in the process of configuring a newly joined device
|
// we're still in the process of configuring a newly joined device
|
||||||
log.debug("not sending wakeUpNoMoreInformation yet")
|
log.debug("not sending wakeUpNoMoreInformation yet: late configure")
|
||||||
result += response(configureAfterSecure())
|
result += response(configure())
|
||||||
} else {
|
} else {
|
||||||
result += response(zwave.wakeUpV1.wakeUpNoMoreInformation())
|
result += response(zwave.wakeUpV1.wakeUpNoMoreInformation())
|
||||||
}
|
}
|
||||||
@@ -150,11 +148,6 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
|
|
||||||
// log.debug "Received SecurityCommandsSupportedReport"
|
|
||||||
response(configureAfterSecure())
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
||||||
def map = [ name: "battery", unit: "%" ]
|
def map = [ name: "battery", unit: "%" ]
|
||||||
if (cmd.batteryLevel == 0xFF) {
|
if (cmd.batteryLevel == 0xFF) {
|
||||||
@@ -226,36 +219,6 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
|||||||
createEvent(descriptionText: cmd.toString(), isStateChange: false)
|
createEvent(descriptionText: cmd.toString(), isStateChange: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
def configureAfterSecure() {
|
|
||||||
// log.debug "configureAfterSecure()"
|
|
||||||
|
|
||||||
def request = [
|
|
||||||
// send temperature, humidity, and illuminance every 8 minutes
|
|
||||||
zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 128|64|32),
|
|
||||||
zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 8*60),
|
|
||||||
|
|
||||||
// send battery every 20 hours
|
|
||||||
zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1),
|
|
||||||
zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 20*60*60),
|
|
||||||
|
|
||||||
// send no-motion report 60 seconds after motion stops
|
|
||||||
zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 60),
|
|
||||||
|
|
||||||
// send binary sensor report instead of basic set for motion
|
|
||||||
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: 2),
|
|
||||||
|
|
||||||
// disable notification-style motion events
|
|
||||||
zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0),
|
|
||||||
|
|
||||||
zwave.batteryV1.batteryGet(),
|
|
||||||
zwave.sensorBinaryV2.sensorBinaryGet(sensorType:0x0C)
|
|
||||||
]
|
|
||||||
|
|
||||||
setConfigured()
|
|
||||||
|
|
||||||
secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PING is used by Device-Watch in attempt to reach the Device
|
* PING is used by Device-Watch in attempt to reach the Device
|
||||||
* */
|
* */
|
||||||
@@ -265,7 +228,36 @@ def ping() {
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
// log.debug "configure()"
|
// log.debug "configure()"
|
||||||
//["delay 30000"] + secure(zwave.securityV1.securityCommandsSupportedGet())
|
def request = []
|
||||||
|
// send temperature, humidity, and illuminance every 8 minutes
|
||||||
|
request << zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 128|64|32)
|
||||||
|
request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 8*60)
|
||||||
|
|
||||||
|
// send battery every 20 hours
|
||||||
|
request << zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1)
|
||||||
|
request << zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 20*60*60)
|
||||||
|
|
||||||
|
// send no-motion report 60 seconds after motion stops
|
||||||
|
request << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 60)
|
||||||
|
|
||||||
|
// send binary sensor report instead of basic set for motion
|
||||||
|
request << zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: 2)
|
||||||
|
|
||||||
|
// Turn on the Multisensor Gen5 PIR sensor
|
||||||
|
request << zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, scaledConfigurationValue: 1)
|
||||||
|
|
||||||
|
// disable notification-style motion events
|
||||||
|
request << zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0)
|
||||||
|
|
||||||
|
request << zwave.batteryV1.batteryGet()
|
||||||
|
request << zwave.sensorBinaryV2.sensorBinaryGet(sensorType: 0x0C) //motion
|
||||||
|
request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) //temperature
|
||||||
|
request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03) //illuminance
|
||||||
|
request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x05) //humidity
|
||||||
|
|
||||||
|
setConfigured()
|
||||||
|
|
||||||
|
secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
|
||||||
}
|
}
|
||||||
|
|
||||||
private setConfigured() {
|
private setConfigured() {
|
||||||
@@ -283,4 +275,3 @@ private secure(physicalgraph.zwave.Command cmd) {
|
|||||||
private secureSequence(commands, delay=200) {
|
private secureSequence(commands, delay=200) {
|
||||||
delayBetween(commands.collect{ secure(it) }, delay)
|
delayBetween(commands.collect{ secure(it) }, delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
devicetypes/smartthings/aeon-multisensor.src/.st-ignore
Normal file
2
devicetypes/smartthings/aeon-multisensor.src/.st-ignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
48
devicetypes/smartthings/aeon-multisensor.src/README.md
Normal file
48
devicetypes/smartthings/aeon-multisensor.src/README.md
Normal 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)
|
||||||
@@ -20,6 +20,7 @@ metadata {
|
|||||||
capability "Illuminance Measurement"
|
capability "Illuminance Measurement"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
fingerprint deviceId: "0x2001", inClusters: "0x30,0x31,0x80,0x84,0x70,0x85,0x72,0x86"
|
fingerprint deviceId: "0x2001", inClusters: "0x30,0x31,0x80,0x84,0x70,0x85,0x72,0x86"
|
||||||
}
|
}
|
||||||
@@ -79,7 +80,7 @@ metadata {
|
|||||||
state "humidity", label:'${currentValue}% humidity', unit:""
|
state "humidity", label:'${currentValue}% humidity', unit:""
|
||||||
}
|
}
|
||||||
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
|
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) {
|
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
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
|
// Parse incoming device messages to generate events
|
||||||
def parse(String description)
|
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() {
|
def configure() {
|
||||||
delayBetween([
|
delayBetween([
|
||||||
// send binary sensor report instead of basic set for motion
|
// send binary sensor report instead of basic set for motion
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
* Date: 2014-07-15
|
* Date: 2014-07-15
|
||||||
*/
|
*/
|
||||||
metadata {
|
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 "Actuator"
|
||||||
capability "Alarm"
|
capability "Alarm"
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
@@ -61,6 +61,8 @@ metadata {
|
|||||||
def installed() {
|
def installed() {
|
||||||
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
// 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])
|
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() {
|
def updated() {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ metadata {
|
|||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
attribute "thermostatFanState", "string"
|
attribute "thermostatFanState", "string"
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ metadata {
|
|||||||
command "quickSetHeat"
|
command "quickSetHeat"
|
||||||
|
|
||||||
fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60"
|
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
|
// 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 parse(String description)
|
||||||
{
|
{
|
||||||
def result = []
|
def result = []
|
||||||
@@ -439,6 +451,14 @@ def setCoolingSetpoint(Double degrees, Integer delay = 30000) {
|
|||||||
], delay)
|
], delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PING is used by Device-Watch in attempt to reach the Device
|
||||||
|
* */
|
||||||
|
def ping() {
|
||||||
|
log.debug "ping() called"
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
delayBetween([
|
delayBetween([
|
||||||
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
|
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
|
||||||
|
|||||||
@@ -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()
|
||||||
|
])
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
])
|
||||||
|
}
|
||||||
@@ -68,8 +68,8 @@
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("contact", "device.contact", width: 2, height: 2) {
|
standardTile("contact", "device.contact", width: 2, height: 2) {
|
||||||
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
|
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
|
||||||
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
|
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
||||||
state "temperature", label:'${currentValue}°',
|
state "temperature", label:'${currentValue}°',
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
}
|
}
|
||||||
standardTile("tamper", "device.alarm") {
|
standardTile("tamper", "device.alarm") {
|
||||||
state("secure", label:'secure', icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
|
state("secure", label:'secure', icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
|
||||||
state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
|
state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#00a0dc")
|
||||||
}
|
}
|
||||||
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
|
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
|
|||||||
@@ -107,8 +107,8 @@
|
|||||||
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
|
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
|
||||||
}
|
}
|
||||||
standardTile("acceleration", "device.acceleration") {
|
standardTile("acceleration", "device.acceleration") {
|
||||||
state("active", label:'vibration', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
|
state("active", label:'vibration', icon:"st.motion.acceleration.active", backgroundColor:"#00a0dc")
|
||||||
state("inactive", label:'still', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
|
state("inactive", label:'still', icon:"st.motion.acceleration.inactive", backgroundColor:"#cccccc")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
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 "Actuator"
|
||||||
capability "Health Check"
|
capability "Health Check"
|
||||||
capability "Valve"
|
capability "Valve"
|
||||||
@@ -34,19 +34,22 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// tile definitions
|
// tile definitions
|
||||||
tiles {
|
tiles(scale: 2) {
|
||||||
standardTile("contact", "device.contact", width: 2, height: 2, canChangeIcon: true) {
|
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
|
||||||
state "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
|
tileAttribute ("device.valve", key: "PRIMARY_CONTROL") {
|
||||||
state "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
|
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
|
||||||
state "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
|
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
|
||||||
state "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
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"
|
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
main "contact"
|
main "valve"
|
||||||
details(["contact","refresh"])
|
details(["valve","refresh"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,22 +65,23 @@ def updated(){
|
|||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.trace description
|
log.trace description
|
||||||
def result = null
|
|
||||||
def cmd = zwave.parse(description)
|
def cmd = zwave.parse(description)
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
result = createEvent(zwaveEvent(cmd))
|
return zwaveEvent(cmd)
|
||||||
}
|
}
|
||||||
log.debug "Parse returned ${result?.descriptionText}"
|
log.debug "Could not parse message"
|
||||||
return result
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
|
||||||
def value = cmd.value ? "closed" : "open"
|
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) {
|
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() {
|
def open() {
|
||||||
@@ -98,3 +102,9 @@ def ping() {
|
|||||||
def refresh() {
|
def refresh() {
|
||||||
zwave.switchBinaryV1.switchBinaryGet().format()
|
zwave.switchBinaryV1.switchBinaryGet().format()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def createEventWithDebug(eventMap) {
|
||||||
|
def event = createEvent(eventMap)
|
||||||
|
log.debug "Event created with ${event?.descriptionText}"
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ metadata {
|
|||||||
state "off", label: '${name}', action: "on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
state "off", label: '${name}', action: "on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
||||||
}
|
}
|
||||||
standardTile("contact", "device.contact", inactiveLabel: false) {
|
standardTile("contact", "device.contact", inactiveLabel: false) {
|
||||||
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
|
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
|
||||||
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
|
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Cloud Execution
|
|||||||
|
|
||||||
Works with:
|
Works with:
|
||||||
|
|
||||||
* [FortrezZ Siren Strobe Alarm](https://www.smartthings.com/works-with-smartthings/other/fortrezz-water-valve)
|
* [FortrezZ Siren Strobe Alarm](https://www.smartthings.com/products/fortrezz-siren-strobe-alarm)
|
||||||
|
|
||||||
## Table of contents
|
## Table of contents
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
* Date: 2013-03-05
|
* Date: 2013-03-05
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "SmartAlert Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.smokedetector") {
|
definition (name: "SmartAlert Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.smoke") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#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 "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"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
|
|||||||
@@ -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", 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: "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,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"
|
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ metadata {
|
|||||||
state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#00A0DC")
|
state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#00A0DC")
|
||||||
}
|
}
|
||||||
standardTile("contact", "device.contact") {
|
standardTile("contact", "device.contact") {
|
||||||
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
||||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
|
||||||
}
|
}
|
||||||
standardTile("acceleration", "device.acceleration", decoration: "flat") {
|
standardTile("acceleration", "device.acceleration", decoration: "flat") {
|
||||||
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC")
|
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC")
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name: "motion", type: "generic", width: 6, height: 4) {
|
multiAttributeTile(name: "motion", type: "generic", width: 6, height: 4) {
|
||||||
tileAttribute("device.motion", key: "PRIMARY_CONTROL") {
|
tileAttribute("device.motion", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#53a7c0"
|
attributeState "active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#00A0DC"
|
||||||
attributeState "inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#ffffff"
|
attributeState "inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#cccccc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ metadata {
|
|||||||
state("closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc")
|
state("closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc")
|
||||||
}
|
}
|
||||||
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
|
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
|
||||||
state("active", label: 'Active', icon: "st.motion.acceleration.active", backgroundColor: "#53a7c0")
|
state("active", label: 'Active', icon: "st.motion.acceleration.active", backgroundColor: "#00a0dc")
|
||||||
state("inactive", label: 'Inactive', icon: "st.motion.acceleration.inactive", backgroundColor: "#ffffff")
|
state("inactive", label: 'Inactive', icon: "st.motion.acceleration.inactive", backgroundColor: "#cccccc")
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
state("temperature", label: '${currentValue}°',
|
state("temperature", label: '${currentValue}°',
|
||||||
@@ -178,7 +178,7 @@ private List<Map> handleAcceleration(descMap) {
|
|||||||
result += parseAxis(descMap.additionalAttrs)
|
result += parseAxis(descMap.additionalAttrs)
|
||||||
}
|
}
|
||||||
} else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012) {
|
} else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012) {
|
||||||
def addAttrs = descMap.additionalAttrs
|
def addAttrs = descMap.additionalAttrs ?: []
|
||||||
addAttrs << ["attrInt": descMap.attrInt, "value": descMap.value]
|
addAttrs << ["attrInt": descMap.attrInt, "value": descMap.value]
|
||||||
result += parseAxis(addAttrs)
|
result += parseAxis(addAttrs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,16 +22,16 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("contact", "device.contact", width: 2, height: 2) {
|
standardTile("contact", "device.contact", width: 2, height: 2) {
|
||||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821", action: "open")
|
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC", action: "open")
|
||||||
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e", action: "close")
|
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13", action: "close")
|
||||||
}
|
}
|
||||||
standardTile("freezerDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
|
standardTile("freezerDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
|
||||||
state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
|
||||||
state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
||||||
}
|
}
|
||||||
standardTile("mainDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
|
standardTile("mainDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
|
||||||
state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
|
||||||
state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
||||||
}
|
}
|
||||||
standardTile("control", "device.contact", width: 1, height: 1, decoration: "flat") {
|
standardTile("control", "device.contact", width: 1, height: 1, decoration: "flat") {
|
||||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", action: "open")
|
state("closed", label:'${name}', icon:"st.contact.contact.closed", action: "open")
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ metadata {
|
|||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
standardTile("contact", "device.contact", width: 4, height: 4) {
|
standardTile("contact", "device.contact", width: 4, height: 4) {
|
||||||
state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#79b821")
|
state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#00A0DC")
|
||||||
state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#ffa81e")
|
state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#e86d13")
|
||||||
}
|
}
|
||||||
childDeviceTile("freezerDoor", "freezerDoor", height: 2, width: 2, childTileName: "freezerDoor")
|
childDeviceTile("freezerDoor", "freezerDoor", height: 2, width: 2, childTileName: "freezerDoor")
|
||||||
childDeviceTile("mainDoor", "mainDoor", height: 2, width: 2, childTileName: "mainDoor")
|
childDeviceTile("mainDoor", "mainDoor", height: 2, width: 2, childTileName: "mainDoor")
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ metadata {
|
|||||||
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#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"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ metadata {
|
|||||||
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
|
attributeState "on", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'${name}', backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "turningOn", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "turningOff", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "turningOff", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute("device.level", key: "SECONDARY_CONTROL") {
|
tileAttribute("device.level", key: "SECONDARY_CONTROL") {
|
||||||
@@ -59,7 +59,7 @@ metadata {
|
|||||||
tileAttribute("device.switch", key: "SECONDARY_CONTROL") {
|
tileAttribute("device.switch", key: "SECONDARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'…', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#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"
|
attributeState "turningOff", label:'…', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute("device.level", key: "VALUE_CONTROL") {
|
tileAttribute("device.level", key: "VALUE_CONTROL") {
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#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 "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 "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") {
|
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
|
||||||
attributeState "currentIP", label: ''
|
attributeState "currentIP", label: ''
|
||||||
|
|||||||
@@ -46,8 +46,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("motion", "device.motion", width: 2, height: 2) {
|
standardTile("motion", "device.motion", width: 2, height: 2) {
|
||||||
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
|
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
|
||||||
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
|
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#CCCCCC")
|
||||||
state("offline", label:'${name}', icon:"st.motion.motion.inactive", backgroundColor:"#ff0000")
|
state("offline", label:'${name}', icon:"st.motion.motion.inactive", backgroundColor:"#ff0000")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,11 +38,11 @@
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#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 "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 "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") {
|
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
|
||||||
attributeState "currentIP", label: ''
|
attributeState "currentIP", label: ''
|
||||||
@@ -50,11 +50,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#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 "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 "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") {
|
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
|
||||||
|
|||||||
@@ -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"
|
||||||
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, 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, 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, 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"
|
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY PAR38 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart PAR38 Soft White"
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#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 "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"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
@@ -103,12 +103,12 @@ def parse(String description) {
|
|||||||
|
|
||||||
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
|
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
|
||||||
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
|
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
|
||||||
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
state.hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
||||||
sendEvent(name: "hue", value: hueValue, descriptionText: "Color has changed")
|
runIn(5, updateColor, [overwrite: true])
|
||||||
}
|
}
|
||||||
else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute
|
else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute
|
||||||
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
state.saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100)
|
||||||
sendEvent(name: "saturation", value: saturationValue, descriptionText: "Color has changed", displayed: false)
|
runIn(5, updateColor, [overwrite: true])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
|
else if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
|
||||||
@@ -127,6 +127,11 @@ def parse(String description) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def updateColor() {
|
||||||
|
sendEvent(name: "hue", value: state.hueValue, descriptionText: "Color has changed")
|
||||||
|
sendEvent(name: "saturation", value: state.saturationValue, descriptionText: "Color has changed", displayed: false)
|
||||||
|
}
|
||||||
|
|
||||||
def on() {
|
def on() {
|
||||||
zigbee.on()
|
zigbee.on()
|
||||||
}
|
}
|
||||||
@@ -205,8 +210,8 @@ def setColor(value){
|
|||||||
zigbee.on() +
|
zigbee.on() +
|
||||||
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND,
|
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND,
|
||||||
getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") +
|
getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") +
|
||||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
|
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) +
|
||||||
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
def setHue(value) {
|
def setHue(value) {
|
||||||
|
|||||||
@@ -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"
|
||||||
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: "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, 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) {
|
tiles(scale: 2) {
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#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 "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"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ metadata {
|
|||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
|
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 "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 "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"
|
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)
|
sendEvent(event)
|
||||||
|
//handle valve attribute
|
||||||
|
event.name = "valve"
|
||||||
|
sendEvent(event)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
def descMap = zigbee.parseDescriptionAsMap(description)
|
def descMap = zigbee.parseDescriptionAsMap(description)
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#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 "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"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#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 "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"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
|
|||||||
@@ -75,6 +75,10 @@ def parse(String description) {
|
|||||||
return result
|
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) {
|
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
|
||||||
[ createEvent(descriptionText: "${device.displayName} woke up", isStateChange:true),
|
[ createEvent(descriptionText: "${device.displayName} woke up", isStateChange:true),
|
||||||
response(["delay 2000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]) ]
|
response(["delay 2000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]) ]
|
||||||
|
|||||||
@@ -30,9 +30,15 @@ metadata {
|
|||||||
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82"
|
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82"
|
||||||
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x80,0x71,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0x59,0x73,0x5A,0x8F,0x98,0x7A", outClusters:"0x20" // Philio multi+
|
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x80,0x71,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0x59,0x73,0x5A,0x8F,0x98,0x7A", outClusters:"0x20" // Philio multi+
|
||||||
fingerprint mfr:"0086", prod:"0002", model:"001D", deviceJoinName: "Aeon Labs Door/Window Sensor (Gen 5)"
|
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:"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:"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
|
// simulator metadata
|
||||||
@@ -107,9 +113,9 @@ def updated() {
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
commands([
|
commands([
|
||||||
zwave.manufacturerSpecificV2.manufacturerSpecificGet(),
|
zwave.sensorBinaryV2.sensorBinaryGet(sensorType: zwave.sensorBinaryV2.SENSOR_TYPE_DOOR_WINDOW),
|
||||||
zwave.batteryV1.batteryGet()
|
zwave.manufacturerSpecificV2.manufacturerSpecificGet()
|
||||||
], 6000)
|
], 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
def sensorValueEvent(value) {
|
def sensorValueEvent(value) {
|
||||||
@@ -184,11 +190,17 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
|
|||||||
cmds << command(zwave.manufacturerSpecificV2.manufacturerSpecificGet())
|
cmds << command(zwave.manufacturerSpecificV2.manufacturerSpecificGet())
|
||||||
cmds << "delay 1200"
|
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) {
|
if (!state.lastbat || now() - state.lastbat > 53*60*60*1000) {
|
||||||
cmds << command(zwave.batteryV1.batteryGet())
|
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()
|
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
|
||||||
}
|
}
|
||||||
|
|
||||||
[event, response(cmds)]
|
[event, response(cmds)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,24 @@ metadata {
|
|||||||
|
|
||||||
fingerprint deviceId: "0x4003", inClusters: "0x98"
|
fingerprint deviceId: "0x4003", inClusters: "0x98"
|
||||||
fingerprint deviceId: "0x4004", inClusters: "0x98"
|
fingerprint deviceId: "0x4004", inClusters: "0x98"
|
||||||
fingerprint mfr:"0129", prod:"0002", model:"0000", deviceJoinName: "Yale Key Free Touchscreen Deadbolt"
|
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 {
|
simulator {
|
||||||
@@ -69,13 +86,13 @@ import physicalgraph.zwave.commands.doorlockv1.*
|
|||||||
import physicalgraph.zwave.commands.usercodev1.*
|
import physicalgraph.zwave.commands.usercodev1.*
|
||||||
|
|
||||||
def installed() {
|
def installed() {
|
||||||
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
// Device-Watch pings if no device events received for 1 hour (checkInterval)
|
||||||
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
sendEvent(name: "checkInterval", value: 1 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
// Device-Watch pings if no device events received for 1 hour (checkInterval)
|
||||||
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
sendEvent(name: "checkInterval", value: 1 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
try {
|
try {
|
||||||
if (!state.init) {
|
if (!state.init) {
|
||||||
state.init = true
|
state.init = true
|
||||||
@@ -135,6 +152,10 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupported
|
|||||||
|
|
||||||
def zwaveEvent(DoorLockOperationReport cmd) {
|
def zwaveEvent(DoorLockOperationReport cmd) {
|
||||||
def result = []
|
def result = []
|
||||||
|
|
||||||
|
unschedule("followupStateCheck")
|
||||||
|
unschedule("stateCheck")
|
||||||
|
|
||||||
def map = [ name: "lock" ]
|
def map = [ name: "lock" ]
|
||||||
if (cmd.doorLockMode == 0xFF) {
|
if (cmd.doorLockMode == 0xFF) {
|
||||||
map.value = "locked"
|
map.value = "locked"
|
||||||
@@ -348,7 +369,7 @@ def zwaveEvent(UserCodeReport cmd) {
|
|||||||
code = state["set$name"] ?: decrypt(state[name]) ?: "****"
|
code = state["set$name"] ?: decrypt(state[name]) ?: "****"
|
||||||
state.remove("set$name".toString())
|
state.remove("set$name".toString())
|
||||||
} else {
|
} 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.descriptionText = "$device.displayName code $cmd.userIdentifier is set"
|
||||||
map.displayed = (cmd.userIdentifier != state.requestCode && cmd.userIdentifier != state.pollCode)
|
map.displayed = (cmd.userIdentifier != state.requestCode && cmd.userIdentifier != state.pollCode)
|
||||||
map.isStateChange = true
|
map.isStateChange = true
|
||||||
@@ -439,11 +460,12 @@ def zwaveEvent(physicalgraph.zwave.commands.timev1.TimeGet cmd) {
|
|||||||
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet 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
|
// 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") ]
|
def result = [ createEvent(name: "lock", value: cmd.value ? "unlocked" : "locked") ]
|
||||||
result << response(zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId))
|
def cmds = [
|
||||||
if (state.assoc != zwaveHubNodeId) {
|
zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format(),
|
||||||
result << response(zwave.associationV1.associationGet(groupingIdentifier:2))
|
"delay 1200",
|
||||||
}
|
zwave.associationV1.associationGet(groupingIdentifier:2).format()
|
||||||
result
|
]
|
||||||
|
[result, response(cmds)]
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
||||||
@@ -513,11 +535,18 @@ def unlockwtimeout() {
|
|||||||
lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT)
|
lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* PING is used by Device-Watch in attempt to reach the Device
|
|
||||||
* */
|
|
||||||
def ping() {
|
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() {
|
def refresh() {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ metadata {
|
|||||||
fingerprint mfr: "0060", prod: "0001", model: "0002", deviceJoinName: "Everspring Motion Sensor" // Everspring SP814
|
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: "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: "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 {
|
simulator {
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("motion", "device.motion", width: 3, height: 2) {
|
standardTile("motion", "device.motion", width: 3, height: 2) {
|
||||||
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC"
|
||||||
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#CCCCCC"
|
||||||
}
|
}
|
||||||
|
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
* Date: 2014-07-15
|
* Date: 2014-07-15
|
||||||
*/
|
*/
|
||||||
metadata {
|
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 "Actuator"
|
||||||
capability "Alarm"
|
capability "Alarm"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ metadata {
|
|||||||
attribute "alarmState", "string"
|
attribute "alarmState", "string"
|
||||||
|
|
||||||
fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86"
|
fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86"
|
||||||
|
fingerprint mfr:"0138", prod:"0001", model:"0001", deviceJoinName: "First Alert Smoke Detector"
|
||||||
fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)"
|
fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
devicetypes/smartthings/zwave-water-valve.src/.st-ignore
Normal file
2
devicetypes/smartthings/zwave-water-valve.src/.st-ignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
38
devicetypes/smartthings/zwave-water-valve.src/README.md
Normal file
38
devicetypes/smartthings/zwave-water-valve.src/README.md
Normal 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)
|
||||||
|
|
||||||
|
|
||||||
@@ -12,14 +12,16 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
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 "Actuator"
|
||||||
|
capability "Health Check"
|
||||||
capability "Valve"
|
capability "Valve"
|
||||||
capability "Polling"
|
capability "Polling"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
fingerprint deviceId: "0x1006", inClusters: "0x25"
|
fingerprint deviceId: "0x1006", inClusters: "0x25"
|
||||||
|
fingerprint mfr:"0173", prod:"0003", model:"0002", deviceJoinName: "Leak Intelligence Leak Gopher Water Shutoff Valve"
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulator metadata
|
// simulator metadata
|
||||||
@@ -35,7 +37,7 @@ metadata {
|
|||||||
// tile definitions
|
// tile definitions
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
|
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 "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 "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 "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"
|
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() {
|
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())
|
response(refresh())
|
||||||
}
|
}
|
||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.trace "parse description : $description"
|
log.trace "parse description : $description"
|
||||||
def result = null
|
|
||||||
def cmd = zwave.parse(description, [0x20: 1])
|
def cmd = zwave.parse(description, [0x20: 1])
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
result = createEvent(zwaveEvent(cmd))
|
return zwaveEvent(cmd)
|
||||||
}
|
}
|
||||||
log.debug "Parse returned ${result?.descriptionText}"
|
log.debug "Could not parse message"
|
||||||
return result
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
|
||||||
def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown"
|
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.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { //TODO should show MSR when device is discovered
|
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}"
|
log.debug "productTypeId: ${cmd.productTypeId}"
|
||||||
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
|
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
|
||||||
updateDataValue("MSR", msr)
|
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) {
|
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 zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
|
||||||
def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown"
|
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) {
|
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() {
|
def open() {
|
||||||
@@ -114,6 +126,13 @@ def poll() {
|
|||||||
zwave.switchBinaryV1.switchBinaryGet().format()
|
zwave.switchBinaryV1.switchBinaryGet().format()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PING is used by Device-Watch in attempt to reach the Device
|
||||||
|
* */
|
||||||
|
def ping() {
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
log.debug "refresh() is called"
|
log.debug "refresh() is called"
|
||||||
def commands = [zwave.switchBinaryV1.switchBinaryGet().format()]
|
def commands = [zwave.switchBinaryV1.switchBinaryGet().format()]
|
||||||
@@ -122,3 +141,9 @@ def refresh() {
|
|||||||
}
|
}
|
||||||
delayBetween(commands,100)
|
delayBetween(commands,100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def createEventWithDebug(eventMap) {
|
||||||
|
def event = createEvent(eventMap)
|
||||||
|
log.debug "Event created with ${event?.descriptionText}"
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,273 +0,0 @@
|
|||||||
/**
|
|
||||||
* Lloyds Banking Group Connect & Protect
|
|
||||||
*
|
|
||||||
* Copyright 2016 Domotz
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
definition(
|
|
||||||
name: "Lloyds Banking Group Connect & Protect",
|
|
||||||
namespace: "domotz.dev",
|
|
||||||
author: "Domotz",
|
|
||||||
description: "The Lloyds Connect & Protect SmartApp is a bridge between SmartThings Cloud and Lloyds Banking Group to enable advanced connected device monitoring and alerting features to be included in the offering to their customers for the connected home service",
|
|
||||||
category: "Convenience",
|
|
||||||
singleInstance: true,
|
|
||||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
|
||||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
|
|
||||||
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
|
|
||||||
oauth: [displayName: "Lloyds Banking Group Connect & Protect", displayLink: ""]) {
|
|
||||||
appSetting "endpointRetrievalUrl"
|
|
||||||
appSetting "xApiKey"
|
|
||||||
}
|
|
||||||
|
|
||||||
def getSupportedTypes() {
|
|
||||||
return [
|
|
||||||
[obj: switches, name: "switches", attribute: "switch", capability: "switch", title: "Switches"],
|
|
||||||
[obj: motions, name: "motions", attribute: "motion", capability: "motionSensor", title: "Motion Sensors"],
|
|
||||||
[obj: temperature, name: "temperature", attribute: "temperature", capability: "temperatureMeasurement", title: "Temperature Sensors"],
|
|
||||||
[obj: contact, name: "contact", attribute: "contact", capability: "contactSensor", title: "Contact Sensors"],
|
|
||||||
[obj: presence, name: "presence", attribute: "presence", capability: "presenceSensor", title: "Presence Sensors"],
|
|
||||||
[obj: water, name: "water", attribute: "water", capability: "waterSensor", title: "Water Sensors"],
|
|
||||||
[obj: smoke, name: "smoke", attribute: "smoke", capability: "smokeDetector", title: "Smoke Sensors"],
|
|
||||||
[obj: battery, name: "battery", attribute: "battery", capability: "battery", title: "Batteries"]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
preferences {
|
|
||||||
section("Allow Lloyds Banking Group Connect & Protect service to monitor these devices") {
|
|
||||||
for (type in getSupportedTypes()) {
|
|
||||||
input type.get("name"), "capability.${type.get('capability')}", title: type.get('title'), multiple: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def installed() {
|
|
||||||
initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
def updated() {
|
|
||||||
unsubscribe()
|
|
||||||
initialize()
|
|
||||||
hubUpdateHandler()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def getRequestHeaders() {
|
|
||||||
return ['Accept': '*/*', 'X-API-KEY': appSettings.xApiKey]
|
|
||||||
}
|
|
||||||
|
|
||||||
def subscribeToDeviceEvents() {
|
|
||||||
for (type in getSupportedTypes()) {
|
|
||||||
subscribe(type.get("obj"), "${type.get("attribute")}", genericDeviceEventHandler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def initialize() {
|
|
||||||
if (atomicState.endpoint != null) {
|
|
||||||
log.debug "Detected endpoint: ${atomicState.endpoint}"
|
|
||||||
subscribeToDeviceEvents()
|
|
||||||
subscribe(location, "routineExecuted", modeChangeHandler)
|
|
||||||
subscribe(location, "mode", modeChangeHandler)
|
|
||||||
} else {
|
|
||||||
log.debug "There is no endpoint, requesting domotz for a new one"
|
|
||||||
requestNewEndpoint()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def getHubLocation() {
|
|
||||||
def location_info = [:]
|
|
||||||
location_info['uid'] = location.id
|
|
||||||
//location_info['hubs'] = location.hubs
|
|
||||||
location_info['latitude'] = location.latitude
|
|
||||||
location_info['longitude'] = location.longitude
|
|
||||||
location_info['current_mode'] = location.mode
|
|
||||||
//location_info['modes'] = location.modes
|
|
||||||
location_info['name'] = location.name
|
|
||||||
location_info['temperature_scale'] = location.temperatureScale
|
|
||||||
location_info['version'] = location.version
|
|
||||||
location_info['channel_name'] = location.channelName
|
|
||||||
location_info['zip_code'] = location.zipCode
|
|
||||||
log.debug "Triggered getHubLocation with properties: ${location_info}"
|
|
||||||
return location_info
|
|
||||||
}
|
|
||||||
|
|
||||||
def modeChangeHandler(evt) {
|
|
||||||
log.debug "mode changed to ${evt.value}"
|
|
||||||
def url = null
|
|
||||||
if (atomicState.endpoint != null) {
|
|
||||||
url = atomicState.endpoint + '/hub-change'
|
|
||||||
|
|
||||||
httpPutJson(
|
|
||||||
uri: url,
|
|
||||||
body: getHubLocation(),
|
|
||||||
headers: getRequestHeaders()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
log.debug "There is no endpoint, requesting domotz for a new one"
|
|
||||||
requestNewEndpoint()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def genericDeviceEventHandler(event) {
|
|
||||||
log.debug "Device Event Handler, event properties: ${event.getProperties().toString()}"
|
|
||||||
log.debug "Device Event Handler, value: ${event.value}"
|
|
||||||
def resp = [:]
|
|
||||||
def url = null
|
|
||||||
def device = null
|
|
||||||
|
|
||||||
device = getDevice(event.device, resp)
|
|
||||||
|
|
||||||
url = atomicState.endpoint + "/device/" + device.provider_uid + "/${event.name}"
|
|
||||||
|
|
||||||
log.debug "Device Event Handler, put url: ${url}"
|
|
||||||
log.debug "Device Event Handler, put body: value: ${event.value}\ndate: ${event.isoDate}"
|
|
||||||
httpPutJson(
|
|
||||||
uri: url,
|
|
||||||
body: [
|
|
||||||
"value": event.value,
|
|
||||||
"time" : event.isoDate
|
|
||||||
],
|
|
||||||
headers: getRequestHeaders()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def hubUpdateHandler() {
|
|
||||||
log.debug "Hub Update Handler, with settings: ${settings}"
|
|
||||||
def url = null
|
|
||||||
def deviceList = [:]
|
|
||||||
|
|
||||||
if (atomicState.endpoint != null) {
|
|
||||||
url = atomicState.endpoint + '/device-list'
|
|
||||||
log.debug "Hub Update Event Handler, put url: ${url}"
|
|
||||||
deviceList = getDeviceList()
|
|
||||||
httpPutJson(
|
|
||||||
uri: url,
|
|
||||||
body: deviceList,
|
|
||||||
headers: getRequestHeaders()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
log.debug "There is no endpoint, requesting domotz for a new one"
|
|
||||||
requestNewEndpoint()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def getDeviceList() {
|
|
||||||
try {
|
|
||||||
|
|
||||||
def resp = [:]
|
|
||||||
def attribute = null
|
|
||||||
|
|
||||||
for (type in getSupportedTypes()) {
|
|
||||||
type.get("obj").each {
|
|
||||||
device = getDevice(it, resp)
|
|
||||||
attribute = type.get("attribute")
|
|
||||||
if (it.currentState(attribute)) {
|
|
||||||
device['attributes'][attribute] = [
|
|
||||||
"value": it.currentState(attribute).value,
|
|
||||||
"time" : it.currentState(attribute).getIsoDate(),
|
|
||||||
"unit" : it.currentState(attribute).unit
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resp
|
|
||||||
} catch (e) {
|
|
||||||
log.debug("caught exception", e)
|
|
||||||
return [:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def getDevice(it, resp) {
|
|
||||||
if (resp[it.id]) {
|
|
||||||
return resp[it.id]
|
|
||||||
}
|
|
||||||
resp[it.id] = [name: it.name, display_name: it.displayName, provider_uid: it.id, type: it.typeName, label: it.label, manufacturer_name: it.manufacturerName, model: it.modelName, attributes: [:]]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def activateMonitoring(resp) {
|
|
||||||
unsubscribe()
|
|
||||||
log.debug "Event monitoring activated for endpoint: ${request.JSON.endpoint}"
|
|
||||||
atomicState.endpoint = request.JSON.endpoint
|
|
||||||
log.debug "Event monitoring activated for endpoint: ${atomicState.endpoint}"
|
|
||||||
initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
def deactivateMonitoring() {
|
|
||||||
log.debug "Event monitoring deactivated."
|
|
||||||
atomicState.endpoint = null
|
|
||||||
unsubscribe()
|
|
||||||
}
|
|
||||||
|
|
||||||
def requestNewEndpoint() {
|
|
||||||
log.debug "Requesting a new endpoint."
|
|
||||||
def hubId = location.id
|
|
||||||
def params = [
|
|
||||||
uri : "${appSettings.endpointRetrievalUrl}/${hubId}/endpoint",
|
|
||||||
headers: getRequestHeaders()
|
|
||||||
]
|
|
||||||
|
|
||||||
try {
|
|
||||||
httpGet(params) { response ->
|
|
||||||
log.debug "Request was successful, received endpoint: ${response.data.endpoint}"
|
|
||||||
atomicState.endpoint = response.data.endpoint
|
|
||||||
subscribeToDeviceEvents()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
log.debug "Unable to retrieve the endpoint"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def handleClientUninstall() {
|
|
||||||
log.info("Deactivated from client")
|
|
||||||
try {
|
|
||||||
app.delete()
|
|
||||||
} catch (e) {
|
|
||||||
unschedule()
|
|
||||||
unsubscribe()
|
|
||||||
httpError(500, "An error occurred during deleting SmartApp: ${e}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mappings {
|
|
||||||
path("/device") {
|
|
||||||
action:
|
|
||||||
[
|
|
||||||
GET: getDeviceList
|
|
||||||
]
|
|
||||||
}
|
|
||||||
path("/location") {
|
|
||||||
action:
|
|
||||||
[
|
|
||||||
GET: getHubLocation
|
|
||||||
]
|
|
||||||
}
|
|
||||||
path("/monitoring") {
|
|
||||||
action:
|
|
||||||
[
|
|
||||||
POST : activateMonitoring,
|
|
||||||
DELETE: deactivateMonitoring
|
|
||||||
]
|
|
||||||
}
|
|
||||||
path("/uninstall") {
|
|
||||||
action
|
|
||||||
[GET: handleClientUninstall]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -765,7 +765,6 @@ def turnOffSwitch() {
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
device.off();
|
device.off();
|
||||||
|
|
||||||
return [Device_id: params.id, result_action: "200"]
|
return [Device_id: params.id, result_action: "200"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -789,6 +788,7 @@ def getTempSensorsStatus(id) {
|
|||||||
return []
|
return []
|
||||||
} else {
|
} else {
|
||||||
def bat = getBatteryStatus(device.id)
|
def bat = getBatteryStatus(device.id)
|
||||||
return [temperature: device.currentValue('temperature')] + bat
|
def scale = [Scale: location.temperatureScale]
|
||||||
|
return [temperature: device.currentValue('temperature')] + bat + scale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,14 +41,14 @@ def updated() {
|
|||||||
def motionHandler(evt) {
|
def motionHandler(evt) {
|
||||||
log.debug "handler $evt.name: $evt.value"
|
log.debug "handler $evt.name: $evt.value"
|
||||||
if (evt.value == "inactive") {
|
if (evt.value == "inactive") {
|
||||||
runIn(delayMins * 60, scheduleCheck, [overwrite: false])
|
runIn(delayMins * 60, scheduleCheck, [overwrite: true])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def presenceHandler(evt) {
|
def presenceHandler(evt) {
|
||||||
log.debug "handler $evt.name: $evt.value"
|
log.debug "handler $evt.name: $evt.value"
|
||||||
if (evt.value == "not present") {
|
if (evt.value == "not present") {
|
||||||
runIn(delayMins * 60, scheduleCheck, [overwrite: false])
|
runIn(delayMins * 60, scheduleCheck, [overwrite: true])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpenT2T SmartApp Test
|
* OpenT2T SmartApp Test
|
||||||
*
|
*
|
||||||
@@ -81,28 +85,33 @@ def getInputs() {
|
|||||||
//API external Endpoints
|
//API external Endpoints
|
||||||
mappings {
|
mappings {
|
||||||
path("/devices") {
|
path("/devices") {
|
||||||
action: [
|
action:
|
||||||
|
[
|
||||||
GET: "getDevices"
|
GET: "getDevices"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
path("/devices/:id") {
|
path("/devices/:id") {
|
||||||
action: [
|
action:
|
||||||
|
[
|
||||||
GET: "getDevice"
|
GET: "getDevice"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
path("/update/:id") {
|
path("/update/:id") {
|
||||||
action: [
|
action:
|
||||||
|
[
|
||||||
PUT: "updateDevice"
|
PUT: "updateDevice"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
path("/deviceSubscription") {
|
path("/deviceSubscription") {
|
||||||
action: [
|
action:
|
||||||
|
[
|
||||||
POST : "registerDeviceChange",
|
POST : "registerDeviceChange",
|
||||||
DELETE: "unregisterDeviceChange"
|
DELETE: "unregisterDeviceChange"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
path("/locationSubscription") {
|
path("/locationSubscription") {
|
||||||
action: [
|
action:
|
||||||
|
[
|
||||||
POST : "registerDeviceGraph",
|
POST : "registerDeviceGraph",
|
||||||
DELETE: "unregisterDeviceGraph"
|
DELETE: "unregisterDeviceGraph"
|
||||||
]
|
]
|
||||||
@@ -116,6 +125,8 @@ def installed() {
|
|||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
log.debug "Updating with settings: ${settings}"
|
log.debug "Updating with settings: ${settings}"
|
||||||
|
|
||||||
|
//Initialize state variables if didn't exist.
|
||||||
if (state.deviceSubscriptionMap == null) {
|
if (state.deviceSubscriptionMap == null) {
|
||||||
state.deviceSubscriptionMap = [:]
|
state.deviceSubscriptionMap = [:]
|
||||||
log.debug "deviceSubscriptionMap created."
|
log.debug "deviceSubscriptionMap created."
|
||||||
@@ -124,6 +135,11 @@ def updated() {
|
|||||||
state.locationSubscriptionMap = [:]
|
state.locationSubscriptionMap = [:]
|
||||||
log.debug "locationSubscriptionMap created."
|
log.debug "locationSubscriptionMap created."
|
||||||
}
|
}
|
||||||
|
if (state.verificationKeyMap == null) {
|
||||||
|
state.verificationKeyMap = [:]
|
||||||
|
log.debug "verificationKeyMap created."
|
||||||
|
}
|
||||||
|
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
registerAllDeviceSubscriptions()
|
registerAllDeviceSubscriptions()
|
||||||
}
|
}
|
||||||
@@ -132,9 +148,11 @@ def initialize() {
|
|||||||
log.debug "Initializing with settings: ${settings}"
|
log.debug "Initializing with settings: ${settings}"
|
||||||
state.deviceSubscriptionMap = [:]
|
state.deviceSubscriptionMap = [:]
|
||||||
log.debug "deviceSubscriptionMap created."
|
log.debug "deviceSubscriptionMap created."
|
||||||
registerAllDeviceSubscriptions()
|
|
||||||
state.locationSubscriptionMap = [:]
|
state.locationSubscriptionMap = [:]
|
||||||
log.debug "locationSubscriptionMap created."
|
log.debug "locationSubscriptionMap created."
|
||||||
|
state.verificationKeyMap = [:]
|
||||||
|
log.debug "verificationKeyMap created."
|
||||||
|
registerAllDeviceSubscriptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** Subscription Functions ***/
|
/*** Subscription Functions ***/
|
||||||
@@ -160,6 +178,7 @@ def registerDeviceChange() {
|
|||||||
def subscriptionEndpt = params.subscriptionURL
|
def subscriptionEndpt = params.subscriptionURL
|
||||||
def deviceId = params.deviceId
|
def deviceId = params.deviceId
|
||||||
def myDevice = findDevice(deviceId)
|
def myDevice = findDevice(deviceId)
|
||||||
|
|
||||||
if (myDevice == null) {
|
if (myDevice == null) {
|
||||||
httpError(404, "Cannot find device with device ID ${deviceId}.")
|
httpError(404, "Cannot find device with device ID ${deviceId}.")
|
||||||
}
|
}
|
||||||
@@ -179,12 +198,18 @@ def registerDeviceChange() {
|
|||||||
state.deviceSubscriptionMap[deviceId] << subscriptionEndpt
|
state.deviceSubscriptionMap[deviceId] << subscriptionEndpt
|
||||||
log.info "Added subscription URL: ${subscriptionEndpt} for ${myDevice.displayName}"
|
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) {
|
} catch (e) {
|
||||||
httpError(500, "something went wrong: $e")
|
httpError(500, "something went wrong: $e")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info "Current subscription map is ${state.deviceSubscriptionMap}"
|
log.info "Current subscription map is ${state.deviceSubscriptionMap}"
|
||||||
|
log.info "Current verification key map is ${state.verificationKeyMap}"
|
||||||
return ["succeed"]
|
return ["succeed"]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +231,7 @@ def unregisterDeviceChange() {
|
|||||||
} else {
|
} else {
|
||||||
state.deviceSubscriptionMap[deviceId].remove(subscriptionEndpt)
|
state.deviceSubscriptionMap[deviceId].remove(subscriptionEndpt)
|
||||||
}
|
}
|
||||||
|
state.verificationKeyMap.remove(subscriptionEndpt)
|
||||||
log.info "Removed subscription URL: ${subscriptionEndpt} for ${myDevice.displayName}"
|
log.info "Removed subscription URL: ${subscriptionEndpt} for ${myDevice.displayName}"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -217,6 +243,7 @@ def unregisterDeviceChange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.info "Current subscription map is ${state.deviceSubscriptionMap}"
|
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
|
//Endpoints function: Subscribe to device additiona/removal updated in a location
|
||||||
@@ -235,7 +262,14 @@ def registerDeviceGraph() {
|
|||||||
state.locationSubscriptionMap[location.id] << subscriptionEndpt
|
state.locationSubscriptionMap[location.id] << subscriptionEndpt
|
||||||
log.info "Added subscription URL: ${subscriptionEndpt} for Location ${location.name}"
|
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 location subscription map is ${state.locationSubscriptionMap}"
|
||||||
|
log.info "Current verification key map is ${state.verificationKeyMap}"
|
||||||
return ["succeed"]
|
return ["succeed"]
|
||||||
} else {
|
} else {
|
||||||
httpError(400, "missing input parameter: subscriptionURL")
|
httpError(400, "missing input parameter: subscriptionURL")
|
||||||
@@ -254,6 +288,7 @@ def unregisterDeviceGraph() {
|
|||||||
} else {
|
} else {
|
||||||
state.locationSubscriptionMap[location.id].remove(subscriptionEndpt)
|
state.locationSubscriptionMap[location.id].remove(subscriptionEndpt)
|
||||||
}
|
}
|
||||||
|
state.verificationKeyMap.remove(subscriptionEndpt)
|
||||||
log.info "Removed subscription URL: ${subscriptionEndpt} for Location ${location.name}"
|
log.info "Removed subscription URL: ${subscriptionEndpt} for Location ${location.name}"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -264,26 +299,38 @@ def unregisterDeviceGraph() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.info "Current location subscription map is ${state.locationSubscriptionMap}"
|
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
|
//When events are triggered, send HTTP post to web socket servers
|
||||||
def deviceEventHandler(evt) {
|
def deviceEventHandler(evt) {
|
||||||
def evt_device = evt.device
|
def evtDevice = evt.device
|
||||||
def evt_deviceType = getDeviceType(evt_device)
|
def evtDeviceType = getDeviceType(evtDevice)
|
||||||
def deviceInfo
|
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)
|
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
|
//send event to all subscriptions urls
|
||||||
log.debug "Current subscription urls for ${evt_device.displayName} is ${state.deviceSubscriptionMap[evt_device.id]}"
|
log.debug "Current subscription urls for ${evtDevice.displayName} is ${state.deviceSubscriptionMap[evtDevice.id]}"
|
||||||
state.deviceSubscriptionMap[evt_device.id].each {
|
state.deviceSubscriptionMap[evtDevice.id].each {
|
||||||
params.uri = "${it}"
|
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 "POST URI: ${params.uri}"
|
||||||
|
log.trace "Header: ${params.header}"
|
||||||
log.trace "Payload: ${params.body}"
|
log.trace "Payload: ${params.body}"
|
||||||
try {
|
try {
|
||||||
httpPostJson(params) { resp ->
|
httpPostJson(params) { resp ->
|
||||||
@@ -301,15 +348,22 @@ def locationEventHandler(evt) {
|
|||||||
switch (evt.name) {
|
switch (evt.name) {
|
||||||
case "DeviceCreated":
|
case "DeviceCreated":
|
||||||
case "DeviceDeleted":
|
case "DeviceDeleted":
|
||||||
def evt_device = evt.device
|
def evtDevice = evt.device
|
||||||
def evt_deviceType = getDeviceType(evt_device)
|
def evtDeviceType = getDeviceType(evtDevice)
|
||||||
log.info "DeviceName: ${evt_device.displayName}, DeviceID: ${evt_device.id}, deviceType: ${evt_deviceType}"
|
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 {
|
state.locationSubscriptionMap[location.id].each {
|
||||||
params.uri = "${it}"
|
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 "POST URI: ${params.uri}"
|
||||||
|
log.trace "Header: ${params.header}"
|
||||||
log.trace "Payload: ${params.body}"
|
log.trace "Payload: ${params.body}"
|
||||||
try {
|
try {
|
||||||
httpPostJson(params) { resp ->
|
httpPostJson(params) { resp ->
|
||||||
@@ -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 ***/
|
/*** Device Query/Update Functions ***/
|
||||||
|
|
||||||
@@ -433,8 +504,7 @@ private getDeviceType(device) {
|
|||||||
|
|
||||||
//Loop through the device capability list to determine the device type.
|
//Loop through the device capability list to determine the device type.
|
||||||
capabilities.each { capability ->
|
capabilities.each { capability ->
|
||||||
switch(capability.name.toLowerCase())
|
switch (capability.name.toLowerCase()) {
|
||||||
{
|
|
||||||
case "switch":
|
case "switch":
|
||||||
deviceType = "switch"
|
deviceType = "switch"
|
||||||
|
|
||||||
@@ -579,8 +649,7 @@ private mapDeviceCommands(command, value) {
|
|||||||
if (value == 1 || value == "1" || value == "lock") {
|
if (value == 1 || value == "1" || value == "lock") {
|
||||||
resultCommand = "lock"
|
resultCommand = "lock"
|
||||||
resultValue = ""
|
resultValue = ""
|
||||||
}
|
} else if (value == 0 || value == "0" || value == "unlock") {
|
||||||
else if (value == 0 || value == "0" || value == "unlock") {
|
|
||||||
resultCommand = "unlock"
|
resultCommand = "unlock"
|
||||||
resultValue = ""
|
resultValue = ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,12 +30,15 @@ preferences {
|
|||||||
section("Monitor this door or window") {
|
section("Monitor this door or window") {
|
||||||
input "contact", "capability.contactSensor"
|
input "contact", "capability.contactSensor"
|
||||||
}
|
}
|
||||||
|
|
||||||
section("And notify me if it's open for more than this many minutes (default 10)") {
|
section("And notify me if it's open for more than this many minutes (default 10)") {
|
||||||
input "openThreshold", "number", description: "Number of minutes", required: false
|
input "openThreshold", "number", description: "Number of minutes", required: false
|
||||||
}
|
}
|
||||||
|
|
||||||
section("Delay between notifications (default 10 minutes") {
|
section("Delay between notifications (default 10 minutes") {
|
||||||
input "frequency", "number", title: "Number of minutes", description: "", required: false
|
input "frequency", "number", title: "Number of minutes", description: "", required: false
|
||||||
}
|
}
|
||||||
|
|
||||||
section("Via text message at this number (or via push notification if not specified") {
|
section("Via text message at this number (or via push notification if not specified") {
|
||||||
input("recipients", "contact", title: "Send notifications to") {
|
input("recipients", "contact", title: "Send notifications to") {
|
||||||
input "phone", "phone", title: "Phone number (optional)", required: false
|
input "phone", "phone", title: "Phone number (optional)", required: false
|
||||||
@@ -59,18 +62,15 @@ def subscribe() {
|
|||||||
subscribe(contact, "contact.closed", doorClosed)
|
subscribe(contact, "contact.closed", doorClosed)
|
||||||
}
|
}
|
||||||
|
|
||||||
def doorOpen(evt)
|
def doorOpen(evt) {
|
||||||
{
|
|
||||||
log.trace "doorOpen($evt.name: $evt.value)"
|
log.trace "doorOpen($evt.name: $evt.value)"
|
||||||
def t0 = now()
|
|
||||||
def delay = (openThreshold != null && openThreshold != "") ? openThreshold * 60 : 600
|
def delay = (openThreshold != null && openThreshold != "") ? openThreshold * 60 : 600
|
||||||
runIn(delay, doorOpenTooLong, [overwrite: false])
|
runIn(delay, doorOpenTooLong, [overwrite: true])
|
||||||
log.debug "scheduled doorOpenTooLong in ${now() - t0} msec"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def doorClosed(evt)
|
def doorClosed(evt) {
|
||||||
{
|
|
||||||
log.trace "doorClosed($evt.name: $evt.value)"
|
log.trace "doorClosed($evt.name: $evt.value)"
|
||||||
|
unschedule(doorOpenTooLong)
|
||||||
}
|
}
|
||||||
|
|
||||||
def doorOpenTooLong() {
|
def doorOpenTooLong() {
|
||||||
@@ -92,15 +92,13 @@ def doorOpenTooLong() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendMessage()
|
void sendMessage() {
|
||||||
{
|
|
||||||
def minutes = (openThreshold != null && openThreshold != "") ? openThreshold : 10
|
def minutes = (openThreshold != null && openThreshold != "") ? openThreshold : 10
|
||||||
def msg = "${contact.displayName} has been left open for ${minutes} minutes."
|
def msg = "${contact.displayName} has been left open for ${minutes} minutes."
|
||||||
log.info msg
|
log.info msg
|
||||||
if (location.contactBookEnabled) {
|
if (location.contactBookEnabled) {
|
||||||
sendNotificationToContacts(msg, recipients)
|
sendNotificationToContacts(msg, recipients)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (phone) {
|
if (phone) {
|
||||||
sendSms phone, msg
|
sendSms phone, msg
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ def motionHandler(evt) {
|
|||||||
else {
|
else {
|
||||||
state.motionStopTime = now()
|
state.motionStopTime = now()
|
||||||
if(delayMinutes) {
|
if(delayMinutes) {
|
||||||
runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: false])
|
runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: true])
|
||||||
} else {
|
} else {
|
||||||
turnOffMotionAfterDelay()
|
turnOffMotionAfterDelay()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,19 +125,19 @@
|
|||||||
if(allOk) {
|
if(allOk) {
|
||||||
|
|
||||||
if(everyoneIsAway() && (state.sunMode == "sunrise")) {
|
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
|
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
|
||||||
runIn(delay, "setAway")
|
runIn(delay, "setAway")
|
||||||
}
|
}
|
||||||
|
|
||||||
if(everyoneIsAway() && (state.sunMode == "sunset")) {
|
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
|
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
|
||||||
runIn(delay, "setAway")
|
runIn(delay, "setAway")
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
log.info("Home is Occupied Setting New Home Mode")
|
log.debug("Home is Occupied Setting New Home Mode")
|
||||||
setHome()
|
setHome()
|
||||||
|
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
log.debug("Checking if everyone is away")
|
log.debug("Checking if everyone is away")
|
||||||
|
|
||||||
if(everyoneIsAway()) {
|
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
|
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
|
||||||
runIn(delay, "setAway")
|
runIn(delay, "setAway")
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
else {
|
else {
|
||||||
def lastTime = state[evt.deviceId]
|
def lastTime = state[evt.deviceId]
|
||||||
if (lastTime == null || now() - lastTime >= 1 * 60000) {
|
if (lastTime == null || now() - lastTime >= 1 * 60000) {
|
||||||
log.info("Someone is home, running home sequence")
|
log.debug("Someone is home, running home sequence")
|
||||||
setHome()
|
setHome()
|
||||||
}
|
}
|
||||||
state[evt.deviceId] = now()
|
state[evt.deviceId] = now()
|
||||||
@@ -175,14 +175,14 @@
|
|||||||
if(everyoneIsAway()) {
|
if(everyoneIsAway()) {
|
||||||
if(state.sunMode == "sunset") {
|
if(state.sunMode == "sunset") {
|
||||||
def message = "Performing \"${awayNight}\" for you as requested."
|
def message = "Performing \"${awayNight}\" for you as requested."
|
||||||
log.info(message)
|
log.debug(message)
|
||||||
sendAway(message)
|
sendAway(message)
|
||||||
location.helloHome.execute(settings.awayNight)
|
location.helloHome.execute(settings.awayNight)
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(state.sunMode == "sunrise") {
|
else if(state.sunMode == "sunrise") {
|
||||||
def message = "Performing \"${awayDay}\" for you as requested."
|
def message = "Performing \"${awayDay}\" for you as requested."
|
||||||
log.info(message)
|
log.debug(message)
|
||||||
sendAway(message)
|
sendAway(message)
|
||||||
location.helloHome.execute(settings.awayDay)
|
location.helloHome.execute(settings.awayDay)
|
||||||
}
|
}
|
||||||
@@ -192,19 +192,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
else {
|
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
|
//set home mode when house is occupied
|
||||||
def setHome() {
|
def setHome() {
|
||||||
sendOutOfDateNotification()
|
sendOutOfDateNotification()
|
||||||
log.info("Setting Home Mode!!")
|
log.debug("Setting Home Mode!!")
|
||||||
if(anyoneIsHome()) {
|
if(anyoneIsHome()) {
|
||||||
if(state.sunMode == "sunset"){
|
if(state.sunMode == "sunset"){
|
||||||
if (location.mode != "${homeModeNight}"){
|
if (location.mode != "${homeModeNight}"){
|
||||||
def message = "Performing \"${homeNight}\" for you as requested."
|
def message = "Performing \"${homeNight}\" for you as requested."
|
||||||
log.info(message)
|
log.debug(message)
|
||||||
sendHome(message)
|
sendHome(message)
|
||||||
location.helloHome.execute(settings.homeNight)
|
location.helloHome.execute(settings.homeNight)
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,7 @@
|
|||||||
if(state.sunMode == "sunrise"){
|
if(state.sunMode == "sunrise"){
|
||||||
if (location.mode != "${homeModeDay}"){
|
if (location.mode != "${homeModeDay}"){
|
||||||
def message = "Performing \"${homeDay}\" for you as requested."
|
def message = "Performing \"${homeDay}\" for you as requested."
|
||||||
log.info(message)
|
log.debug(message)
|
||||||
sendHome(message)
|
sendHome(message)
|
||||||
location.helloHome.execute(settings.homeDay)
|
location.helloHome.execute(settings.homeDay)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user