mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-24 05:04:10 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fba8ea199a |
@@ -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,5 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2015 SmartThings
|
* Ecobee Sensor
|
||||||
|
*
|
||||||
|
* 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:
|
||||||
@@ -10,9 +12,6 @@
|
|||||||
* 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") {
|
||||||
@@ -27,16 +26,7 @@ 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:[
|
||||||
// Celsius
|
[value: 31, color: "#153591"],
|
||||||
[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"],
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ def generateModeEvent(mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generateFanModeEvent(fanMode) {
|
def generateFanModeEvent(fanMode) {
|
||||||
sendEvent(name: "thermostatFanMode", value: fanMode, descriptionText: "$device.displayName fan is in ${fanMode} mode", displayed: true)
|
sendEvent(name: "thermostatFanMode", value: fanMode, descriptionText: "$device.displayName fan is in ${mode} 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
|
||||||
generateFanModeEvent(currentFanMode) // reset the tile back
|
generateModeEvent(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
|
||||||
generateFanModeEvent(currentFanMode) // reset the tile back
|
generateModeEvent(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
|
||||||
void on() {
|
def on() {
|
||||||
log.trace parent.on(this)
|
log.trace parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
|
|
||||||
void off() {
|
def off() {
|
||||||
log.trace parent.off(this)
|
log.trace parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
|
|
||||||
void nextLevel() {
|
def 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 @@ void nextLevel() {
|
|||||||
setLevel(level)
|
setLevel(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLevel(percent) {
|
def 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSaturation(percent) {
|
def 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHue(percent) {
|
def 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
void setColor(value) {
|
def 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 @@ void setColor(value) {
|
|||||||
if (value.switch) { sendEvent(name: "switch", value: value.switch)}
|
if (value.switch) { sendEvent(name: "switch", value: value.switch)}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
def 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAdjustedColor(value) {
|
def 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void refresh() {
|
def 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"
|
||||||
|
}
|
||||||
|
|
||||||
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
|
main(["switch"])
|
||||||
state "level", action:"switch level.setLevel"
|
details(["rich-control", "refresh"])
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
void on() {
|
def on() {
|
||||||
parent.on(this)
|
parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
|
|
||||||
void off() {
|
def off() {
|
||||||
parent.off(this)
|
parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLevel(percent) {
|
def 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
void refresh() {
|
def refresh() {
|
||||||
log.debug "Executing 'refresh'"
|
log.debug "Executing 'refresh'"
|
||||||
parent.manualRefresh()
|
parent.manualRefresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
#==============================================================================
|
|
||||||
# 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=부재중
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
# 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였습니다
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
|
|
||||||
# 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였습니다
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
|
|
||||||
# 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,12 +72,15 @@ 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", "battery"])
|
details(["contact", "acceleration", "temperature", "3axis", "battery"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,14 +23,22 @@
|
|||||||
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", 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",
|
||||||
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"
|
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_DEADBOLT_10", deviceJoinName: "Kwikset 10-Button 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,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10T", deviceJoinName: "Kwikset 10-Button Touch Deadbolt"
|
manufacturer: "Kwikset", model: "SMARTCODE_LEVER_5", deviceJoinName: "Kwikset 5-Button Lever"
|
||||||
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,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: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt 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: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen 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: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever 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: "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) {
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
/**
|
|
||||||
* Controlled Power Off
|
|
||||||
*
|
|
||||||
* Copyright 2016 Andrew Crow
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
definition(
|
|
||||||
name: "Controlled Power Off",
|
|
||||||
namespace: "acrow311",
|
|
||||||
author: "Andrew Crow",
|
|
||||||
description: "Application used to power off devices that should be allowed to finish their cycle before being shut down such as air conditions and tankless water heaters. Application will monitor electric usage and delay shutdown until usage has returned to inactive state.",
|
|
||||||
category: "My Apps",
|
|
||||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
|
||||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
|
|
||||||
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
|
|
||||||
oauth: true)
|
|
||||||
|
|
||||||
|
|
||||||
preferences {
|
|
||||||
section("Shutdown when device not active") {
|
|
||||||
input(name: "meter", type: "capability.powerMeter", title: "When This Power Meter...", required: true, multiple: false, description: null)
|
|
||||||
input(name: "threshold", type: "number", title: "Reports Below...", required: true, description: "In watts, enter integer value")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def installed() {
|
|
||||||
log.debug "Installed with settings: ${settings}"
|
|
||||||
initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
def updated() {
|
|
||||||
log.debug "Updated with settings: ${settings}"
|
|
||||||
initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
def initialize() {
|
|
||||||
unsubscribe()
|
|
||||||
subscribe(meter, "power", meterHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
def meterHandler(evt) {
|
|
||||||
def meterValue = evt.value as double
|
|
||||||
def thresholdValue = threshold as int
|
|
||||||
def switchState = meter.currentValue("switch") == "on" // Get current switch status (on = true)
|
|
||||||
|
|
||||||
if (switchState) { // If the switch is already off, do nothing
|
|
||||||
if (meterValue < thresholdValue) { // If the power consumption is low enough, turn off switch
|
|
||||||
log.info "${meter} reported energy ${meterValue} below ${threshold}. Turning off switch."
|
|
||||||
sendNotificationEvent("${meter} not running, shutting down.")
|
|
||||||
meter.off()
|
|
||||||
} else { // Power consumption too high - device connected to switch in use - do not shutdown.
|
|
||||||
sendNotificationEvent("Power consumption too high to shut off ${meter}. Attempting again in a moment.")
|
|
||||||
log.info "${meter} reported energy ${meterValue} above ${threshold}. Leaving switch on."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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,7 +235,6 @@ 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}}'
|
||||||
|
|
||||||
@@ -252,7 +251,7 @@ def getEcobeeThermostats() {
|
|||||||
|
|
||||||
if (resp.status == 200) {
|
if (resp.status == 200) {
|
||||||
resp.data.thermostatList.each { stat ->
|
resp.data.thermostatList.each { stat ->
|
||||||
atomicState.remoteSensors = atomicState.remoteSensors == null ? stat.remoteSensors : atomicState.remoteSensors << 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)
|
||||||
}
|
}
|
||||||
@@ -274,14 +273,11 @@ def getEcobeeThermostats() {
|
|||||||
|
|
||||||
Map sensorsDiscovered() {
|
Map sensorsDiscovered() {
|
||||||
def map = [:]
|
def map = [:]
|
||||||
log.info "list ${atomicState.remoteSensors}"
|
atomicState.remoteSensors.each {
|
||||||
atomicState.remoteSensors.each { sensors ->
|
if (it.type != "thermostat") {
|
||||||
sensors.each {
|
def value = "${it?.name}"
|
||||||
if (it.type != "thermostat") {
|
def key = "ecobee_sensor-"+ it?.id + "-" + it?.code
|
||||||
def value = "${it?.name}"
|
map["${key}"] = value
|
||||||
def key = "ecobee_sensor-"+ it?.id + "-" + it?.code
|
|
||||||
map["${key}"] = value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
atomicState.sensors = map
|
atomicState.sensors = map
|
||||||
|
|||||||
@@ -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") && isValidSource(parsedEvent.mac)) {
|
} else if(headerString?.contains("json")) {
|
||||||
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,11 +494,6 @@ 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