mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-20 13:20:53 +00:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20d0da1732 | ||
|
|
c1422438ac | ||
|
|
8ed23f4c7e | ||
|
|
e7e6ea7d56 | ||
|
|
12896f4095 | ||
|
|
ab4e8a892a | ||
|
|
e076818573 | ||
|
|
cd8bbca5ee | ||
|
|
2d060bddfc | ||
|
|
4da9730319 | ||
|
|
25db4f5235 | ||
|
|
eae2a9ca08 | ||
|
|
2dd2d7cba4 | ||
|
|
f5708bca8b | ||
|
|
a9da6d130a | ||
|
|
3a2c6f86be | ||
|
|
71d2b89a37 | ||
|
|
b131ba1507 | ||
|
|
f04a9e3f7a | ||
|
|
6a905e4380 | ||
|
|
442f16680d | ||
|
|
1c68099b52 | ||
|
|
cc9321ca9f | ||
|
|
919c9b88ee | ||
|
|
2438942071 | ||
|
|
d86dcfd82f |
263
devicetypes/fuzzysb/dlink-dch-z510.src/dlink-dch-z510.groovy
Normal file
263
devicetypes/fuzzysb/dlink-dch-z510.src/dlink-dch-z510.groovy
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2015 Stuart Buchanan
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Dlink DCH-Z510
|
||||||
|
*
|
||||||
|
* Author: fuzzysb
|
||||||
|
* Date: 2015-01-05
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
input "defaultSound", "enum", title: "Default Sound to use for the Siren?", options: ["Emergency","FireAlarm","Ambulance","PoliceCar","DoorChime"], required: false, defaultValue: "Emergency"
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata {
|
||||||
|
definition (name: "Dlink DCH-Z510", namespace: "fuzzysb", author: "Stuart Buchanan") {
|
||||||
|
capability "Actuator"
|
||||||
|
capability "Alarm"
|
||||||
|
capability "Switch"
|
||||||
|
capability "Configuration"
|
||||||
|
|
||||||
|
command "Emergency"
|
||||||
|
command "FireAlarm"
|
||||||
|
command "Ambulance"
|
||||||
|
command "PoliceCar"
|
||||||
|
command "DoorChime"
|
||||||
|
|
||||||
|
fingerprint deviceId: "0x1005", inClusters: "0x5E,0x71,0x20,0x25,0x85,0x70,0x72,0x86,0x30,0x59,0x73,0x5A,0x98,0x7A"
|
||||||
|
}
|
||||||
|
|
||||||
|
simulator {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tiles(scale: 2) {
|
||||||
|
multiAttributeTile(name:"alarm", type: "generic", width: 6, height: 4){
|
||||||
|
tileAttribute ("device.alarm", key: "PRIMARY_CONTROL") {
|
||||||
|
attributeState "off", label:'off', action:'alarm.siren', icon:"st.alarm.alarm.alarm", backgroundColor:"#ffffff"
|
||||||
|
attributeState "both", label:'alarm!', action:'alarm.off', icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
standardTile("Emergency", "device.button", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "default", label:'Emergency', action:"Emergency", icon:"st.Weather.weather1"
|
||||||
|
}
|
||||||
|
standardTile("FireAlarm", "device.button", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "default", label:'Fire Alarm', action:"FireAlarm", icon:"st.Outdoor.outdoor10"
|
||||||
|
}
|
||||||
|
standardTile("Ambulance", "device.button", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "default", label:'Ambulance', action:"Ambulance", icon:"st.Transportation.transportation2"
|
||||||
|
}
|
||||||
|
standardTile("PoliceCar", "device.button", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "default", label:'Police Car', action:"PoliceCar", icon:"st.Transportation.transportation8"
|
||||||
|
}
|
||||||
|
standardTile("DoorChime", "device.button", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "default", label:'Door Chime', action:"DoorChime", icon:"st.Home.home30"
|
||||||
|
}
|
||||||
|
standardTile("off", "device.button", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "default", label:'', action:"alarm.off", icon:"st.secondary.off"
|
||||||
|
}
|
||||||
|
main "alarm"
|
||||||
|
details(["alarm", "Emergency", "FireAlarm", "Ambulance", "PoliceCar", "DoorChime", "off"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def parse(String description)
|
||||||
|
{
|
||||||
|
def result = null
|
||||||
|
if (description.startsWith("Err 106")) {
|
||||||
|
state.sec = 0
|
||||||
|
result = createEvent( name: "secureInclusion", value: "failed", isStateChange: true,
|
||||||
|
descriptionText: "This sensor failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.")
|
||||||
|
} else if (description != "updated") {
|
||||||
|
def cmd = zwave.parse(description, [0x20: 1, 0x25: 1, 0x26: 1, 0x70: 1, 0x80: 1])
|
||||||
|
if (cmd) {
|
||||||
|
result = zwaveEvent(cmd)
|
||||||
|
log.debug "Parse returned ${result?.inspect()}"
|
||||||
|
} else {
|
||||||
|
log.debug("Couldn't zwave.parse '$description'")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
log.debug "Parsed '${description}' to ${result.inspect()}"
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
|
||||||
|
def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x25: 3, 0x26: 3, 0x70: 1, 0x80: 1])
|
||||||
|
state.sec = 1
|
||||||
|
log.debug "encapsulated: ${encapsulatedCommand}"
|
||||||
|
if (encapsulatedCommand) {
|
||||||
|
zwaveEvent(encapsulatedCommand)
|
||||||
|
} else {
|
||||||
|
log.warn "Unable to extract encapsulated cmd from $cmd"
|
||||||
|
createEvent(descriptionText: cmd.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
|
||||||
|
response(configure())
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
|
||||||
|
log.debug "---CONFIGURATION REPORT V2--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}"
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd)
|
||||||
|
{
|
||||||
|
[name: "switch", value: cmd.value ? "on" : "off", type: "digital", displayed: true, isStateChange: true]
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
|
||||||
|
log.debug "rx $cmd"
|
||||||
|
[
|
||||||
|
createEvent([name: "switch", value: cmd.value ? "on" : "off", displayed: false]),
|
||||||
|
createEvent([name: "alarm", value: cmd.value ? "both" : "off"])
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) {
|
||||||
|
createEvent(name:"Alarm", cmd.sensorValue ? "on" : "off")
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
|
||||||
|
if (cmd.notificationType == 6 && cmd.event == 22) {
|
||||||
|
log.debug "Playing Door Chime"
|
||||||
|
} else if (cmd.notificationType == 10 && cmd.event == 1) {
|
||||||
|
log.debug "Playing Police Car"
|
||||||
|
} else if (cmd.notificationType == 10 && cmd.event == 3) {
|
||||||
|
log.debug "Playing Ambulance"
|
||||||
|
} else if (cmd.notificationType == 10 && cmd.event == 2) {
|
||||||
|
log.debug "Playing Fire Alarm"
|
||||||
|
} else if (cmd.notificationType == 7 && cmd.event == 1) {
|
||||||
|
log.debug "Playing Emergency"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
||||||
|
log.debug "Unhandled: $cmd"
|
||||||
|
createEvent(descriptionText: cmd.toString(), isStateChange: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
def strobe() {
|
||||||
|
on()
|
||||||
|
}
|
||||||
|
|
||||||
|
def siren() {
|
||||||
|
on()
|
||||||
|
}
|
||||||
|
|
||||||
|
def both() {
|
||||||
|
on()
|
||||||
|
}
|
||||||
|
|
||||||
|
def on() {
|
||||||
|
log.debug("Sounding Siren")
|
||||||
|
switch ( settings.defaultSound ) {
|
||||||
|
case "Emergency":
|
||||||
|
Emergency()
|
||||||
|
break
|
||||||
|
|
||||||
|
case "FireAlarm":
|
||||||
|
FireAlarm()
|
||||||
|
break
|
||||||
|
|
||||||
|
case "Ambulance":
|
||||||
|
Ambulance()
|
||||||
|
break
|
||||||
|
|
||||||
|
case "PoliceCar":
|
||||||
|
PoliceCar()
|
||||||
|
break
|
||||||
|
|
||||||
|
case "DoorChime":
|
||||||
|
DoorChime()
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
Emergency()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def off() {
|
||||||
|
log.debug "sending off"
|
||||||
|
[
|
||||||
|
secure(zwave.basicV1.basicSet(value: 0x00)),
|
||||||
|
secure(zwave.basicV1.basicGet())
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def Emergency() {
|
||||||
|
log.debug "Sounding Siren With Emergency"
|
||||||
|
[
|
||||||
|
secure(zwave.notificationV3.notificationReport(event: 0x01, notificationType: 0x07)),
|
||||||
|
secure(zwave.basicV1.basicGet())
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def FireAlarm() {
|
||||||
|
log.debug "Sounding Siren With Fire Alarm"
|
||||||
|
[
|
||||||
|
secure(zwave.notificationV3.notificationReport(event: 0x02, notificationType: 0x0A)),
|
||||||
|
secure(zwave.basicV1.basicGet())
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def Ambulance() {
|
||||||
|
log.debug "Sounding Siren With Ambulance"
|
||||||
|
[
|
||||||
|
secure(zwave.notificationV3.notificationReport(event: 0x03, notificationType: 0x0A)),
|
||||||
|
secure(zwave.basicV1.basicGet())
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def PoliceCar() {
|
||||||
|
log.debug "Sounding Siren With Police Car"
|
||||||
|
[
|
||||||
|
secure(zwave.notificationV3.notificationReport(event: 0x01, notificationType: 0x0A)),
|
||||||
|
secure(zwave.basicV1.basicGet())
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def DoorChime() {
|
||||||
|
log.debug "Sounding Siren With Door Chime"
|
||||||
|
[
|
||||||
|
secure(zwave.notificationV3.notificationReport(event: 0x16, notificationType: 0x06)),
|
||||||
|
secure(zwave.basicV1.basicGet())
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def configure() {
|
||||||
|
log.debug "Resetting Siren Parameters to SmartThings Compatible Defaults"
|
||||||
|
def cmds = []
|
||||||
|
|
||||||
|
cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 4, size: 1)
|
||||||
|
cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 29, size: 1)
|
||||||
|
cmds << zwave.configurationV1.configurationSet(configurationValue: [6], parameterNumber: 31, size: 1)
|
||||||
|
|
||||||
|
delayBetween(cmds, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
private secure(physicalgraph.zwave.Command cmd) {
|
||||||
|
if (state.sec) {
|
||||||
|
log.debug "Sending Secure Command $cmd"
|
||||||
|
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
|
||||||
|
} else {
|
||||||
|
log.debug "Sending Insecure Command $cmd"
|
||||||
|
cmd.format()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,294 +1,294 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2015 SmartThings
|
* Copyright 2015 SmartThings
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
* 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:
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* 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
|
* 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
|
* 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.
|
* for the specific language governing permissions and limitations under the License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Arrival Sensor", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Arrival Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Tone"
|
capability "Tone"
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Signal Strength"
|
capability "Signal Strength"
|
||||||
capability "Presence Sensor"
|
capability "Presence Sensor"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
|
|
||||||
fingerprint profileId: "FC01", deviceId: "019A"
|
fingerprint profileId: "FC01", deviceId: "019A"
|
||||||
fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000,0003", outClusters: "0003"
|
fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000,0003", outClusters: "0003"
|
||||||
fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000", outClusters: "0006"
|
fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000", outClusters: "0006"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
status "present": "presence: 1"
|
status "present": "presence: 1"
|
||||||
status "not present": "presence: 0"
|
status "not present": "presence: 0"
|
||||||
status "battery": "battery: 27, batteryDivisor: 0A, rssi: 100, lqi: 64"
|
status "battery": "battery: 27, batteryDivisor: 0A, rssi: 100, lqi: 64"
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
section {
|
section {
|
||||||
image(name: 'educationalcontent', multiple: true, images: [
|
image(name: 'educationalcontent', multiple: true, images: [
|
||||||
"http://cdn.device-gse.smartthings.com/Arrival/Arrival1.jpg",
|
"http://cdn.device-gse.smartthings.com/Arrival/Arrival1.jpg",
|
||||||
"http://cdn.device-gse.smartthings.com/Arrival/Arrival2.jpg"
|
"http://cdn.device-gse.smartthings.com/Arrival/Arrival2.jpg"
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
||||||
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
|
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
|
||||||
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ebeef2"
|
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ebeef2"
|
||||||
}
|
}
|
||||||
standardTile("beep", "device.beep", decoration: "flat") {
|
standardTile("beep", "device.beep", decoration: "flat") {
|
||||||
state "beep", label:'', action:"tone.beep", icon:"st.secondary.beep", backgroundColor:"#ffffff"
|
state "beep", label:'', action:"tone.beep", icon:"st.secondary.beep", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) {
|
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""/*, backgroundColors:[
|
state "battery", label:'${currentValue}% battery', unit:""/*, backgroundColors:[
|
||||||
[value: 5, color: "#BC2323"],
|
[value: 5, color: "#BC2323"],
|
||||||
[value: 10, color: "#D04E00"],
|
[value: 10, color: "#D04E00"],
|
||||||
[value: 15, color: "#F1D801"],
|
[value: 15, color: "#F1D801"],
|
||||||
[value: 16, color: "#FFFFFF"]
|
[value: 16, color: "#FFFFFF"]
|
||||||
]*/
|
]*/
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
valueTile("lqi", "device.lqi", decoration: "flat", inactiveLabel: false) {
|
valueTile("lqi", "device.lqi", decoration: "flat", inactiveLabel: false) {
|
||||||
state "lqi", label:'${currentValue}% signal', unit:""
|
state "lqi", label:'${currentValue}% signal', unit:""
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
main "presence"
|
main "presence"
|
||||||
details(["presence", "beep", "battery"/*, "lqi"*/])
|
details(["presence", "beep", "battery"/*, "lqi"*/])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def beep() {
|
def beep() {
|
||||||
/*
|
/*
|
||||||
You can make the speaker turn on for 0.5-second beeps by sending some CLI commands:
|
You can make the speaker turn on for 0.5-second beeps by sending some CLI commands:
|
||||||
|
|
||||||
Command: send raw, wait 7, send raw, wait 7, send raw
|
Command: send raw, wait 7, send raw, wait 7, send raw
|
||||||
Future: new packet type "st.beep"
|
Future: new packet type "st.beep"
|
||||||
|
|
||||||
raw 0xFC05 {15 0A 11 00 00 15 01}
|
raw 0xFC05 {15 0A 11 00 00 15 01}
|
||||||
send 0x2F7F 2 2
|
send 0x2F7F 2 2
|
||||||
|
|
||||||
where "0xABCD" is the node ID of the Smart Tag, everything else above is a constant. Except
|
where "0xABCD" is the node ID of the Smart Tag, everything else above is a constant. Except
|
||||||
the "15 01" at the end of the first raw command, that sets the speaker's period (reciprocal
|
the "15 01" at the end of the first raw command, that sets the speaker's period (reciprocal
|
||||||
of frequency). You can play with this value up or down to experiment with loudness as the
|
of frequency). You can play with this value up or down to experiment with loudness as the
|
||||||
loudness will be strongly dependent upon frequency and the enclosure that it's in. Note that
|
loudness will be strongly dependent upon frequency and the enclosure that it's in. Note that
|
||||||
"15 01" represents the hex number 0x0115 so a lower frequency is "16 01" (longer period) and
|
"15 01" represents the hex number 0x0115 so a lower frequency is "16 01" (longer period) and
|
||||||
a higher frequency is "14 01" (shorter period). Note that since the tag only checks its parent
|
a higher frequency is "14 01" (shorter period). Note that since the tag only checks its parent
|
||||||
for messages every 5 seconds (while at rest) or every 3 seconds (while in motion) it will take
|
for messages every 5 seconds (while at rest) or every 3 seconds (while in motion) it will take
|
||||||
up to this long from the time you send the message to the time you hear a sound.
|
up to this long from the time you send the message to the time you hear a sound.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[
|
[
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}"
|
"raw 0xFC05 {15 0A 11 00 00 15 01}"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
def results
|
def results
|
||||||
if (isBatteryMessage(description)) {
|
if (isBatteryMessage(description)) {
|
||||||
results = parseBatteryMessage(description)
|
results = parseBatteryMessage(description)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
results = parsePresenceMessage(description)
|
results = parsePresenceMessage(description)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug "Parse returned $results.descriptionText"
|
log.debug "Parse returned $results.descriptionText"
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map parsePresenceMessage(String description) {
|
private Map parsePresenceMessage(String description) {
|
||||||
def name = parseName(description)
|
def name = parseName(description)
|
||||||
def value = parseValue(description)
|
def value = parseValue(description)
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
def descriptionText = parseDescriptionText(linkText, value, description)
|
def descriptionText = parseDescriptionText(linkText, value, description)
|
||||||
def handlerName = getState(value)
|
def handlerName = getState(value)
|
||||||
def isStateChange = isStateChange(device, name, value)
|
def isStateChange = isStateChange(device, name, value)
|
||||||
|
|
||||||
def results = [
|
def results = [
|
||||||
name: name,
|
name: name,
|
||||||
value: value,
|
value: value,
|
||||||
unit: null,
|
unit: null,
|
||||||
linkText: linkText,
|
linkText: linkText,
|
||||||
descriptionText: descriptionText,
|
descriptionText: descriptionText,
|
||||||
handlerName: handlerName,
|
handlerName: handlerName,
|
||||||
isStateChange: isStateChange,
|
isStateChange: isStateChange,
|
||||||
displayed: displayed(description, isStateChange)
|
displayed: displayed(description, isStateChange)
|
||||||
]
|
]
|
||||||
|
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
private String parseName(String description) {
|
private String parseName(String description) {
|
||||||
if (description?.startsWith("presence: ")) {
|
if (description?.startsWith("presence: ")) {
|
||||||
return "presence"
|
return "presence"
|
||||||
}
|
}
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
private String parseValue(String description) {
|
private String parseValue(String description) {
|
||||||
if (description?.startsWith("presence: "))
|
if (description?.startsWith("presence: "))
|
||||||
{
|
{
|
||||||
if (description?.endsWith("1"))
|
if (description?.endsWith("1"))
|
||||||
{
|
{
|
||||||
return "present"
|
return "present"
|
||||||
}
|
}
|
||||||
else if (description?.endsWith("0"))
|
else if (description?.endsWith("0"))
|
||||||
{
|
{
|
||||||
return "not present"
|
return "not present"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
description
|
description
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseDescriptionText(String linkText, String value, String description) {
|
private parseDescriptionText(String linkText, String value, String description) {
|
||||||
switch(value) {
|
switch(value) {
|
||||||
case "present": return "$linkText has arrived"
|
case "present": return "$linkText has arrived"
|
||||||
case "not present": return "$linkText has left"
|
case "not present": return "$linkText has left"
|
||||||
default: return value
|
default: return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getState(String value) {
|
private getState(String value) {
|
||||||
def state = value
|
def state = value
|
||||||
if (value == "present") {
|
if (value == "present") {
|
||||||
state = "arrived"
|
state = "arrived"
|
||||||
}
|
}
|
||||||
else if (value == "not present") {
|
else if (value == "not present") {
|
||||||
state = "left"
|
state = "left"
|
||||||
}
|
}
|
||||||
|
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean isBatteryMessage(String description) {
|
private Boolean isBatteryMessage(String description) {
|
||||||
// "raw:36EF1C, dni:36EF, battery:1B, rssi:, lqi:"
|
// "raw:36EF1C, dni:36EF, battery:1B, rssi:, lqi:"
|
||||||
description ==~ /.*battery:.*rssi:.*lqi:.*/
|
description ==~ /.*battery:.*rssi:.*lqi:.*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private List parseBatteryMessage(String description) {
|
private List parseBatteryMessage(String description) {
|
||||||
def results = []
|
def results = []
|
||||||
def parts = description.split(',')
|
def parts = description.split(',')
|
||||||
parts.each { part ->
|
parts.each { part ->
|
||||||
part = part.trim()
|
part = part.trim()
|
||||||
if (part.startsWith('battery:')) {
|
if (part.startsWith('battery:')) {
|
||||||
def batteryResult = getBatteryResult(part, description)
|
def batteryResult = getBatteryResult(part, description)
|
||||||
if (batteryResult) {
|
if (batteryResult) {
|
||||||
results << batteryResult
|
results << batteryResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (part.startsWith('rssi:')) {
|
else if (part.startsWith('rssi:')) {
|
||||||
def rssiResult = getRssiResult(part, description)
|
def rssiResult = getRssiResult(part, description)
|
||||||
if (rssiResult) {
|
if (rssiResult) {
|
||||||
results << rssiResult
|
results << rssiResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (part.startsWith('lqi:')) {
|
else if (part.startsWith('lqi:')) {
|
||||||
def lqiResult = getLqiResult(part, description)
|
def lqiResult = getLqiResult(part, description)
|
||||||
if (lqiResult) {
|
if (lqiResult) {
|
||||||
results << lqiResult
|
results << lqiResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
private getBatteryResult(part, description) {
|
private getBatteryResult(part, description) {
|
||||||
def batteryDivisor = description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"} ? description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"}.split(":")[1].trim() : null
|
def batteryDivisor = description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"} ? description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"}.split(":")[1].trim() : null
|
||||||
def name = "battery"
|
def name = "battery"
|
||||||
def value = zigbee.parseSmartThingsBatteryValue(part, batteryDivisor)
|
def value = zigbee.parseSmartThingsBatteryValue(part, batteryDivisor)
|
||||||
def unit = "%"
|
def unit = "%"
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
def descriptionText = "$linkText battery was ${value}${unit}"
|
def descriptionText = "$linkText battery was ${value}${unit}"
|
||||||
def isStateChange = isStateChange(device, name, value)
|
def isStateChange = isStateChange(device, name, value)
|
||||||
|
|
||||||
[
|
[
|
||||||
name: name,
|
name: name,
|
||||||
value: value,
|
value: value,
|
||||||
unit: unit,
|
unit: unit,
|
||||||
linkText: linkText,
|
linkText: linkText,
|
||||||
descriptionText: descriptionText,
|
descriptionText: descriptionText,
|
||||||
handlerName: name,
|
handlerName: name,
|
||||||
isStateChange: isStateChange,
|
isStateChange: isStateChange,
|
||||||
//displayed: displayed(description, isStateChange)
|
//displayed: displayed(description, isStateChange)
|
||||||
displayed: false
|
displayed: false
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRssiResult(part, description) {
|
private getRssiResult(part, description) {
|
||||||
def name = "rssi"
|
def name = "rssi"
|
||||||
def parts = part.split(":")
|
def parts = part.split(":")
|
||||||
if (parts.size() != 2) return null
|
if (parts.size() != 2) return null
|
||||||
|
|
||||||
def valueString = parts[1].trim()
|
def valueString = parts[1].trim()
|
||||||
def valueInt = Integer.parseInt(valueString, 16)
|
def valueInt = Integer.parseInt(valueString, 16)
|
||||||
def value = (valueInt - 128).toString()
|
def value = (valueInt - 128).toString()
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
def descriptionText = "$linkText was $value dBm"
|
def descriptionText = "$linkText was $value dBm"
|
||||||
def isStateChange = isStateChange(device, name, value)
|
def isStateChange = isStateChange(device, name, value)
|
||||||
|
|
||||||
[
|
[
|
||||||
name: name,
|
name: name,
|
||||||
value: value,
|
value: value,
|
||||||
unit: "dBm",
|
unit: "dBm",
|
||||||
linkText: linkText,
|
linkText: linkText,
|
||||||
descriptionText: descriptionText,
|
descriptionText: descriptionText,
|
||||||
handlerName: null,
|
handlerName: null,
|
||||||
isStateChange: isStateChange,
|
isStateChange: isStateChange,
|
||||||
//displayed: displayed(description, isStateChange)
|
//displayed: displayed(description, isStateChange)
|
||||||
displayed: false
|
displayed: false
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use LQI (Link Quality Indicator) as a measure of signal strength. The values
|
* Use LQI (Link Quality Indicator) as a measure of signal strength. The values
|
||||||
* are 0 to 255 (0x00 to 0xFF) and higher values represent higher signal
|
* are 0 to 255 (0x00 to 0xFF) and higher values represent higher signal
|
||||||
* strength. Return as a percentage of 255.
|
* strength. Return as a percentage of 255.
|
||||||
*
|
*
|
||||||
* Note: To make the signal strength indicator more accurate, we could combine
|
* Note: To make the signal strength indicator more accurate, we could combine
|
||||||
* LQI with RSSI.
|
* LQI with RSSI.
|
||||||
*/
|
*/
|
||||||
private getLqiResult(part, description) {
|
private getLqiResult(part, description) {
|
||||||
def name = "lqi"
|
def name = "lqi"
|
||||||
def parts = part.split(":")
|
def parts = part.split(":")
|
||||||
if (parts.size() != 2) return null
|
if (parts.size() != 2) return null
|
||||||
|
|
||||||
def valueString = parts[1].trim()
|
def valueString = parts[1].trim()
|
||||||
def valueInt = Integer.parseInt(valueString, 16)
|
def valueInt = Integer.parseInt(valueString, 16)
|
||||||
def percentageOf = 255
|
def percentageOf = 255
|
||||||
def value = Math.round((valueInt / percentageOf * 100)).toString()
|
def value = Math.round((valueInt / percentageOf * 100)).toString()
|
||||||
def unit = "%"
|
def unit = "%"
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
def descriptionText = "$linkText Signal (LQI) was ${value}${unit}"
|
def descriptionText = "$linkText Signal (LQI) was ${value}${unit}"
|
||||||
def isStateChange = isStateChange(device, name, value)
|
def isStateChange = isStateChange(device, name, value)
|
||||||
|
|
||||||
[
|
[
|
||||||
name: name,
|
name: name,
|
||||||
value: value,
|
value: value,
|
||||||
unit: unit,
|
unit: unit,
|
||||||
linkText: linkText,
|
linkText: linkText,
|
||||||
descriptionText: descriptionText,
|
descriptionText: descriptionText,
|
||||||
handlerName: null,
|
handlerName: null,
|
||||||
isStateChange: isStateChange,
|
isStateChange: isStateChange,
|
||||||
//displayed: displayed(description, isStateChange)
|
//displayed: displayed(description, isStateChange)
|
||||||
displayed: false
|
displayed: false
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Ecobee Sensor
|
* Copyright 2015 SmartThings
|
||||||
*
|
|
||||||
* Copyright 2015 Juan Risso
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
* 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:
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
@@ -12,6 +10,9 @@
|
|||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
* 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.
|
* for the specific language governing permissions and limitations under the License.
|
||||||
*
|
*
|
||||||
|
* Ecobee Sensor
|
||||||
|
*
|
||||||
|
* Author: SmartThings
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Ecobee Sensor", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Ecobee Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||||
@@ -26,7 +27,16 @@ metadata {
|
|||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
state("temperature", label:'${currentValue}°', unit:"F",
|
state("temperature", label:'${currentValue}°', unit:"F",
|
||||||
backgroundColors:[
|
backgroundColors:[
|
||||||
[value: 31, color: "#153591"],
|
// Celsius
|
||||||
|
[value: 0, color: "#153591"],
|
||||||
|
[value: 7, color: "#1e9cbb"],
|
||||||
|
[value: 15, color: "#90d2a7"],
|
||||||
|
[value: 23, color: "#44b621"],
|
||||||
|
[value: 28, color: "#f1d801"],
|
||||||
|
[value: 35, color: "#d04e00"],
|
||||||
|
[value: 37, color: "#bc2323"],
|
||||||
|
// Fahrenheit
|
||||||
|
[value: 40, color: "#153591"],
|
||||||
[value: 44, color: "#1e9cbb"],
|
[value: 44, color: "#1e9cbb"],
|
||||||
[value: 59, color: "#90d2a7"],
|
[value: 59, color: "#90d2a7"],
|
||||||
[value: 74, color: "#44b621"],
|
[value: 74, color: "#44b621"],
|
||||||
@@ -38,8 +48,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("motion", "device.motion") {
|
standardTile("motion", "device.motion") {
|
||||||
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
|
|
||||||
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
|
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
|
||||||
|
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ def generateModeEvent(mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generateFanModeEvent(fanMode) {
|
def generateFanModeEvent(fanMode) {
|
||||||
sendEvent(name: "thermostatFanMode", value: fanMode, descriptionText: "$device.displayName fan is in ${mode} mode", displayed: true)
|
sendEvent(name: "thermostatFanMode", value: fanMode, descriptionText: "$device.displayName fan is in ${fanMode} mode", displayed: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateOperatingStateEvent(operatingState) {
|
def generateOperatingStateEvent(operatingState) {
|
||||||
@@ -493,7 +493,7 @@ def fanOn() {
|
|||||||
} else {
|
} else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
def currentFanMode = device.currentState("thermostatFanMode")?.value
|
def currentFanMode = device.currentState("thermostatFanMode")?.value
|
||||||
generateModeEvent(currentFanMode) // reset the tile back
|
generateFanModeEvent(currentFanMode) // reset the tile back
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,7 +514,7 @@ def fanAuto() {
|
|||||||
} else {
|
} else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
def currentFanMode = device.currentState("thermostatFanMode")?.value
|
def currentFanMode = device.currentState("thermostatFanMode")?.value
|
||||||
generateModeEvent(currentFanMode) // reset the tile back
|
generateFanModeEvent(currentFanMode) // reset the tile back
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ metadata {
|
|||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
command "setAdjustedColor"
|
command "setAdjustedColor"
|
||||||
command "reset"
|
command "reset"
|
||||||
command "refresh"
|
command "refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -68,17 +68,17 @@ def parse(description) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle commands
|
// handle commands
|
||||||
def on() {
|
void on() {
|
||||||
log.trace parent.on(this)
|
log.trace parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
void off() {
|
||||||
log.trace parent.off(this)
|
log.trace parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
|
|
||||||
def nextLevel() {
|
void nextLevel() {
|
||||||
def level = device.latestValue("level") as Integer ?: 0
|
def level = device.latestValue("level") as Integer ?: 0
|
||||||
if (level <= 100) {
|
if (level <= 100) {
|
||||||
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
|
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
|
||||||
@@ -89,25 +89,25 @@ def nextLevel() {
|
|||||||
setLevel(level)
|
setLevel(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
def setLevel(percent) {
|
void setLevel(percent) {
|
||||||
log.debug "Executing 'setLevel'"
|
log.debug "Executing 'setLevel'"
|
||||||
parent.setLevel(this, percent)
|
parent.setLevel(this, percent)
|
||||||
sendEvent(name: "level", value: percent)
|
sendEvent(name: "level", value: percent)
|
||||||
}
|
}
|
||||||
|
|
||||||
def setSaturation(percent) {
|
void setSaturation(percent) {
|
||||||
log.debug "Executing 'setSaturation'"
|
log.debug "Executing 'setSaturation'"
|
||||||
parent.setSaturation(this, percent)
|
parent.setSaturation(this, percent)
|
||||||
sendEvent(name: "saturation", value: percent)
|
sendEvent(name: "saturation", value: percent)
|
||||||
}
|
}
|
||||||
|
|
||||||
def setHue(percent) {
|
void setHue(percent) {
|
||||||
log.debug "Executing 'setHue'"
|
log.debug "Executing 'setHue'"
|
||||||
parent.setHue(this, percent)
|
parent.setHue(this, percent)
|
||||||
sendEvent(name: "hue", value: percent)
|
sendEvent(name: "hue", value: percent)
|
||||||
}
|
}
|
||||||
|
|
||||||
def setColor(value) {
|
void setColor(value) {
|
||||||
log.debug "setColor: ${value}, $this"
|
log.debug "setColor: ${value}, $this"
|
||||||
parent.setColor(this, value)
|
parent.setColor(this, value)
|
||||||
if (value.hue) { sendEvent(name: "hue", value: value.hue)}
|
if (value.hue) { sendEvent(name: "hue", value: value.hue)}
|
||||||
@@ -117,25 +117,25 @@ def setColor(value) {
|
|||||||
if (value.switch) { sendEvent(name: "switch", value: value.switch)}
|
if (value.switch) { sendEvent(name: "switch", value: value.switch)}
|
||||||
}
|
}
|
||||||
|
|
||||||
def reset() {
|
void reset() {
|
||||||
log.debug "Executing 'reset'"
|
log.debug "Executing 'reset'"
|
||||||
def value = [level:100, hex:"#90C638", saturation:56, hue:23]
|
def value = [level:100, hex:"#90C638", saturation:56, hue:23]
|
||||||
setAdjustedColor(value)
|
setAdjustedColor(value)
|
||||||
parent.poll()
|
parent.poll()
|
||||||
}
|
}
|
||||||
|
|
||||||
def setAdjustedColor(value) {
|
void setAdjustedColor(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
log.trace "setAdjustedColor: ${value}"
|
log.trace "setAdjustedColor: ${value}"
|
||||||
def adjusted = value + [:]
|
def adjusted = value + [:]
|
||||||
adjusted.hue = adjustOutgoingHue(value.hue)
|
adjusted.hue = adjustOutgoingHue(value.hue)
|
||||||
// Needed because color picker always sends 100
|
// Needed because color picker always sends 100
|
||||||
adjusted.level = null
|
adjusted.level = null
|
||||||
setColor(adjusted)
|
setColor(adjusted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
void refresh() {
|
||||||
log.debug "Executing 'refresh'"
|
log.debug "Executing 'refresh'"
|
||||||
parent.manualRefresh()
|
parent.manualRefresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,48 +12,48 @@ metadata {
|
|||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
command "refresh"
|
command "refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
// TODO: define status and reply messages here
|
// TODO: define status and reply messages here
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"rich-control", type: "lighting", canChangeIcon: true){
|
multiAttributeTile(name:"rich-control", type: "lighting", 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:"#79b821", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
|
||||||
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
|
|
||||||
attributeState "level", label: 'Level ${currentValue}%'
|
|
||||||
}
|
}
|
||||||
}
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
|
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
||||||
|
}
|
||||||
|
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
|
||||||
|
attributeState "level", label: 'Level ${currentValue}%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
state "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
|
|
||||||
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
|
|
||||||
state "level", action:"switch level.setLevel"
|
|
||||||
}
|
|
||||||
|
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
|
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
main(["switch"])
|
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
|
||||||
details(["rich-control", "refresh"])
|
state "level", action:"switch level.setLevel"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
|
||||||
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
}
|
||||||
|
|
||||||
|
main(["switch"])
|
||||||
|
details(["rich-control", "refresh"])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
@@ -74,23 +74,23 @@ def parse(description) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle commands
|
// handle commands
|
||||||
def on() {
|
void on() {
|
||||||
parent.on(this)
|
parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
void off() {
|
||||||
parent.off(this)
|
parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
|
|
||||||
def setLevel(percent) {
|
void setLevel(percent) {
|
||||||
log.debug "Executing 'setLevel'"
|
log.debug "Executing 'setLevel'"
|
||||||
parent.setLevel(this, percent)
|
parent.setLevel(this, percent)
|
||||||
sendEvent(name: "level", value: percent)
|
sendEvent(name: "level", value: percent)
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
void refresh() {
|
||||||
log.debug "Executing 'refresh'"
|
log.debug "Executing 'refresh'"
|
||||||
parent.manualRefresh()
|
parent.manualRefresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#==============================================================================
|
||||||
|
# Copyright 2016 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.
|
||||||
|
#==============================================================================
|
||||||
|
# Purpose: Mobile Presence i18n Translation File
|
||||||
|
#
|
||||||
|
# Filename: mobile-presence.src/i18n/messages.properties
|
||||||
|
#
|
||||||
|
# Change History:
|
||||||
|
# 1. 20160205 TW Initial release with informal Korean translation.
|
||||||
|
#==============================================================================
|
||||||
|
# Korean (ko)
|
||||||
|
# Device Preferences
|
||||||
|
'''Give your device a name'''.ko=기기 이름 바꾸기
|
||||||
|
'''Set Device Image'''.ko=디바이스 이미지 설정
|
||||||
|
# Events / Notifications
|
||||||
|
'''{{ linkText }} has left'''.ko={{ linkText }}님이 나갔습니다
|
||||||
|
'''{{ linkText }} has arrived'''.ko={{ linkText }}님이 도착했습니다
|
||||||
|
'''present'''.ko=집안
|
||||||
|
'''not present'''.ko=부재중
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
# Generated on Wed Feb 24 14:28:26 CST 2016 by dylan
|
||||||
|
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
|
||||||
|
'''Degrees'''.ko=온도
|
||||||
|
'''Temperature Offset'''.ko=온도 직접 설정
|
||||||
|
'''This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.'''.ko=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다.
|
||||||
|
'''battery'''.ko=배터리
|
||||||
|
'''dry'''.ko=건조
|
||||||
|
'''wet'''.ko=누수
|
||||||
|
'''{{ device.displayName }} battery has too much power: (> 3.5) volts.'''.ko={{ device.displayName }} 배터리 전력이 너무 높습니다(3.5볼트 초과).
|
||||||
|
'''{{ device.displayName }} battery was {{ value }}'''.ko={{ device.displayName }} 배터리가 {{ value }}였습니다
|
||||||
|
'''{{ device.displayName }} is {{ value | translate }}'''.ko={{ device.displayName }}이(가) {{ value | translate }}입니다
|
||||||
|
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}이(가) {{ value }}°C였습니다
|
||||||
|
'''{{ device.displayName }} was {{ value }}°F'''.ko={{ device.displayName }}이(가) {{ value }}°F였습니다
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
# Generated on Wed Feb 24 14:28:26 CST 2016 by dylan
|
||||||
|
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
|
||||||
|
'''Degrees'''.ko=온도
|
||||||
|
'''Temperature Offset'''.ko=온도 직접 설정
|
||||||
|
'''This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.'''.ko=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다.
|
||||||
|
'''battery'''.ko=배터리
|
||||||
|
'''{{ device.displayName }} battery has too much power: (> 3.5) volts.'''.ko={{ device.displayName }} 배터리 전력이 너무 높습니다(3.5볼트 초과).
|
||||||
|
'''{{ device.displayName }} battery was {{ value }}'''.ko={{ device.displayName }} 배터리가 {{ value }}였습니다
|
||||||
|
'''{{ device.displayName }} detected motion'''.ko={{ device.displayName }}가 움직임을 감지하였습니다.
|
||||||
|
'''{{ device.displayName }} motion has stopped'''.ko={{ device.displayName }} 동작이 중단되었습니다
|
||||||
|
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}이(가) {{ value }}°C였습니다
|
||||||
|
'''{{ device.displayName }} was {{ value }}°F'''.ko={{ device.displayName }}이(가) {{ value }}°F였습니다
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//DEPRECATED - Using the smartsense-motion-sensor.groovy DTH for this device. Users need to be moved before deleting this DTH
|
||||||
|
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "SmartSense Motion/Temp Sensor", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "SmartSense Motion/Temp Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Motion Sensor"
|
capability "Motion Sensor"
|
||||||
@@ -25,10 +27,6 @@ metadata {
|
|||||||
|
|
||||||
command "enrollResponse"
|
command "enrollResponse"
|
||||||
|
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3305-S"
|
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3305"
|
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325"
|
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -233,7 +231,7 @@ private Map getBatteryResult(rawValue) {
|
|||||||
def volts = rawValue / 10
|
def volts = rawValue / 10
|
||||||
def descriptionText
|
def descriptionText
|
||||||
|
|
||||||
if (rawValue == 0) {}
|
if (rawValue == 0 || rawValue == 255) {}
|
||||||
else {
|
else {
|
||||||
if (volts > 3.5) {
|
if (volts > 3.5) {
|
||||||
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
# Generated on Wed Feb 24 14:28:26 CST 2016 by dylan
|
||||||
|
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
|
||||||
|
'''Degrees'''.ko=온도
|
||||||
|
'''Do you want to use this sensor on a garage door?'''.ko=차고 문의 센서 사용 설정하기
|
||||||
|
'''No'''.ko=아니요
|
||||||
|
'''Tap to set'''.ko=눌러서 설정
|
||||||
|
'''Temperature Offset'''.ko=온도 직접 설정
|
||||||
|
'''This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.'''.ko=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다.
|
||||||
|
'''Updating device to garage sensor'''.ko=기기-차고 센서 업데이트 중
|
||||||
|
'''Updating device to open/close sensor'''.ko=기기-열림/닫힘 센서 업데이트 중
|
||||||
|
'''Yes'''.ko=예
|
||||||
|
'''{{ device.displayName }} status was closed'''.ko={{ device.displayName }}은(는) 닫힌 상태입니다
|
||||||
|
'''{{ device.displayName }} status was opened'''.ko={{ device.displayName }}은(는) 열린 상태입니다
|
||||||
|
'''{{ device.displayName }} was active'''.ko={{ device.displayName }}이(가) 활성화되었습니다
|
||||||
|
'''{{ device.displayName }} was closed'''.ko={{ device.displayName }}이(가) 닫혔습니다
|
||||||
|
'''{{ device.displayName }} was inactive'''.ko={{ device.displayName }}이(가) 비활성화되었습니다
|
||||||
|
'''{{ device.displayName }} was opened'''.ko={{ device.displayName }}이(가) 열렸습니다
|
||||||
|
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}이(가) {{ value }}°C였습니다
|
||||||
|
'''{{ device.displayName }} was {{ value }}°F'''.ko={{ device.displayName }}이(가) {{ value }}°F였습니다
|
||||||
@@ -72,15 +72,12 @@ metadata {
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
valueTile("3axis", "device.threeAxis", decoration: "flat", wordWrap: false, width: 2, height: 2) {
|
|
||||||
state("threeAxis", label:'${currentValue}', unit:"", backgroundColor:"#ffffff")
|
|
||||||
}
|
|
||||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
}
|
}
|
||||||
|
|
||||||
main(["contact", "acceleration", "temperature"])
|
main(["contact", "acceleration", "temperature"])
|
||||||
details(["contact", "acceleration", "temperature", "3axis", "battery"])
|
details(["contact", "acceleration", "temperature", "battery"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
* for the specific language governing permissions and limitations under the License.
|
* for the specific language governing permissions and limitations under the License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
//DEPRECATED - Using the smartsense-multi-sensor.groovy DTH for this device. Users need to be moved before deleting this DTH
|
||||||
|
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "SmartSense Open/Closed Accelerometer Sensor", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "SmartSense Open/Closed Accelerometer Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||||
@@ -23,8 +24,7 @@
|
|||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
command "enrollResponse"
|
command "enrollResponse"
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320"
|
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -225,7 +225,8 @@ def getTemperature(value) {
|
|||||||
|
|
||||||
def volts = rawValue / 10
|
def volts = rawValue / 10
|
||||||
def descriptionText
|
def descriptionText
|
||||||
if (volts > 3.5) {
|
if (rawValue == 0 || rawValue == 255) {}
|
||||||
|
else if (volts > 3.5) {
|
||||||
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -220,7 +220,8 @@ private Map getBatteryResult(rawValue) {
|
|||||||
|
|
||||||
def volts = rawValue / 10
|
def volts = rawValue / 10
|
||||||
def descriptionText
|
def descriptionText
|
||||||
if (volts > 3.5) {
|
if (rawValue == 0 || rawValue == 255) {}
|
||||||
|
else if (volts > 3.5) {
|
||||||
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -196,7 +196,8 @@ private Map getBatteryResult(rawValue) {
|
|||||||
|
|
||||||
def volts = rawValue / 10
|
def volts = rawValue / 10
|
||||||
def descriptionText
|
def descriptionText
|
||||||
if (volts > 3.5) {
|
if (rawValue == 0 || rawValue == 255) {}
|
||||||
|
else if (volts > 3.5) {
|
||||||
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ metadata {
|
|||||||
attributeState "power", label:'${currentValue} W'
|
attributeState "power", label:'${currentValue} W'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
main "switch"
|
main "switch"
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ metadata {
|
|||||||
attributeState "level", action:"switch level.setLevel"
|
attributeState "level", action:"switch level.setLevel"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
main "switch"
|
main "switch"
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ metadata {
|
|||||||
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
controlTile("rgbSelector", "device.color", "color", height: 3, width: 3, inactiveLabel: false) {
|
controlTile("rgbSelector", "device.color", "color", height: 3, width: 3, inactiveLabel: false) {
|
||||||
|
|||||||
@@ -23,22 +23,14 @@
|
|||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
|
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019",
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_5", deviceJoinName: "Kwikset 5-Button Deadbolt"
|
||||||
manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_5", deviceJoinName: "Kwikset 5-Button Deadbolt"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_LEVER_5", deviceJoinName: "Kwikset 5-Button Lever"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019",
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10", deviceJoinName: "Kwikset 10-Button Deadbolt"
|
||||||
manufacturer: "Kwikset", model: "SMARTCODE_LEVER_5", deviceJoinName: "Kwikset 5-Button Lever"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10T", deviceJoinName: "Kwikset 10-Button Touch Deadbolt"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019",
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL220 TS LL", deviceJoinName: "Yale Touch Screen Lever Lock"
|
||||||
manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10", deviceJoinName: "Kwikset 10-Button Deadbolt"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019",
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
|
||||||
manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10T", deviceJoinName: "Kwikset 10-Button Touch Deadbolt"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019",
|
|
||||||
manufacturer: "Yale", model: "YRL220 TS LL", deviceJoinName: "Yale Touch Screen Lever Lock"
|
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019",
|
|
||||||
manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock"
|
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019",
|
|
||||||
manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
|
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019",
|
|
||||||
manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
@@ -60,7 +52,7 @@
|
|||||||
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("refresh", "device.lock", inactiveLabel:false, decoration:"flat", width:2, height:2) {
|
standardTile("refresh", "device.refresh", inactiveLabel:false, decoration:"flat", width:2, height:2) {
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ metadata {
|
|||||||
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "colorTemperature", label: '${currentValue} K'
|
state "colorTemperature", label: '${currentValue} K'
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ metadata {
|
|||||||
attributeState "power", label:'${currentValue} W'
|
attributeState "power", label:'${currentValue} W'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
main "switch"
|
main "switch"
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ metadata {
|
|||||||
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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
main "switch"
|
main "switch"
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,322 +1,322 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2015 SmartThings
|
* Copyright 2015 SmartThings
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
* 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:
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* 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
|
* 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
|
* 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.
|
* for the specific language governing permissions and limitations under the License.
|
||||||
*
|
*
|
||||||
* Button Controller
|
* Button Controller
|
||||||
*
|
*
|
||||||
* Author: SmartThings
|
* Author: SmartThings
|
||||||
* Date: 2014-5-21
|
* Date: 2014-5-21
|
||||||
*/
|
*/
|
||||||
definition(
|
definition(
|
||||||
name: "Button Controller",
|
name: "Button Controller",
|
||||||
namespace: "smartthings",
|
namespace: "smartthings",
|
||||||
author: "SmartThings",
|
author: "SmartThings",
|
||||||
description: "Control devices with buttons like the Aeon Labs Minimote",
|
description: "Control devices with buttons like the Aeon Labs Minimote",
|
||||||
category: "Convenience",
|
category: "Convenience",
|
||||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/MyApps/Cat-MyApps.png",
|
iconUrl: "https://s3.amazonaws.com/smartapp-icons/MyApps/Cat-MyApps.png",
|
||||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/MyApps/Cat-MyApps@2x.png"
|
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/MyApps/Cat-MyApps@2x.png"
|
||||||
)
|
)
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
page(name: "selectButton")
|
page(name: "selectButton")
|
||||||
page(name: "configureButton1")
|
page(name: "configureButton1")
|
||||||
page(name: "configureButton2")
|
page(name: "configureButton2")
|
||||||
page(name: "configureButton3")
|
page(name: "configureButton3")
|
||||||
page(name: "configureButton4")
|
page(name: "configureButton4")
|
||||||
|
|
||||||
page(name: "timeIntervalInput", title: "Only during a certain time") {
|
page(name: "timeIntervalInput", title: "Only during a certain time") {
|
||||||
section {
|
section {
|
||||||
input "starting", "time", title: "Starting", required: false
|
input "starting", "time", title: "Starting", required: false
|
||||||
input "ending", "time", title: "Ending", required: false
|
input "ending", "time", title: "Ending", required: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def selectButton() {
|
def selectButton() {
|
||||||
dynamicPage(name: "selectButton", title: "First, select your button device", nextPage: "configureButton1", uninstall: configured()) {
|
dynamicPage(name: "selectButton", title: "First, select your button device", nextPage: "configureButton1", uninstall: configured()) {
|
||||||
section {
|
section {
|
||||||
input "buttonDevice", "capability.button", title: "Button", multiple: false, required: true
|
input "buttonDevice", "capability.button", title: "Button", multiple: false, required: true
|
||||||
}
|
}
|
||||||
|
|
||||||
section(title: "More options", hidden: hideOptionsSection(), hideable: true) {
|
section(title: "More options", hidden: hideOptionsSection(), hideable: true) {
|
||||||
|
|
||||||
def timeLabel = timeIntervalLabel()
|
def timeLabel = timeIntervalLabel()
|
||||||
|
|
||||||
href "timeIntervalInput", title: "Only during a certain time", description: timeLabel ?: "Tap to set", state: timeLabel ? "complete" : null
|
href "timeIntervalInput", title: "Only during a certain time", description: timeLabel ?: "Tap to set", state: timeLabel ? "complete" : null
|
||||||
|
|
||||||
input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
|
input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
|
||||||
options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
||||||
|
|
||||||
input "modes", "mode", title: "Only when mode is", multiple: true, required: false
|
input "modes", "mode", title: "Only when mode is", multiple: true, required: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def configureButton1() {
|
def configureButton1() {
|
||||||
dynamicPage(name: "configureButton1", title: "Now let's decide how to use the first button",
|
dynamicPage(name: "configureButton1", title: "Now let's decide how to use the first button",
|
||||||
nextPage: "configureButton2", uninstall: configured(), getButtonSections(1))
|
nextPage: "configureButton2", uninstall: configured(), getButtonSections(1))
|
||||||
}
|
}
|
||||||
def configureButton2() {
|
def configureButton2() {
|
||||||
dynamicPage(name: "configureButton2", title: "If you have a second button, set it up here",
|
dynamicPage(name: "configureButton2", title: "If you have a second button, set it up here",
|
||||||
nextPage: "configureButton3", uninstall: configured(), getButtonSections(2))
|
nextPage: "configureButton3", uninstall: configured(), getButtonSections(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
def configureButton3() {
|
def configureButton3() {
|
||||||
dynamicPage(name: "configureButton3", title: "If you have a third button, you can do even more here",
|
dynamicPage(name: "configureButton3", title: "If you have a third button, you can do even more here",
|
||||||
nextPage: "configureButton4", uninstall: configured(), getButtonSections(3))
|
nextPage: "configureButton4", uninstall: configured(), getButtonSections(3))
|
||||||
}
|
}
|
||||||
def configureButton4() {
|
def configureButton4() {
|
||||||
dynamicPage(name: "configureButton4", title: "If you have a fourth button, you rule, and can set it up here",
|
dynamicPage(name: "configureButton4", title: "If you have a fourth button, you rule, and can set it up here",
|
||||||
install: true, uninstall: true, getButtonSections(4))
|
install: true, uninstall: true, getButtonSections(4))
|
||||||
}
|
}
|
||||||
|
|
||||||
def getButtonSections(buttonNumber) {
|
def getButtonSections(buttonNumber) {
|
||||||
return {
|
return {
|
||||||
section("Lights") {
|
section("Lights") {
|
||||||
input "lights_${buttonNumber}_pushed", "capability.switch", title: "Pushed", multiple: true, required: false
|
input "lights_${buttonNumber}_pushed", "capability.switch", title: "Pushed", multiple: true, required: false
|
||||||
input "lights_${buttonNumber}_held", "capability.switch", title: "Held", multiple: true, required: false
|
input "lights_${buttonNumber}_held", "capability.switch", title: "Held", multiple: true, required: false
|
||||||
}
|
}
|
||||||
section("Locks") {
|
section("Locks") {
|
||||||
input "locks_${buttonNumber}_pushed", "capability.lock", title: "Pushed", multiple: true, required: false
|
input "locks_${buttonNumber}_pushed", "capability.lock", title: "Pushed", multiple: true, required: false
|
||||||
input "locks_${buttonNumber}_held", "capability.lock", title: "Held", multiple: true, required: false
|
input "locks_${buttonNumber}_held", "capability.lock", title: "Held", multiple: true, required: false
|
||||||
}
|
}
|
||||||
section("Sonos") {
|
section("Sonos") {
|
||||||
input "sonos_${buttonNumber}_pushed", "capability.musicPlayer", title: "Pushed", multiple: true, required: false
|
input "sonos_${buttonNumber}_pushed", "capability.musicPlayer", title: "Pushed", multiple: true, required: false
|
||||||
input "sonos_${buttonNumber}_held", "capability.musicPlayer", title: "Held", multiple: true, required: false
|
input "sonos_${buttonNumber}_held", "capability.musicPlayer", title: "Held", multiple: true, required: false
|
||||||
}
|
}
|
||||||
section("Modes") {
|
section("Modes") {
|
||||||
input "mode_${buttonNumber}_pushed", "mode", title: "Pushed", required: false
|
input "mode_${buttonNumber}_pushed", "mode", title: "Pushed", required: false
|
||||||
input "mode_${buttonNumber}_held", "mode", title: "Held", required: false
|
input "mode_${buttonNumber}_held", "mode", title: "Held", required: false
|
||||||
}
|
}
|
||||||
def phrases = location.helloHome?.getPhrases()*.label
|
def phrases = location.helloHome?.getPhrases()*.label
|
||||||
if (phrases) {
|
if (phrases) {
|
||||||
section("Hello Home Actions") {
|
section("Hello Home Actions") {
|
||||||
log.trace phrases
|
log.trace phrases
|
||||||
input "phrase_${buttonNumber}_pushed", "enum", title: "Pushed", required: false, options: phrases
|
input "phrase_${buttonNumber}_pushed", "enum", title: "Pushed", required: false, options: phrases
|
||||||
input "phrase_${buttonNumber}_held", "enum", title: "Held", required: false, options: phrases
|
input "phrase_${buttonNumber}_held", "enum", title: "Held", required: false, options: phrases
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
section("Sirens") {
|
section("Sirens") {
|
||||||
input "sirens_${buttonNumber}_pushed","capability.alarm" ,title: "Pushed", multiple: true, required: false
|
input "sirens_${buttonNumber}_pushed","capability.alarm" ,title: "Pushed", multiple: true, required: false
|
||||||
input "sirens_${buttonNumber}_held", "capability.alarm", title: "Held", multiple: true, required: false
|
input "sirens_${buttonNumber}_held", "capability.alarm", title: "Held", multiple: true, required: false
|
||||||
}
|
}
|
||||||
|
|
||||||
section("Custom Message") {
|
section("Custom Message") {
|
||||||
input "textMessage_${buttonNumber}", "text", title: "Message", required: false
|
input "textMessage_${buttonNumber}", "text", title: "Message", required: false
|
||||||
}
|
}
|
||||||
|
|
||||||
section("Push Notifications") {
|
section("Push Notifications") {
|
||||||
input "notifications_${buttonNumber}_pushed","bool" ,title: "Pushed", required: false, defaultValue: false
|
input "notifications_${buttonNumber}_pushed","bool" ,title: "Pushed", required: false, defaultValue: false
|
||||||
input "notifications_${buttonNumber}_held", "bool", title: "Held", required: false, defaultValue: false
|
input "notifications_${buttonNumber}_held", "bool", title: "Held", required: false, defaultValue: false
|
||||||
}
|
}
|
||||||
|
|
||||||
section("Sms Notifications") {
|
section("Sms Notifications") {
|
||||||
input "phone_${buttonNumber}_pushed","phone" ,title: "Pushed", required: false
|
input "phone_${buttonNumber}_pushed","phone" ,title: "Pushed", required: false
|
||||||
input "phone_${buttonNumber}_held", "phone", title: "Held", required: false
|
input "phone_${buttonNumber}_held", "phone", title: "Held", required: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def installed() {
|
def installed() {
|
||||||
initialize()
|
initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
initialize()
|
initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
def initialize() {
|
def initialize() {
|
||||||
subscribe(buttonDevice, "button", buttonEvent)
|
subscribe(buttonDevice, "button", buttonEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
def configured() {
|
def configured() {
|
||||||
return buttonDevice || buttonConfigured(1) || buttonConfigured(2) || buttonConfigured(3) || buttonConfigured(4)
|
return buttonDevice || buttonConfigured(1) || buttonConfigured(2) || buttonConfigured(3) || buttonConfigured(4)
|
||||||
}
|
}
|
||||||
|
|
||||||
def buttonConfigured(idx) {
|
def buttonConfigured(idx) {
|
||||||
return settings["lights_$idx_pushed"] ||
|
return settings["lights_$idx_pushed"] ||
|
||||||
settings["locks_$idx_pushed"] ||
|
settings["locks_$idx_pushed"] ||
|
||||||
settings["sonos_$idx_pushed"] ||
|
settings["sonos_$idx_pushed"] ||
|
||||||
settings["mode_$idx_pushed"] ||
|
settings["mode_$idx_pushed"] ||
|
||||||
settings["notifications_$idx_pushed"] ||
|
settings["notifications_$idx_pushed"] ||
|
||||||
settings["sirens_$idx_pushed"] ||
|
settings["sirens_$idx_pushed"] ||
|
||||||
settings["notifications_$idx_pushed"] ||
|
settings["notifications_$idx_pushed"] ||
|
||||||
settings["phone_$idx_pushed"]
|
settings["phone_$idx_pushed"]
|
||||||
}
|
}
|
||||||
|
|
||||||
def buttonEvent(evt){
|
def buttonEvent(evt){
|
||||||
if(allOk) {
|
if(allOk) {
|
||||||
def buttonNumber = evt.data // why doesn't jsonData work? always returning [:]
|
def buttonNumber = evt.data // why doesn't jsonData work? always returning [:]
|
||||||
def value = evt.value
|
def value = evt.value
|
||||||
log.debug "buttonEvent: $evt.name = $evt.value ($evt.data)"
|
log.debug "buttonEvent: $evt.name = $evt.value ($evt.data)"
|
||||||
log.debug "button: $buttonNumber, value: $value"
|
log.debug "button: $buttonNumber, value: $value"
|
||||||
|
|
||||||
def recentEvents = buttonDevice.eventsSince(new Date(now() - 3000)).findAll{it.value == evt.value && it.data == evt.data}
|
def recentEvents = buttonDevice.eventsSince(new Date(now() - 3000)).findAll{it.value == evt.value && it.data == evt.data}
|
||||||
log.debug "Found ${recentEvents.size()?:0} events in past 3 seconds"
|
log.debug "Found ${recentEvents.size()?:0} events in past 3 seconds"
|
||||||
|
|
||||||
if(recentEvents.size <= 1){
|
if(recentEvents.size <= 1){
|
||||||
switch(buttonNumber) {
|
switch(buttonNumber) {
|
||||||
case ~/.*1.*/:
|
case ~/.*1.*/:
|
||||||
executeHandlers(1, value)
|
executeHandlers(1, value)
|
||||||
break
|
break
|
||||||
case ~/.*2.*/:
|
case ~/.*2.*/:
|
||||||
executeHandlers(2, value)
|
executeHandlers(2, value)
|
||||||
break
|
break
|
||||||
case ~/.*3.*/:
|
case ~/.*3.*/:
|
||||||
executeHandlers(3, value)
|
executeHandlers(3, value)
|
||||||
break
|
break
|
||||||
case ~/.*4.*/:
|
case ~/.*4.*/:
|
||||||
executeHandlers(4, value)
|
executeHandlers(4, value)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug "Found recent button press events for $buttonNumber with value $value"
|
log.debug "Found recent button press events for $buttonNumber with value $value"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def executeHandlers(buttonNumber, value) {
|
def executeHandlers(buttonNumber, value) {
|
||||||
log.debug "executeHandlers: $buttonNumber - $value"
|
log.debug "executeHandlers: $buttonNumber - $value"
|
||||||
|
|
||||||
def lights = find('lights', buttonNumber, value)
|
def lights = find('lights', buttonNumber, value)
|
||||||
if (lights != null) toggle(lights)
|
if (lights != null) toggle(lights)
|
||||||
|
|
||||||
def locks = find('locks', buttonNumber, value)
|
def locks = find('locks', buttonNumber, value)
|
||||||
if (locks != null) toggle(locks)
|
if (locks != null) toggle(locks)
|
||||||
|
|
||||||
def sonos = find('sonos', buttonNumber, value)
|
def sonos = find('sonos', buttonNumber, value)
|
||||||
if (sonos != null) toggle(sonos)
|
if (sonos != null) toggle(sonos)
|
||||||
|
|
||||||
def mode = find('mode', buttonNumber, value)
|
def mode = find('mode', buttonNumber, value)
|
||||||
if (mode != null) changeMode(mode)
|
if (mode != null) changeMode(mode)
|
||||||
|
|
||||||
def phrase = find('phrase', buttonNumber, value)
|
def phrase = find('phrase', buttonNumber, value)
|
||||||
if (phrase != null) location.helloHome.execute(phrase)
|
if (phrase != null) location.helloHome.execute(phrase)
|
||||||
|
|
||||||
def textMessage = findMsg('textMessage', buttonNumber)
|
def textMessage = findMsg('textMessage', buttonNumber)
|
||||||
|
|
||||||
def notifications = find('notifications', buttonNumber, value)
|
def notifications = find('notifications', buttonNumber, value)
|
||||||
if (notifications?.toBoolean()) sendPush(textMessage ?: "Button $buttonNumber was pressed" )
|
if (notifications?.toBoolean()) sendPush(textMessage ?: "Button $buttonNumber was pressed" )
|
||||||
|
|
||||||
def phone = find('phone', buttonNumber, value)
|
def phone = find('phone', buttonNumber, value)
|
||||||
if (phone != null) sendSms(phone, textMessage ?:"Button $buttonNumber was pressed")
|
if (phone != null) sendSms(phone, textMessage ?:"Button $buttonNumber was pressed")
|
||||||
|
|
||||||
def sirens = find('sirens', buttonNumber, value)
|
def sirens = find('sirens', buttonNumber, value)
|
||||||
if (sirens != null) toggle(sirens)
|
if (sirens != null) toggle(sirens)
|
||||||
}
|
}
|
||||||
|
|
||||||
def find(type, buttonNumber, value) {
|
def find(type, buttonNumber, value) {
|
||||||
def preferenceName = type + "_" + buttonNumber + "_" + value
|
def preferenceName = type + "_" + buttonNumber + "_" + value
|
||||||
def pref = settings[preferenceName]
|
def pref = settings[preferenceName]
|
||||||
if(pref != null) {
|
if(pref != null) {
|
||||||
log.debug "Found: $pref for $preferenceName"
|
log.debug "Found: $pref for $preferenceName"
|
||||||
}
|
}
|
||||||
|
|
||||||
return pref
|
return pref
|
||||||
}
|
}
|
||||||
|
|
||||||
def findMsg(type, buttonNumber) {
|
def findMsg(type, buttonNumber) {
|
||||||
def preferenceName = type + "_" + buttonNumber
|
def preferenceName = type + "_" + buttonNumber
|
||||||
def pref = settings[preferenceName]
|
def pref = settings[preferenceName]
|
||||||
if(pref != null) {
|
if(pref != null) {
|
||||||
log.debug "Found: $pref for $preferenceName"
|
log.debug "Found: $pref for $preferenceName"
|
||||||
}
|
}
|
||||||
|
|
||||||
return pref
|
return pref
|
||||||
}
|
}
|
||||||
|
|
||||||
def toggle(devices) {
|
def toggle(devices) {
|
||||||
log.debug "toggle: $devices = ${devices*.currentValue('switch')}"
|
log.debug "toggle: $devices = ${devices*.currentValue('switch')}"
|
||||||
|
|
||||||
if (devices*.currentValue('switch').contains('on')) {
|
if (devices*.currentValue('switch').contains('on')) {
|
||||||
devices.off()
|
devices.off()
|
||||||
}
|
}
|
||||||
else if (devices*.currentValue('switch').contains('off')) {
|
else if (devices*.currentValue('switch').contains('off')) {
|
||||||
devices.on()
|
devices.on()
|
||||||
}
|
}
|
||||||
else if (devices*.currentValue('lock').contains('locked')) {
|
else if (devices*.currentValue('lock').contains('locked')) {
|
||||||
devices.unlock()
|
devices.unlock()
|
||||||
}
|
}
|
||||||
else if (devices*.currentValue('lock').contains('unlocked')) {
|
else if (devices*.currentValue('lock').contains('unlocked')) {
|
||||||
devices.lock()
|
devices.lock()
|
||||||
}
|
}
|
||||||
else if (devices*.currentValue('alarm').contains('off')) {
|
else if (devices*.currentValue('alarm').contains('off')) {
|
||||||
devices.siren()
|
devices.siren()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
devices.on()
|
devices.on()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def changeMode(mode) {
|
def changeMode(mode) {
|
||||||
log.debug "changeMode: $mode, location.mode = $location.mode, location.modes = $location.modes"
|
log.debug "changeMode: $mode, location.mode = $location.mode, location.modes = $location.modes"
|
||||||
|
|
||||||
if (location.mode != mode && location.modes?.find { it.name == mode }) {
|
if (location.mode != mode && location.modes?.find { it.name == mode }) {
|
||||||
setLocationMode(mode)
|
setLocationMode(mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// execution filter methods
|
// execution filter methods
|
||||||
private getAllOk() {
|
private getAllOk() {
|
||||||
modeOk && daysOk && timeOk
|
modeOk && daysOk && timeOk
|
||||||
}
|
}
|
||||||
|
|
||||||
private getModeOk() {
|
private getModeOk() {
|
||||||
def result = !modes || modes.contains(location.mode)
|
def result = !modes || modes.contains(location.mode)
|
||||||
log.trace "modeOk = $result"
|
log.trace "modeOk = $result"
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDaysOk() {
|
private getDaysOk() {
|
||||||
def result = true
|
def result = true
|
||||||
if (days) {
|
if (days) {
|
||||||
def df = new java.text.SimpleDateFormat("EEEE")
|
def df = new java.text.SimpleDateFormat("EEEE")
|
||||||
if (location.timeZone) {
|
if (location.timeZone) {
|
||||||
df.setTimeZone(location.timeZone)
|
df.setTimeZone(location.timeZone)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
|
df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
|
||||||
}
|
}
|
||||||
def day = df.format(new Date())
|
def day = df.format(new Date())
|
||||||
result = days.contains(day)
|
result = days.contains(day)
|
||||||
}
|
}
|
||||||
log.trace "daysOk = $result"
|
log.trace "daysOk = $result"
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTimeOk() {
|
private getTimeOk() {
|
||||||
def result = true
|
def result = true
|
||||||
if (starting && ending) {
|
if (starting && ending) {
|
||||||
def currTime = now()
|
def currTime = now()
|
||||||
def start = timeToday(starting).time
|
def start = timeToday(starting).time
|
||||||
def stop = timeToday(ending).time
|
def stop = timeToday(ending).time
|
||||||
result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
|
result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
|
||||||
}
|
}
|
||||||
log.trace "timeOk = $result"
|
log.trace "timeOk = $result"
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
private hhmm(time, fmt = "h:mm a")
|
private hhmm(time, fmt = "h:mm a")
|
||||||
{
|
{
|
||||||
def t = timeToday(time, location.timeZone)
|
def t = timeToday(time, location.timeZone)
|
||||||
def f = new java.text.SimpleDateFormat(fmt)
|
def f = new java.text.SimpleDateFormat(fmt)
|
||||||
f.setTimeZone(location.timeZone ?: timeZone(time))
|
f.setTimeZone(location.timeZone ?: timeZone(time))
|
||||||
f.format(t)
|
f.format(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
private hideOptionsSection() {
|
private hideOptionsSection() {
|
||||||
(starting || ending || days || modes) ? false : true
|
(starting || ending || days || modes) ? false : true
|
||||||
}
|
}
|
||||||
|
|
||||||
private timeIntervalLabel() {
|
private timeIntervalLabel() {
|
||||||
(starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
|
(starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ def connectionStatus(message, redirectUrl = null) {
|
|||||||
|
|
||||||
def getEcobeeThermostats() {
|
def getEcobeeThermostats() {
|
||||||
log.debug "getting device list"
|
log.debug "getting device list"
|
||||||
|
atomicState.remoteSensors = []
|
||||||
|
|
||||||
def requestBody = '{"selection":{"selectionType":"registered","selectionMatch":"","includeRuntime":true,"includeSensors":true}}'
|
def requestBody = '{"selection":{"selectionType":"registered","selectionMatch":"","includeRuntime":true,"includeSensors":true}}'
|
||||||
|
|
||||||
@@ -251,7 +252,7 @@ def getEcobeeThermostats() {
|
|||||||
|
|
||||||
if (resp.status == 200) {
|
if (resp.status == 200) {
|
||||||
resp.data.thermostatList.each { stat ->
|
resp.data.thermostatList.each { stat ->
|
||||||
atomicState.remoteSensors = stat.remoteSensors
|
atomicState.remoteSensors = atomicState.remoteSensors == null ? stat.remoteSensors : atomicState.remoteSensors << stat.remoteSensors
|
||||||
def dni = [app.id, stat.identifier].join('.')
|
def dni = [app.id, stat.identifier].join('.')
|
||||||
stats[dni] = getThermostatDisplayName(stat)
|
stats[dni] = getThermostatDisplayName(stat)
|
||||||
}
|
}
|
||||||
@@ -273,11 +274,14 @@ def getEcobeeThermostats() {
|
|||||||
|
|
||||||
Map sensorsDiscovered() {
|
Map sensorsDiscovered() {
|
||||||
def map = [:]
|
def map = [:]
|
||||||
atomicState.remoteSensors.each {
|
log.info "list ${atomicState.remoteSensors}"
|
||||||
if (it.type != "thermostat") {
|
atomicState.remoteSensors.each { sensors ->
|
||||||
def value = "${it?.name}"
|
sensors.each {
|
||||||
def key = "ecobee_sensor-"+ it?.id + "-" + it?.code
|
if (it.type != "thermostat") {
|
||||||
map["${key}"] = value
|
def value = "${it?.name}"
|
||||||
|
def key = "ecobee_sensor-"+ it?.id + "-" + it?.code
|
||||||
|
map["${key}"] = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
atomicState.sensors = map
|
atomicState.sensors = map
|
||||||
@@ -541,10 +545,15 @@ def updateSensorData() {
|
|||||||
def occupancy = ""
|
def occupancy = ""
|
||||||
it.capability.each {
|
it.capability.each {
|
||||||
if (it.type == "temperature") {
|
if (it.type == "temperature") {
|
||||||
if (location.temperatureScale == "F") {
|
if (it.value == "unknown") {
|
||||||
temperature = Math.round(it.value.toDouble() / 10)
|
temperature = "--"
|
||||||
} else {
|
} else {
|
||||||
temperature = convertFtoC(it.value.toDouble() / 10)
|
if (location.temperatureScale == "F") {
|
||||||
|
temperature = Math.round(it.value.toDouble() / 10)
|
||||||
|
} else {
|
||||||
|
temperature = convertFtoC(it.value.toDouble() / 10)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (it.type == "occupancy") {
|
} else if (it.type == "occupancy") {
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ def locationHandler(evt) {
|
|||||||
log.error "/description.xml returned a bridge that didn't exist"
|
log.error "/description.xml returned a bridge that didn't exist"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(headerString?.contains("json")) {
|
} else if(headerString?.contains("json") && isValidSource(parsedEvent.mac)) {
|
||||||
log.trace "description.xml response (application/json)"
|
log.trace "description.xml response (application/json)"
|
||||||
def body = new groovy.json.JsonSlurper().parseText(parsedEvent.body)
|
def body = new groovy.json.JsonSlurper().parseText(parsedEvent.body)
|
||||||
if (body.success != null) {
|
if (body.success != null) {
|
||||||
@@ -494,6 +494,11 @@ def doDeviceSync(){
|
|||||||
discoverBridges()
|
discoverBridges()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def isValidSource(macAddress) {
|
||||||
|
def vbridges = getVerifiedHueBridges()
|
||||||
|
return (vbridges?.find {"${it.value.mac}" == macAddress}) != null
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
//CHILD DEVICE METHODS
|
//CHILD DEVICE METHODS
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
|
|||||||
Reference in New Issue
Block a user