Compare commits

..

5 Commits

Author SHA1 Message Date
Vinay Rao
024a6cb698 Merge pull request #632 from SmartThingsCommunity/staging
Rolling up changes to production from staging 2016-03-17 Release
2016-03-18 10:43:22 -07:00
Vinay Rao
62a965d90b Merge pull request #599 from SmartThingsCommunity/staging
Rolling up changes to production from staging 2016-03-10 Release
2016-03-10 16:26:26 -08:00
Vinay Rao
515b268374 Merge pull request #549 from SmartThingsCommunity/staging
Rolling up changes to production from staging 2016-02-25 Release
2016-02-26 10:51:42 -08:00
Vinay Rao
a103d437c2 Merge pull request #523 from SmartThingsCommunity/staging
Deploy to production 2/18
2016-02-18 09:28:02 -08:00
Vinay Rao
bdd88deb99 Merge pull request #504 from SmartThingsCommunity/staging
Merging changes from staging to production
2016-02-11 22:40:38 -08:00
24 changed files with 357 additions and 762 deletions

View File

@@ -52,9 +52,6 @@ hipchatShareFile {
hipchatSendNotification { hipchatSendNotification {
String branch = project.hasProperty('branch') ? project.property('branch') : 'unknown' String branch = project.hasProperty('branch') ? project.property('branch') : 'unknown'
message = "Began executable deploy of SmartThingsPublic(${branch})." message = "Began executable deploy of SmartThingsPublic(${branch})."
if (branch == 'master') {
message += ' (dev shards)'
}
color = branch == 'master' ? 'yellow' : 'red' color = branch == 'master' ? 'yellow' : 'red'
notify = true notify = true
} }

View File

@@ -11,17 +11,6 @@
* for the specific language governing permissions and limitations under the License. * for the specific language governing permissions and limitations under the License.
* *
*/ */
/*
* Purpose: Arrival Sensor HA DTH File
*
* Filename: Arrival-Sensor-HA.src/Arrival-Sensor-HA.groovy
*
* Change History:
* 1. 20160115 TW - Update/Edit to support i18n translations
* 2. 20160121 TW - Update to V4 battery calcs, added pref's page title translations
*/
metadata { metadata {
definition (name: "Arrival Sensor HA", namespace: "smartthings", author: "SmartThings") { definition (name: "Arrival Sensor HA", namespace: "smartthings", author: "SmartThings") {
capability "Tone" capability "Tone"
@@ -43,7 +32,7 @@ metadata {
]) ])
} }
section { section {
input "checkInterval", "enum", title: "Presence timeout (minutes)", description: "Tap to set", input "checkInterval", "enum", title: "Presence timeout (minutes)",
defaultValue:"2", options: ["2", "3", "5"], displayDuringSetup: false defaultValue:"2", options: ["2", "3", "5"], displayDuringSetup: false
} }
} }
@@ -93,6 +82,7 @@ def parse(String description) {
private handleReportAttributeMessage(String description) { private handleReportAttributeMessage(String description) {
def descMap = zigbee.parseDescriptionAsMap(description) def descMap = zigbee.parseDescriptionAsMap(description)
if (descMap.clusterInt == 0x0001 && descMap.attrInt == 0x0020) { if (descMap.clusterInt == 0x0001 && descMap.attrInt == 0x0020) {
handleBatteryEvent(Integer.parseInt(descMap.value, 16)) handleBatteryEvent(Integer.parseInt(descMap.value, 16))
} }
@@ -104,7 +94,6 @@ private handleReportAttributeMessage(String description) {
* @param volts Battery voltage in .1V increments * @param volts Battery voltage in .1V increments
*/ */
private handleBatteryEvent(volts) { private handleBatteryEvent(volts) {
def descriptionText
if (volts == 0 || volts == 255) { if (volts == 0 || volts == 255) {
log.debug "Ignoring invalid value for voltage (${volts/10}V)" log.debug "Ignoring invalid value for voltage (${volts/10}V)"
} }
@@ -118,17 +107,15 @@ private handleBatteryEvent(volts) {
volts = minVolts volts = minVolts
else if (volts > maxVolts) else if (volts > maxVolts)
volts = maxVolts volts = maxVolts
def value = batteryMap[volts] def pct = batteryMap[volts]
if (value != null) { if (pct != null) {
def linkText = getLinkText(device) def linkText = getLinkText(device)
descriptionText = '{{ linkText }} battery was {{ value }}'
def eventMap = [ def eventMap = [
name: 'battery', name: 'battery',
value: value, value: pct,
descriptionText: descriptionText, descriptionText: "${linkText} battery was ${pct}%"
translatable: true
] ]
log.debug "Creating battery event for voltage=${volts/10}V: ${linkText} ${eventMap.name} is ${eventMap.value}%" log.debug "Creating battery event for voltage=${volts/10}V: ${eventMap}"
sendEvent(eventMap) sendEvent(eventMap)
} }
} }
@@ -144,19 +131,13 @@ private handlePresenceEvent(present) {
stopTimer() stopTimer()
} }
def linkText = getLinkText(device) def linkText = getLinkText(device)
def descriptionText
if ( present )
descriptionText = "{{ linkText }} has arrived"
else
descriptionText = "{{ linkText }} has left"
def eventMap = [ def eventMap = [
name: "presence", name: "presence",
value: present ? "present" : "not present", value: present ? "present" : "not present",
linkText: linkText, linkText: linkText,
descriptionText: descriptionText, descriptionText: "${linkText} has ${present ? 'arrived' : 'left'}",
translatable: true
] ]
log.debug "Creating presence event: ${device.displayName} ${eventMap.name} is ${eventMap.value}" log.debug "Creating presence event: ${eventMap}"
sendEvent(eventMap) sendEvent(eventMap)
} }
@@ -177,4 +158,4 @@ def checkPresenceCallback() {
if (timeSinceLastCheckin >= theCheckInterval) { if (timeSinceLastCheckin >= theCheckInterval) {
handlePresenceEvent(false) handlePresenceEvent(false)
} }
} }

View File

@@ -1,35 +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: Arrival Sensor HA i18n Translation File
#
# Filename: Arrival-Sensor-HA.src/i18n/messages.properties
#
# Change History:
# 1. 20160115 TW Initial release with informal Korean translation.
# 2. 20160121 TW Added def preference section titles.
#==============================================================================
# Korean (ko)
# Device Preferences
'''Give your device a name'''.ko=기기 이름 바꾸기
'''Set Device Image'''.ko=기기 이미지 설정
'''Presence timeout (minutes)'''.ko=시간 초과. 스마트폰 위치 정보
'''Tap to set'''.ko=눌러서 설정
'''Arrival Sensor'''.ko=도착알림 센서
# Events / Notifications
'''{{ linkText }} battery was {{ value }}'''.ko={{ linkText }}남아있는 배터리는 {{ value }}입니다.
'''{{ linkText }} has arrived'''.ko={{ linkText }}집에 도착했습니다.
'''{{ linkText }} has left'''.ko={{ linkText }}집을 나갔습니다.
#==============================================================================

View File

@@ -20,6 +20,7 @@ metadata {
capability "Temperature Measurement" capability "Temperature Measurement"
capability "Motion Sensor" capability "Motion Sensor"
capability "Refresh" capability "Refresh"
capability "Polling"
} }
tiles { tiles {
@@ -67,6 +68,6 @@ def refresh() {
void poll() { void poll() {
log.debug "Executing 'poll' using parent SmartApp" log.debug "Executing 'poll' using parent SmartApp"
parent.pollChild() parent.pollChild(this)
} }

View File

@@ -20,6 +20,7 @@ metadata {
capability "Actuator" capability "Actuator"
capability "Thermostat" capability "Thermostat"
capability "Temperature Measurement" capability "Temperature Measurement"
capability "Polling"
capability "Sensor" capability "Sensor"
capability "Refresh" capability "Refresh"
capability "Relative Humidity Measurement" capability "Relative Humidity Measurement"
@@ -133,7 +134,9 @@ def refresh() {
void poll() { void poll() {
log.debug "Executing 'poll' using parent SmartApp" log.debug "Executing 'poll' using parent SmartApp"
parent.pollChild()
def results = parent.pollChild(this)
generateEvent(results) //parse received message from parent
} }
def generateEvent(Map results) { def generateEvent(Map results) {
@@ -379,16 +382,12 @@ def getDataByName(String name) {
state[name] ?: device.getDataValue(name) state[name] ?: device.getDataValue(name)
} }
def setThermostatMode(String mode) { def setThermostatMode(String value) {
log.debug "setThermostatMode($mode)" log.debug "setThermostatMode({$value})"
mode = mode.toLowerCase()
switchToMode(mode)
} }
def setThermostatFanMode(String mode) { def setThermostatFanMode(String value) {
log.debug "setThermostatFanMode($mode)" log.debug "setThermostatFanMode({$value})"
mode = mode.toLowerCase()
switchToFanMode(mode)
} }
def generateModeEvent(mode) { def generateModeEvent(mode) {

View File

@@ -18,10 +18,9 @@ metadata {
capability "Sensor" capability "Sensor"
capability "Smoke Detector" //attributes: smoke ("detected","clear","tested") capability "Smoke Detector" //attributes: smoke ("detected","clear","tested")
capability "Temperature Measurement" //attributes: temperature capability "Temperature Measurement" //attributes: temperature
attribute "tamper", "enum", ["active", "inactive"]//capability "Tamper Alert"// <- yields "java.lang.RuntimeException: Metadata Error: Capability 'Tamper Alert' not found" error attribute "tamper", "enum", ["detected", "clear"]
attribute "heatAlarm", "enum", ["overheat", "inactive"] attribute "heatAlarm", "enum", ["overheat detected", "clear", "rapid temperature rise", "underheat detected"]
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x9C, 0x98, 0x7A", outClusters: "0x20, 0x8B" fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x9C, 0x98, 0x7A", outClusters: "0x20, 0x8B"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x9C, 0x98, 0x7A"
} }
simulator { simulator {
//battery //battery
@@ -51,7 +50,7 @@ metadata {
input description: "Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings", input description: "Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings",
title: "Advanced Configuration", displayDuringSetup: true, type: "paragraph", element: "paragraph" title: "Advanced Configuration", displayDuringSetup: true, type: "paragraph", element: "paragraph"
input "smokeSensorSensitivity", "enum", title: "Smoke Sensor Sensitivity", options: ["High","Medium","Low"], defaultValue: "${smokeSensorSensitivity}", displayDuringSetup: true input "smokeSensorSensitivity", "enum", title: "Smoke Sensor Sensitivity", options: ["High","Medium","Low"], defaultValue: "${smokeSensorSensitivity}", displayDuringSetup: true
input "zwaveNotificationStatus", "enum", title: "Notifications Status", options: ["disabled","casing opened","exceeding temperature threshold","all notifications"], input "zwaveNotificationStatus", "enum", title: "Notifications Status", options: ["disabled","casing opened","exceeding temperature threshold", "lack of Z-Wave range", "all notifications"],
defaultValue: "${zwaveNotificationStatus}", displayDuringSetup: true defaultValue: "${zwaveNotificationStatus}", displayDuringSetup: true
input "visualIndicatorNotificationStatus", "enum", title: "Visual Indicator Notifications Status", input "visualIndicatorNotificationStatus", "enum", title: "Visual Indicator Notifications Status",
options: ["disabled","casing opened","exceeding temperature threshold", "lack of Z-Wave range", "all notifications"], options: ["disabled","casing opened","exceeding temperature threshold", "lack of Z-Wave range", "all notifications"],
@@ -62,47 +61,44 @@ metadata {
input "temperatureReportInterval", "enum", title: "Temperature Report Interval", input "temperatureReportInterval", "enum", title: "Temperature Report Interval",
options: ["reports inactive", "5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${temperatureReportInterval}", displayDuringSetup: true options: ["reports inactive", "5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${temperatureReportInterval}", displayDuringSetup: true
input "temperatureReportHysteresis", "number", title: "Temperature Report Hysteresis", description: "Available settings: 1-100 C", range: "1..100", displayDuringSetup: true input "temperatureReportHysteresis", "number", title: "Temperature Report Hysteresis", description: "Available settings: 1-100 C", range: "1..100", displayDuringSetup: true
input "temperatureThreshold", "number", title: "Overheat Temperature Threshold", description: "Available settings: 1-100 C", range: "1..100", displayDuringSetup: true input "temperatureThreshold", "number", title: "Overheat Temperature Threshold", description: "Available settings: 0 or 2-100 C", range: "0..100", displayDuringSetup: true
input "excessTemperatureSignalingInterval", "enum", title: "Excess Temperature Signaling Interval", input "excessTemperatureSignalingInterval", "enum", title: "Excess Temperature Signaling Interval",
options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${excessTemperatureSignalingInterval}", displayDuringSetup: true options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${excessTemperatureSignalingInterval}", displayDuringSetup: true
input "lackOfZwaveRangeIndicationInterval", "enum", title: "Lack of Z-Wave Range Indication Interval", input "lackOfZwaveRangeIndicationInterval", "enum", title: "Lack of Z-Wave Range Indication Interval",
options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${lackOfZwaveRangeIndicationInterval}", displayDuringSetup: true options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${lackOfZwaveRangeIndicationInterval}", displayDuringSetup: true
} }
tiles (scale: 2){ tiles (scale: 2){
multiAttributeTile(name:"FGSD", type: "lighting", width: 6, height: 4){ multiAttributeTile(name:"smoke", type: "lighting", width: 6, height: 4){
tileAttribute ("device.smoke", key: "PRIMARY_CONTROL") { tileAttribute ("device.smoke", key: "PRIMARY_CONTROL") {
attributeState("clear", label:"CLEAR", icon:"st.alarm.smoke.clear", backgroundColor:"#ffffff") attributeState("clear", label:"CLEAR", icon:"st.alarm.smoke.clear", backgroundColor:"#ffffff")
attributeState("detected", label:"SMOKE", icon:"st.alarm.smoke.smoke", backgroundColor:"#e86d13") attributeState("detected", label:"SMOKE", icon:"st.alarm.smoke.smoke", backgroundColor:"#e86d13")
attributeState("tested", label:"TEST", icon:"st.alarm.smoke.test", backgroundColor:"#e86d13") attributeState("tested", label:"TEST", icon:"st.alarm.smoke.test", backgroundColor:"#e86d13")
attributeState("replacement required", label:"REPLACE", icon:"st.alarm.smoke.test", backgroundColor:"#FFFF66")
attributeState("unknown", label:"UNKNOWN", icon:"st.alarm.smoke.test", backgroundColor:"#ffffff") attributeState("unknown", label:"UNKNOWN", icon:"st.alarm.smoke.test", backgroundColor:"#ffffff")
} }
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") { tileAttribute ("device.battery", key: "SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0") attributeState "battery", label:'Battery: ${currentValue}%', unit:"%"
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff") }
}
} }
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:"%"
} }
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) { valueTile("temperature", "device.temperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "temperature", label:'${currentValue}°', state "temperature", label:'${currentValue}°', unit:"C"
backgroundColors:[ }
[value: 31, color: "#153591"], valueTile("heatAlarm", "device.heatAlarm", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
[value: 44, color: "#1e9cbb"], state "clear", label:'TEMPERATURE OK', backgroundColor:"#ffffff"
[value: 59, color: "#90d2a7"], state "overheat detected", label:'OVERHEAT DETECTED', backgroundColor:"#ffffff"
[value: 74, color: "#44b621"], state "rapid temperature rise", label:'RAPID TEMP RISE', backgroundColor:"#ffffff"
[value: 84, color: "#f1d801"], state "underheat detected", label:'UNDERHEAT DETECTED', backgroundColor:"#ffffff"
[value: 95, color: "#d04e00"], }
[value: 96, color: "#bc2323"] valueTile("tamper", "device.tamper", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
] state "clear", label:'NO TAMPER', backgroundColor:"#ffffff"
} state "detected", label:'TAMPER DETECTED', backgroundColor:"#ffffff"
valueTile("heatAlarm", "device.heatAlarm", inactiveLabel: false, width: 2, height: 2) {
state "inactive", label:'TEMPERATURE OK', backgroundColor:"#ffffff"
state "overheat", label:'OVERHEAT DETECTED', backgroundColor:"#bc2323"
} }
main "FGSD" main "smoke"
details(["FGSD","temperature", "battery", "heatAlarm"]) details(["smoke","temperature"])
} }
} }
@@ -121,7 +117,7 @@ def parse(String description) {
"If you are unable to control it via SmartThings, you must remove it from your network and add it again.") "If you are unable to control it via SmartThings, you must remove it from your network and add it again.")
} else if (description != "updated") { } else if (description != "updated") {
log.debug "parse() >> zwave.parse(description)" log.debug "parse() >> zwave.parse(description)"
def cmd = zwave.parse(description, [0x31: 5, 0x5A: 1, 0x71: 3, 0x72: 2, 0x84: 1, 0x86: 1, 0x8B: 1, 0x9C: 1]) def cmd = zwave.parse(description, [0x31: 5, 0x71: 3, 0x84: 1])
if (cmd) { if (cmd) {
result = zwaveEvent(cmd) result = zwaveEvent(cmd)
} }
@@ -130,41 +126,15 @@ def parse(String description) {
return result return result
} }
//security
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
setSecured()
def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x5A: 1, 0x71: 3, 0x84: 1, 0x9C: 1])
if (encapsulatedCommand) {
log.debug "command: 98 (Security) 81(SecurityMessageEncapsulation) encapsulatedCommand: $encapsulatedCommand"
zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
//crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
def versions = [0x31: 5, 0x72: 2, 0x86: 1, 0x8B: 1]
def version = versions[cmd.commandClass as Integer]
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
if (!encapsulatedCommand) {
log.debug "Could not extract command from $cmd"
} else {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
log.info "Executing zwaveEvent 86 (VersionV1): 12 (VersionReport) with cmd: $cmd" log.info "Executing zwaveEvent 86 (VersionV1): 12 (VersionReport) with cmd: $cmd"
def version = "${cmd.applicationVersion}.${cmd.applicationSubVersion}" def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}"
updateDataValue("version", fw) updateDataValue("fw", fw)
def text = "$device.displayName: firmware version: $version, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}" def text = "$device.displayName: firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}"
createEvent(descriptionText: text, isStateChange: false) createEvent(descriptionText: text, isStateChange: false)
} }
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ] def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) { if (cmd.batteryLevel == 0xFF) {
@@ -191,6 +161,18 @@ def zwaveEvent(physicalgraph.zwave.commands.applicationstatusv1.ApplicationRejec
createEvent(displayed: true, descriptionText: "$device.displayName rejected the last request") createEvent(displayed: true, descriptionText: "$device.displayName rejected the last request")
} }
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
setSecured()
def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x71: 3, 0x84: 1])
if (encapsulatedCommand) {
log.debug "command: 98 (Security) 81(SecurityMessageEncapsulation) encapsulatedCommand: $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) { def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
log.info "Executing zwaveEvent 98 (SecurityV1): 03 (SecurityCommandsSupportedReport) with cmd: $cmd" log.info "Executing zwaveEvent 98 (SecurityV1): 03 (SecurityCommandsSupportedReport) with cmd: $cmd"
setSecured() setSecured()
@@ -217,31 +199,18 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm
if (cmd.notificationType == 7) { if (cmd.notificationType == 7) {
switch (cmd.event) { switch (cmd.event) {
case 0: case 0:
result << createEvent(name: "tamper", value: "inactive", displayed: false) result << createEvent(name: "tamper", value: "clear", displayed: false)
break break
case 3: case 3:
result << createEvent(name: "tamper", value: "active", descriptionText: "$device.displayName casing was opened") result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName casing was opened")
break break
} }
} else if (cmd.notificationType == 1) { //Smoke Alarm (V2) } else if (cmd.notificationType == 1) { //Smoke Alarm (V2)
log.debug "notificationv3.NotificationReport: for Smoke Alarm (V2)" log.debug "notificationv3.NotificationReport: for Smoke Alarm (V2)"
result << smokeAlarmEvent(cmd.event) result << smokeAlarmEvent(cmd.event)
} else if (cmd.notificationType == 4) { // Heat Alarm (V2) } else if (cmd.notificationType == 4) { // Heat Alarm (V2)
log.debug "notificationv3.NotificationReport: for Heat Alarm (V2)" log.debug "notificationv3.NotificationReport: for Heat Alarm (V2)"
result << heatAlarmEvent(cmd.event) result << heatAlarmEvent(cmd.event)
} else if (cmd.notificationType == 8) {
if (cmd.event == 0x0A) {
def map = [:]
map.name = "battery"
map.value = 1
map.unit = "%"
map.displayed = true
result << createEvent(map)
}
} else if (cmd.notificationType == 9) {
if (cmd.event == 0x01) {
result << createEvent(descriptionText: "Warning: $device.displayName system hardware failure", isStateChange: true)
}
} else { } else {
log.warn "Need to handle this cmd.notificationType: ${cmd.notificationType}" log.warn "Need to handle this cmd.notificationType: ${cmd.notificationType}"
result << createEvent(descriptionText: cmd.toString(), isStateChange: false) result << createEvent(descriptionText: cmd.toString(), isStateChange: false)
@@ -252,7 +221,7 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm
def smokeAlarmEvent(value) { def smokeAlarmEvent(value) {
log.debug "smokeAlarmEvent(value): $value" log.debug "smokeAlarmEvent(value): $value"
def map = [name: "smoke"] def map = [name: "smoke"]
if (value == 2) { if (value == 1 || value == 2) {
map.value = "detected" map.value = "detected"
map.descriptionText = "$device.displayName detected smoke" map.descriptionText = "$device.displayName detected smoke"
} else if (value == 0) { } else if (value == 0) {
@@ -261,6 +230,9 @@ def smokeAlarmEvent(value) {
} else if (value == 3) { } else if (value == 3) {
map.value = "tested" map.value = "tested"
map.descriptionText = "$device.displayName smoke alarm test" map.descriptionText = "$device.displayName smoke alarm test"
} else if (value == 4) {
map.value = "replacement required"
map.descriptionText = "$device.displayName replacement required"
} else { } else {
map.value = "unknown" map.value = "unknown"
map.descriptionText = "$device.displayName unknown event" map.descriptionText = "$device.displayName unknown event"
@@ -271,12 +243,18 @@ def smokeAlarmEvent(value) {
def heatAlarmEvent(value) { def heatAlarmEvent(value) {
log.debug "heatAlarmEvent(value): $value" log.debug "heatAlarmEvent(value): $value"
def map = [name: "heatAlarm"] def map = [name: "heatAlarm"]
if (value == 2) { if (value == 1 || value == 2) {
map.value = "overheat" map.value = "overheat detected"
map.descriptionText = "$device.displayName overheat detected" map.descriptionText = "$device.displayName overheat detected"
} else if (value == 0) { } else if (value == 0) {
map.value = "inactive" map.value = "clear"
map.descriptionText = "$device.displayName heat alarm cleared (no overheat)" map.descriptionText = "$device.displayName heat alarm cleared (no overheat)"
} else if (value == 3 || value == 4) {
map.value = "rapid temperature rise"
map.descriptionText = "$device.displayName rapid temperature rise"
} else if (value == 5 || value == 6) {
map.value = "underheat detected"
map.descriptionText = "$device.displayName underheat detected"
} else { } else {
map.value = "unknown" map.value = "unknown"
map.descriptionText = "$device.displayName unknown event" map.descriptionText = "$device.displayName unknown event"
@@ -296,14 +274,12 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
//Only ask for battery if we haven't had a BatteryReport in a while //Only ask for battery if we haven't had a BatteryReport in a while
if (!state.lastbatt || (new Date().time) - state.lastbatt > 24*60*60*1000) { if (!state.lastbatt || (new Date().time) - state.lastbatt > 24*60*60*1000) {
log.debug("Device has been configured sending >> batteryGet()") log.debug("Device has been configured sending >> batteryGet()")
cmds << zwave.batteryV1.batteryGet() cmds << zwave.securityV1.securityMessageEncapsulation().encapsulate(zwave.batteryV1.batteryGet()).format()
cmds << "delay 1200"
} }
cmds << zwave.sensorAlarmV1.sensorAlarmGet(sensorType: 0)
cmds << zwave.sensorAlarmV1.sensorAlarmGet(sensorType: 1)
cmds << zwave.sensorAlarmV1.sensorAlarmGet(sensorType: 4)
log.debug("Device has been configured sending >> wakeUpNoMoreInformation()") log.debug("Device has been configured sending >> wakeUpNoMoreInformation()")
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation() cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
result << response(commands(cmds,500)) //tell device back to sleep result << response(cmds) //tell device back to sleep
} }
result result
} }
@@ -341,26 +317,8 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
log.debug "After device is securely joined, send commands to update tiles" log.debug "After device is securely joined, send commands to update tiles"
result << zwave.batteryV1.batteryGet() result << zwave.batteryV1.batteryGet()
result << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) result << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01)
//always send wakeUpNoMoreInformation as secure (at this point "secured" property is not set) result << zwave.wakeUpV1.wakeUpNoMoreInformation()
[[descriptionText:"${device.displayName} MSR report"], response(commands(result, 500) << "delay 1000" << secure(zwave.wakeUpV1.wakeUpNoMoreInformation()))] [[descriptionText:"${device.displayName} MSR report"], response(commands(result, 5000))]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
} }
def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) {
@@ -374,37 +332,6 @@ def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd)
result result
} }
def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd) {
def map = [:]
switch (cmd.sensorType) {
case 0:
map.name = "tamper"
map.value = cmd.sensorState == 0xFF ? "active" : "inactive"
map.descriptionText = cmd.sensorState == 0xFF ? "$device.displayName casing was opened" : ""
break
case 1:
map.name = "smoke"
map.value = cmd.sensorState == 0xFF ? "detected" : "clear"
map.descriptionText = cmd.sensorState == 0xFF ? "$device.displayName detected smoke" : "$device.displayName is clear (no smoke)"
break
case 4:
map.name = "heatAlarm"
map.value = cmd.sensorState == 0xFF ? "overheat" : "inactive"
map.descriptionText = cmd.sensorState == 0xFF ? "$device.displayName overheat detected" : "$device.displayName heat alarm cleared (no overheat)"
break
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.timeparametersv1.TimeParametersGet cmd) {
log.info "Executing zwaveEvent 8B (TimeParametersV1) : 02 (TimeParametersGet) with cmd: $cmd"
def nowCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
//Time Parameters are requested by an un-encapsulated frame
response(zwave.timeParametersV1.timeParametersReport(year: nowCal.get(Calendar.YEAR), month: (nowCal.get(Calendar.MONTH) + 1), day: nowCal.get(Calendar.DAY_OF_MONTH),
hourUtc: nowCal.get(Calendar.HOUR_OF_DAY), minuteUtc: nowCal.get(Calendar.MINUTE), secondUtc: nowCal.get(Calendar.SECOND)).format())
}
def zwaveEvent(physicalgraph.zwave.Command cmd) { def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.warn "General zwaveEvent cmd: ${cmd}" log.warn "General zwaveEvent cmd: ${cmd}"
createEvent(descriptionText: cmd.toString(), isStateChange: false) createEvent(descriptionText: cmd.toString(), isStateChange: false)
@@ -433,7 +360,7 @@ def configure() {
} }
//3. Z-Wave notification status: 0-all disabled (default), 1-casing open enabled, 2-exceeding temp enable //3. Z-Wave notification status: 0-all disabled (default), 1-casing open enabled, 2-exceeding temp enable
if (zwaveNotificationStatus && zwaveNotificationStatus != "null"){ if (zwaveNotificationStatus && zwaveNotificationStatus != "null"){
request += zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: zwaveNotificationOptionValueMap[zwaveNotificationStatus] ?: 0) request += zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: notificationOptionValueMap[zwaveNotificationStatus] ?: 0)
} }
//4. Visual indicator notification status: 0-all disabled (default), 1-casing open enabled, 2-exceeding temp enable, 4-lack of range notification //4. Visual indicator notification status: 0-all disabled (default), 1-casing open enabled, 2-exceeding temp enable, 4-lack of range notification
if (visualIndicatorNotificationStatus && visualIndicatorNotificationStatus != "null") { if (visualIndicatorNotificationStatus && visualIndicatorNotificationStatus != "null") {
@@ -475,16 +402,7 @@ def configure() {
//12. get temperature reading from device //12. get temperature reading from device
request += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) request += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01)
//13. set association group commands(request) + ["delay 10000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
request += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId])
//14. get version
request += zwave.versionV1.versionGet()
//15. get serial number
request += zwave.manufacturerSpecificV2.deviceSpecificGet()
commands(request) + ["delay 1000", command(zwave.wakeUpV1.wakeUpNoMoreInformation())]
} }
} }
@@ -500,42 +418,24 @@ private def getTimeOptionValueMap() { [
"reports inactive" : 0, "reports inactive" : 0,
]} ]}
private def getZwaveNotificationOptionValueMap() { [
"disabled" : 0,
"casing opened" : 1,
"exceeding temperature threshold" : 2,
"all notifications" : 3
]}
private def getNotificationOptionValueMap() { [ private def getNotificationOptionValueMap() { [
"disabled" : 0, "disabled" : 0,
"casing opened" : 1, "casing opened" : 1,
"exceeding temperature threshold" : 2, "exceeding temperature threshold" : 2,
"lack of Z-Wave range" : 4, "lack of Z-Wave range" : 4,
"all notifications" : 7 "all notifications" : 7,
]} ]}
private command(physicalgraph.zwave.Command cmd) { private command(physicalgraph.zwave.Command cmd) {
def secureClasses = [0x20, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C] if (isSecured()) {
if (isSecured() && secureClasses.find{ it == cmd.commandClassId }) {
log.info "Sending secured command: ${cmd}" log.info "Sending secured command: ${cmd}"
secure(cmd) zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
} else { } else {
log.info "Sending unsecured command: ${cmd}" log.info "Sending unsecured command: ${cmd}"
crc16(cmd) cmd.format()
} }
} }
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16encapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
}
private commands(commands, delay=200) { private commands(commands, delay=200) {
log.info "inside commands: ${commands}" log.info "inside commands: ${commands}"
delayBetween(commands.collect{ command(it) }, delay) delayBetween(commands.collect{ command(it) }, delay)
@@ -552,4 +452,4 @@ private setSecured() {
} }
private isSecured() { private isSecured() {
getDataValue("secured") == "true" getDataValue("secured") == "true"
} }

View File

@@ -3,7 +3,6 @@
* *
* Author: SmartThings * Author: SmartThings
*/ */
// for the UI // for the UI
metadata { metadata {
// Automatically generated. Make future change here. // Automatically generated. Make future change here.
@@ -28,10 +27,10 @@ metadata {
tiles (scale: 2){ tiles (scale: 2){
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){ multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", 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:"#C6C7CC", 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:"#00A0DC", 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:"#C6C7CC", nextState:"turningOn" attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
} }
tileAttribute ("device.level", key: "SLIDER_CONTROL") { tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)" attributeState "level", action:"switch level.setLevel", range:"(0..100)"
@@ -44,10 +43,16 @@ metadata {
} }
} }
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 "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 "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
}
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2000..6500)") { controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2000..6500)") {
state "colorTemperature", action:"color temperature.setColorTemperature" state "colorTemperature", action:"color temperature.setColorTemperature"
} }
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'
} }
@@ -55,12 +60,29 @@ metadata {
standardTile("reset", "device.reset", height: 2, width: 2, inactiveLabel: false, decoration: "flat") { standardTile("reset", "device.reset", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single" state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single"
} }
standardTile("refresh", "device.switch", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
} }
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
state "level", action:"switch level.setLevel"
}
valueTile("level", "device.level", inactiveLabel: false, decoration: "flat") {
state "level", label: 'Level ${currentValue}%'
}
controlTile("saturationSliderControl", "device.saturation", "slider", height: 1, width: 2, inactiveLabel: false) {
state "saturation", action:"color control.setSaturation"
}
valueTile("saturation", "device.saturation", inactiveLabel: false, decoration: "flat") {
state "saturation", label: 'Sat ${currentValue} '
}
controlTile("hueSliderControl", "device.hue", "slider", height: 1, width: 2, inactiveLabel: false) {
state "hue", action:"color control.setHue"
}
valueTile("hue", "device.hue", inactiveLabel: false, decoration: "flat") {
state "hue", label: 'Hue ${currentValue} '
}
main(["rich-control"]) main(["switch"])
details(["rich-control", "colorTempSliderControl", "colorTemp", "reset", "refresh"]) details(["rich-control", "colorTempSliderControl", "colorTemp", "reset", "refresh"])
} }
} }
@@ -105,34 +127,34 @@ void nextLevel() {
void 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, descriptionText: "Level has changed to ${percent}%") sendEvent(name: "level", value: percent)
} }
void 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, displayed: false) sendEvent(name: "saturation", value: percent)
} }
void 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, displayed: false) sendEvent(name: "hue", value: percent)
} }
void 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, displayed: false)} if (value.hue) { sendEvent(name: "hue", value: value.hue)}
if (value.saturation) { sendEvent(name: "saturation", value: value.saturation, displayed: false)} if (value.saturation) { sendEvent(name: "saturation", value: value.saturation)}
if (value.hex) { sendEvent(name: "color", value: value.hex)} if (value.hex) { sendEvent(name: "color", value: value.hex)}
if (value.level) { sendEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")} if (value.level) { sendEvent(name: "level", value: value.level)}
sendEvent(name: "switch", value: "on") if (value.switch) { sendEvent(name: "switch", value: value.switch)}
} }
void reset() { void reset() {
log.debug "Executing 'reset'" log.debug "Executing 'reset'"
def value = [level:100, saturation:56, hue:23] def value = [level:100, hex:"#90C638", saturation:56, hue:23]
setAdjustedColor(value) setAdjustedColor(value)
parent.poll() parent.poll()
} }

View File

@@ -36,6 +36,13 @@ metadata {
} }
} }
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 "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 "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)") { controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
state "level", action:"switch level.setLevel" state "level", action:"switch level.setLevel"
} }
@@ -44,7 +51,7 @@ metadata {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
} }
main(["rich-control"]) main(["switch"])
details(["rich-control", "refresh"]) details(["rich-control", "refresh"])
} }
} }

View File

@@ -19,14 +19,13 @@
# #
# Change History: # Change History:
# 1. 20160205 TW Initial release with informal Korean translation. # 1. 20160205 TW Initial release with informal Korean translation.
# 2. 20160224 TW Updated with formal Korean translation.
#============================================================================== #==============================================================================
# Korean (ko) # Korean (ko)
# Device Preferences # Device Preferences
'''Give your device a name'''.ko=기기 이름 바꾸기 '''Give your device a name'''.ko=기기 이름 바꾸기
'''Set Device Image'''.ko=기기 이미지 설정 '''Set Device Image'''.ko=디바이스 이미지 설정
# Events / Notifications # Events / Notifications
'''{{ linkText }} has left'''.ko={{ linkText }}집을 나갔습니다. '''{{ linkText }} has left'''.ko={{ linkText }}님이 나갔습니다
'''{{ linkText }} has arrived'''.ko={{ linkText }}집에 도착했습니다. '''{{ linkText }} has arrived'''.ko={{ linkText }}님이 도착했습니다
'''present'''.ko=집안 '''present'''.ko=집안
'''not present'''.ko=외출 '''not present'''.ko=부재중

View File

@@ -1,28 +1,16 @@
/* /**
=============================================================================== * Copyright 2015 SmartThings
* Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* use this file except in compliance with the License. You may obtain a copy * in compliance with the License. You may obtain a copy of the License at:
* 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 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * for the specific language governing permissions and limitations under the License.
* License for the specific language governing permissions and limitations
* under the License.
===============================================================================
* Purpose: Mobile Presence DTH File
* *
* Filename: mobile-presence.src/mobile-presence.groovy
*
* Change History:
* 1. 20160205 TW - Update/Edit to support i18n translations
===============================================================================
*/ */
metadata { metadata {
definition (name: "Mobile Presence", namespace: "smartthings", author: "SmartThings") { definition (name: "Mobile Presence", namespace: "smartthings", author: "SmartThings") {
capability "Presence Sensor" capability "Presence Sensor"
@@ -53,7 +41,6 @@ def parse(String description) {
def isStateChange = isStateChange(device, name, value) def isStateChange = isStateChange(device, name, value)
def results = [ def results = [
translatable: true,
name: name, name: name,
value: value, value: value,
unit: null, unit: null,
@@ -85,8 +72,8 @@ private String parseValue(String 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
} }
} }
@@ -97,4 +84,4 @@ private getState(String value) {
case "not present": return "left" case "not present": return "left"
default: return value default: return value
} }
} }

View File

@@ -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: SmartPower Outlet i18n Translation File
#
# Filename: SmartPower-Outlet.src/i18n/messages.properties
#
# Change History:
# 1. 20160116 TW Initial release with informal Korean translation.
#==============================================================================
# Korean (ko)
# Device Preferences
'''Give your device a name'''.ko=기기 이름 바꾸기
'''Outlet'''.ko=플러그
# Events descriptionText
'''{{ device.displayName }} is On'''.ko={{ device.displayName }}켜졌습니다.
'''{{ device.displayName }} is Off'''.ko={{ device.displayName }}꺼졌습니다.
'''{{ device.displayName }} power is {{ value }} Watts'''.ko={{ device.displayName }} 전원은 {{ value }}와트입니다
#==============================================================================

View File

@@ -1,26 +1,19 @@
/* /**
=============================================================================== * Copyright 2015 SmartThings
* Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* use this file except in compliance with the License. You may obtain a copy * in compliance with the License. You may obtain a copy of the License at:
* 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 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * for the specific language governing permissions and limitations under the License.
* License for the specific language governing permissions and limitations
* under the License.
===============================================================================
* Purpose: SmartPower Outlet DTH File
* *
* Filename: SmartPower-Outlet.src/SmartPower-Outlet.groovy * SmartPower Outlet (CentraLite)
* *
* Change History: * Author: SmartThings
* 1. 20160117 TW - Update/Edit to support i18n translations * Date: 2015-08-23
===============================================================================
*/ */
metadata { metadata {
// Automatically generated. Make future change here. // Automatically generated. Make future change here.
@@ -98,22 +91,22 @@ def parse(String description) {
finalResult = getPowerDescription(zigbee.parseDescriptionAsMap(description)) finalResult = getPowerDescription(zigbee.parseDescriptionAsMap(description))
if (finalResult) { if (finalResult) {
log.info "final result = $finalResult" log.info finalResult
if (finalResult.type == "update") { if (finalResult.type == "update") {
log.info "$device updates: ${finalResult.value}" log.info "$device updates: ${finalResult.value}"
} }
else if (finalResult.type == "power") { else if (finalResult.type == "power") {
def powerValue = (finalResult.value as Integer)/10 def powerValue = (finalResult.value as Integer)/10
sendEvent(name: "power", value: powerValue, descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true ) sendEvent(name: "power", value: powerValue)
/* /*
Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10 Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10
power level is an integer. The exact power level with correct units needs to be handled in the device type power level is an integer. The exact power level with correct units needs to be handled in the device type
to account for the different Divisor value (AttrId: 0302) and POWER Unit (AttrId: 0300). CLUSTER for simple metering is 0702 to account for the different Divisor value (AttrId: 0302) and POWER Unit (AttrId: 0300). CLUSTER for simple metering is 0702
*/ */
} }
else { else {
def descriptionText = finalResult.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off' sendEvent(name: finalResult.type, value: finalResult.value)
sendEvent(name: finalResult.type, value: finalResult.value, descriptionText: descriptionText, translatable: true)
} }
} }
else { else {

View File

@@ -1,41 +1,14 @@
#==============================================================================
# Copyright 2016 SmartThings # Generated on Wed Feb 24 14:28:26 CST 2016 by dylan
# '''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
# Licensed under the Apache License, Version 2.0 (the "License"); you may not '''Degrees'''.ko=온도
# use this file except in compliance with the License. You may obtain a copy '''Temperature Offset'''.ko=온도 직접 설정
# of the License at: '''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=배터리
# 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: SmartSense Moisture Sensor i18n Translation File
#
# Filename: SmartSense-Moisture-Sensor.src/i18n/messages.properties
#
# Change History:
# 1. 20160116 TW Initial release with formal Korean translation.
#==============================================================================
# Korean (ko)
# Device Preferences
'''dry'''.ko=건조 '''dry'''.ko=건조
'''wet'''.ko=누수 '''wet'''.ko=누수
'''battery'''.ko=배터리 '''{{ device.displayName }} battery has too much power: (> 3.5) volts.'''.ko={{ device.displayName }} 배터리 전력이 너무 높습니다(3.5볼트 초과).
'''Temperature Offset'''.ko=온도 직접 설정 '''{{ device.displayName }} battery was {{ value }}'''.ko={{ device.displayName }} 배터리가 {{ value }}였습니다
'''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=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다. '''{{ device.displayName }} is {{ value | translate }}'''.ko={{ device.displayName }}이(가) {{ value | translate }}입니다
'''Degrees'''.ko=온도
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
'''Give your device a name'''.ko=기기 이름 바꾸기
'''Water Leak Sensor'''.ko=누수센서
# Events descriptionText
'''{{ device.displayName }} is dry'''.ko={{ device.displayName }}가 건조
'''{{ device.displayName }} is wet'''.ko={{ device.displayName }}누수
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}이(가) {{ value }}°C였습니다 '''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}이(가) {{ value }}°C였습니다
'''{{ device.displayName }} was {{ value }}°F'''.ko={{ device.displayName }}이(가) {{ value }}°F였습니다 '''{{ device.displayName }} was {{ value }}°F'''.ko={{ device.displayName }}이(가) {{ value }}°F였습니다
'''{{ device.displayName }} battery has too much power: (> 3.5) volts.'''.ko={{ device.displayName }} 배터리 전력이 너무 높습니다(3.5볼트 초과).
'''{{ device.displayName }} battery was {{ value }}%'''.ko={{ device.displayName }}남아있는 배터리는 {{ value }}%입니다.
#==============================================================================

View File

@@ -1,29 +1,18 @@
/* /**
=============================================================================== * SmartSense Moisture Sensor
* Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * Copyright 2014 SmartThings
* use this file except in compliance with the License. You may obtain a copy *
* of the License at: * 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 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * for the specific language governing permissions and limitations under the License.
* License for the specific language governing permissions and limitations
* under the License.
===============================================================================
* Purpose: SmartSense Moisture Sensor DTH File
* *
* Filename: SmartSense-Moisture-Sensor.src/SmartSense-Moisture-Sensor.groovy
*
* Change History:
* 1. 20160116 TW - Update/Edit to support i18n translations
* 2. 20160125 TW = Incorporated new battery mapping from TM
===============================================================================
*/ */
metadata { metadata {
definition (name: "SmartSense Moisture Sensor",namespace: "smartthings", author: "SmartThings") { definition (name: "SmartSense Moisture Sensor",namespace: "smartthings", author: "SmartThings") {
capability "Configuration" capability "Configuration"
@@ -54,7 +43,7 @@ metadata {
]) ])
} }
section { section {
input title: "Temperature Offset", description: "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'.", displayDuringSetup: false, type: "paragraph", element: "paragraph" input title: "Temperature Offset", description: "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\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
} }
} }
@@ -127,16 +116,16 @@ private Map parseCatchAllMessage(String description) {
resultMap = getBatteryResult(cluster.data.last()) resultMap = getBatteryResult(cluster.data.last())
break break
case 0x0402: case 0x0402:
// temp is last 2 data values. reverse to swap endian // temp is last 2 data values. reverse to swap endian
String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join() String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join()
def value = getTemperature(temp) def value = getTemperature(temp)
resultMap = getTemperatureResult(value) resultMap = getTemperatureResult(value)
break break
} }
} }
return resultMap return resultMap
} }
private boolean shouldProcessMessage(cluster) { private boolean shouldProcessMessage(cluster) {
@@ -231,8 +220,7 @@ private Map getBatteryResult(rawValue) {
def result = [ def result = [
name: 'battery', name: 'battery',
value: '--', value: '--'
translatable: true
] ]
def volts = rawValue / 10 def volts = rawValue / 10
@@ -240,7 +228,7 @@ private Map getBatteryResult(rawValue) {
if (rawValue == 0 || rawValue == 255) {} if (rawValue == 0 || rawValue == 255) {}
else { else {
if (volts > 3.5) { if (volts > 3.5) {
result.descriptionText = "{{ device.displayName }} battery has too much power: (> 3.5) volts." result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
} }
else { else {
if (device.getDataValue("manufacturer") == "SmartThings") { if (device.getDataValue("manufacturer") == "SmartThings") {
@@ -257,7 +245,7 @@ private Map getBatteryResult(rawValue) {
def pct = batteryMap[volts] def pct = batteryMap[volts]
if (pct != null) { if (pct != null) {
result.value = pct result.value = pct
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" result.descriptionText = "${linkText} battery was ${result.value}%"
} }
} }
else { else {
@@ -265,7 +253,7 @@ private Map getBatteryResult(rawValue) {
def maxVolts = 3.0 def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts) def pct = (volts - minVolts) / (maxVolts - minVolts)
result.value = Math.min(100, (int) pct * 100) result.value = Math.min(100, (int) pct * 100)
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" result.descriptionText = "${linkText} battery was ${result.value}%"
} }
} }
} }
@@ -275,37 +263,27 @@ private Map getBatteryResult(rawValue) {
private Map getTemperatureResult(value) { private Map getTemperatureResult(value) {
log.debug 'TEMP' log.debug 'TEMP'
def linkText = getLinkText(device)
if (tempOffset) { if (tempOffset) {
def offset = tempOffset as int def offset = tempOffset as int
def v = value as int def v = value as int
value = v + offset value = v + offset
} }
def descriptionText def descriptionText = "${linkText} was ${value}°${temperatureScale}"
if ( temperatureScale == 'C' )
descriptionText = '{{ device.displayName }} was {{ value }}°C'
else
descriptionText = '{{ device.displayName }} was {{ value }}°F'
return [ return [
name: 'temperature', name: 'temperature',
value: value, value: value,
descriptionText: descriptionText, descriptionText: descriptionText
translatable: true
] ]
} }
private Map getMoistureResult(value) { private Map getMoistureResult(value) {
log.debug "water" log.debug 'water'
def descriptionText String descriptionText = "${device.displayName} is ${value}"
if ( value == "wet" )
descriptionText = '{{ device.displayName }} is wet'
else
descriptionText = '{{ device.displayName }} is dry'
return [ return [
name: 'water', name: 'water',
value: value, value: value,
descriptionText: descriptionText, descriptionText: descriptionText
translatable: true
] ]
} }

View File

@@ -1,40 +1,13 @@
#==============================================================================
# Copyright 2016 SmartThings # Generated on Wed Feb 24 14:28:26 CST 2016 by dylan
#
# 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: SmartSense Motion Sensor i18n Translation File
#
# Filename: SmartSense-Motion-Sensor.src/i18n/messages.properties
#
# Change History:
# 1. 20160116 TW Initial release with formal Korean translation.
# 2. 20160224 TW Updated formal Korean translations from Mike Stoller.
#==============================================================================
# Korean (ko)
# Device Preferences
'''battery'''.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=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다.
'''Degrees'''.ko=온도
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오 '''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
'''Give your device a name'''.ko=기기 이름 바꾸기 '''Degrees'''.ko=온도
'''Motion Sensor'''.ko=모션 센서 '''Temperature Offset'''.ko=온도 직접 설정
# Events descriptionText '''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=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다.
'''{{ device.displayName }} detected motion'''.ko={{ device.displayName }} 가 움직임을 감지하였습니다. '''battery'''.ko=배터리
'''{{ 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였습니다
'''{{ device.displayName }} battery has too much power: (> 3.5) volts.'''.ko={{ device.displayName }} 배터리 전력이 너무 높습니다(3.5볼트 초과). '''{{ 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 }} 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였습니다

View File

@@ -1,27 +1,17 @@
/* /**
=============================================================================== * SmartSense Motion/Temp Sensor
* Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * Copyright 2014 SmartThings
* use this file except in compliance with the License. You may obtain a copy *
* of the License at: * 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 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * for the specific language governing permissions and limitations under the License.
* License for the specific language governing permissions and limitations
* under the License.
===============================================================================
* Purpose: SmartSense Motion Sensor DTH File
* *
* Filename: SmartSense-Motion-Sensor.src/SmartSense-Motion-Sensor.groovy
*
* Change History:
* 1. 20160116 TW - Update/Edit to support i18n translations
* 2. 20160125 TW = Incorporated new battery mapping from TM
===============================================================================
*/ */
metadata { metadata {
@@ -57,7 +47,7 @@ metadata {
]) ])
} }
section { section {
input title: "Temperature Offset", description: "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'.", displayDuringSetup: false, type: "paragraph", element: "paragraph" input title: "Temperature Offset", description: "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\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
} }
} }
@@ -246,8 +236,7 @@ private Map getBatteryResult(rawValue) {
def result = [ def result = [
name: 'battery', name: 'battery',
value: '--', value: '--'
translatable: true
] ]
def volts = rawValue / 10 def volts = rawValue / 10
@@ -255,7 +244,7 @@ private Map getBatteryResult(rawValue) {
if (rawValue == 0 || rawValue == 255) {} if (rawValue == 0 || rawValue == 255) {}
else { else {
if (volts > 3.5) { if (volts > 3.5) {
result.descriptionText = "{{ device.displayName }} battery has too much power: (> 3.5) volts." result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
} }
else { else {
if (device.getDataValue("manufacturer") == "SmartThings") { if (device.getDataValue("manufacturer") == "SmartThings") {
@@ -272,8 +261,7 @@ private Map getBatteryResult(rawValue) {
def pct = batteryMap[volts] def pct = batteryMap[volts]
if (pct != null) { if (pct != null) {
result.value = pct result.value = pct
def value = pct result.descriptionText = "${linkText} battery was ${result.value}%"
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
} }
} }
else { else {
@@ -281,7 +269,7 @@ private Map getBatteryResult(rawValue) {
def maxVolts = 3.0 def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts) def pct = (volts - minVolts) / (maxVolts - minVolts)
result.value = Math.min(100, (int) pct * 100) result.value = Math.min(100, (int) pct * 100)
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" result.descriptionText = "${linkText} battery was ${result.value}%"
} }
} }
} }
@@ -291,33 +279,28 @@ private Map getBatteryResult(rawValue) {
private Map getTemperatureResult(value) { private Map getTemperatureResult(value) {
log.debug 'TEMP' log.debug 'TEMP'
def linkText = getLinkText(device)
if (tempOffset) { if (tempOffset) {
def offset = tempOffset as int def offset = tempOffset as int
def v = value as int def v = value as int
value = v + offset value = v + offset
} }
def descriptionText def descriptionText = "${linkText} was ${value}°${temperatureScale}"
if ( temperatureScale == 'C' )
descriptionText = '{{ device.displayName }} was {{ value }}°C'
else
descriptionText = '{{ device.displayName }} was {{ value }}°F'
return [ return [
name: 'temperature', name: 'temperature',
value: value, value: value,
descriptionText: descriptionText, descriptionText: descriptionText
translatable: true
] ]
} }
private Map getMotionResult(value) { private Map getMotionResult(value) {
log.debug 'motion' log.debug 'motion'
String descriptionText = value == 'active' ? "{{ device.displayName }} detected motion" : "{{ device.displayName }} motion has stopped" String linkText = getLinkText(device)
String descriptionText = value == 'active' ? "${linkText} detected motion" : "${linkText} motion has stopped"
return [ return [
name: 'motion', name: 'motion',
value: value, value: value,
descriptionText: descriptionText, descriptionText: descriptionText
translatable: true
] ]
} }

View File

@@ -1,45 +1,20 @@
#==============================================================================
# Copyright 2016 SmartThings # Generated on Wed Feb 24 14:28:26 CST 2016 by dylan
# '''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
# Licensed under the Apache License, Version 2.0 (the "License"); you may not '''Degrees'''.ko=온도
# use this file except in compliance with the License. You may obtain a copy '''Do you want to use this sensor on a garage door?'''.ko=차고 문의 센서 사용 설정하기
# 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: SmartSense Multi Sensor i18n Translation File
#
# Filename: SmartSense-Multi-Sensor.src/i18n/messages.properties
#
# Change History:
# 1. 20160117 TW Initial release with informal Korean translation.
#==============================================================================
# Korean (ko)
# Device Preferences
'''Yes'''.ko=
'''No'''.ko=아니요 '''No'''.ko=아니요
'''battery'''.ko=배터리 '''Tap to set'''.ko=눌러서 설정
'''Temperature Offset'''.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=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다. '''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=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다.
'''Degrees'''.ko=온도
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
'''Do you want to use this sensor on a garage door?'''.ko=차고 문의 센서 사용 설정하기
'''Tap to set'''.ko=눌러서 설정
'''Give your device a name'''.ko=기기 이름 바꾸기
'''Multipurpose Sensor'''.ko=멀티 센서
# Events descriptionText
'''{{ device.displayName }} was opened'''.ko={{ device.displayName }}열림을 감지하였습니다.
'''{{ device.displayName }} was closed'''.ko={{ device.displayName }}닫혔습니다.
'''{{ device.displayName }} was active'''.ko={{ device.displayName }}활성화되었습니다.
'''{{ device.displayName }} was inactive'''.ko={{ device.displayName }}비활성화되었습니다.
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}이(가){{ value }}°C였습니다.
'''{{ device.displayName }} was {{ value }}°F'''.ko={{ device.displayName }}이(가) {{ value }}°F였습니다
'''{{ device.displayName }} battery was {{ value }}%'''.ko={{ device.displayName }}남아있는 배터리는 {{ value }}%입니다.
'''Updating device to garage sensor'''.ko=기기-차고 센서 업데이트 중 '''Updating device to garage sensor'''.ko=기기-차고 센서 업데이트 중
'''Updating device to open/close 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였습니다

View File

@@ -1,27 +1,17 @@
/* /**
=============================================================================== * SmartSense Multi
* Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * Copyright 2015 SmartThings
* use this file except in compliance with the License. You may obtain a copy *
* of the License at: * 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 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * for the specific language governing permissions and limitations under the License.
* License for the specific language governing permissions and limitations
* under the License.
===============================================================================
* Purpose: SmartSense Multi Sensor DTH File
* *
* Filename: SmartSense-Multi-Sensor.src/SmartSense-Multi-Sensor.groovy
*
* Change History:
* 1. 20160117 TW - Update/Edit to support i18n translations
* 2. 20160125 TW = Incorporated new battery mapping from TM
===============================================================================
*/ */
metadata { metadata {
@@ -72,11 +62,11 @@ metadata {
]) ])
} }
section { section {
input title: "Temperature Offset", description: "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'.", displayDuringSetup: false, type: "paragraph", element: "paragraph" input title: "Temperature Offset", description: "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\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
} }
section { section {
input("garageSensor", "enum", title: "Do you want to use this sensor on a garage door?", description: "Tap to set", options: ["Yes", "No"], defaultValue: "No", required: false, displayDuringSetup: false) input("garageSensor", "enum", title: "Do you want to use this sensor on a garage door?", options: ["Yes", "No"], defaultValue: "No", required: false, displayDuringSetup: false)
} }
} }
@@ -283,19 +273,19 @@ def updated() {
if (garageSensor == "Yes") { if (garageSensor == "Yes") {
def descriptionText = "Updating device to garage sensor" def descriptionText = "Updating device to garage sensor"
if (device.latestValue("status") == "open") { if (device.latestValue("status") == "open") {
sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true) sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText)
} }
else if (device.latestValue("status") == "closed") { else if (device.latestValue("status") == "closed") {
sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true) sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText)
} }
} }
else { else {
def descriptionText = "Updating device to open/close sensor" def descriptionText = "Updating device to open/close sensor"
if (device.latestValue("status") == "garage-open") { if (device.latestValue("status") == "garage-open") {
sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true) sendEvent(name: 'status', value: 'open', descriptionText: descriptionText)
} }
else if (device.latestValue("status") == "garage-closed") { else if (device.latestValue("status") == "garage-closed") {
sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true) sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText)
} }
} }
} }
@@ -311,11 +301,11 @@ def getTemperature(value) {
private Map getBatteryResult(rawValue) { private Map getBatteryResult(rawValue) {
log.debug "Battery rawValue = ${rawValue}" log.debug "Battery rawValue = ${rawValue}"
def linkText = getLinkText(device)
def result = [ def result = [
name: 'battery', name: 'battery',
value: '--', value: '--'
translatable: true
] ]
def volts = rawValue / 10 def volts = rawValue / 10
@@ -323,7 +313,7 @@ private Map getBatteryResult(rawValue) {
if (rawValue == 0 || rawValue == 255) {} if (rawValue == 0 || rawValue == 255) {}
else { else {
if (volts > 3.5) { if (volts > 3.5) {
result.descriptionText = "{{ device.displayName }} battery has too much power: (> 3.5) volts." result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
} }
else { else {
if (device.getDataValue("manufacturer") == "SmartThings") { if (device.getDataValue("manufacturer") == "SmartThings") {
@@ -340,7 +330,7 @@ private Map getBatteryResult(rawValue) {
def pct = batteryMap[volts] def pct = batteryMap[volts]
if (pct != null) { if (pct != null) {
result.value = pct result.value = pct
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" result.descriptionText = "${linkText} battery was ${result.value}%"
} }
} }
else { else {
@@ -348,7 +338,7 @@ private Map getBatteryResult(rawValue) {
def maxVolts = 3.0 def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts) def pct = (volts - minVolts) / (maxVolts - minVolts)
result.value = Math.min(100, (int) pct * 100) result.value = Math.min(100, (int) pct * 100)
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" result.descriptionText = "${linkText} battery was ${result.value}%"
} }
} }
} }
@@ -358,50 +348,40 @@ private Map getBatteryResult(rawValue) {
private Map getTemperatureResult(value) { private Map getTemperatureResult(value) {
log.debug "Temperature" log.debug "Temperature"
def linkText = getLinkText(device)
if (tempOffset) { if (tempOffset) {
def offset = tempOffset as int def offset = tempOffset as int
def v = value as int def v = value as int
value = v + offset value = v + offset
} }
def descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C': def descriptionText = "${linkText} was ${value}°${temperatureScale}"
'{{ device.displayName }} was {{ value }}°F'
return [ return [
name: 'temperature', name: 'temperature',
value: value, value: value,
descriptionText: descriptionText, descriptionText: descriptionText
translatable: true
] ]
} }
private Map getContactResult(value) { private Map getContactResult(value) {
log.debug "Contact: ${device.displayName} value = ${value}" log.debug "Contact"
def descriptionText = value == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed' def linkText = getLinkText(device)
sendEvent(name: 'contact', value: value, descriptionText: descriptionText, displayed: false, translatable: true) def descriptionText = "${linkText} was ${value == 'open' ? 'opened' : 'closed'}"
sendEvent(name: 'status', value: value, descriptionText: descriptionText, translatable: true) sendEvent(name: 'contact', value: value, descriptionText: descriptionText, displayed:false)
sendEvent(name: 'status', value: value, descriptionText: descriptionText)
} }
private getAccelerationResult(numValue) { private getAccelerationResult(numValue) {
log.debug "Acceleration" log.debug "Acceleration"
def name = "acceleration" def name = "acceleration"
def value def value = numValue.endsWith("1") ? "active" : "inactive"
def descriptionText def linkText = getLinkText(device)
def descriptionText = "$linkText was $value"
if ( numValue.endsWith("1") ) {
value = "active"
descriptionText = '{{ device.displayName }} was active'
} else {
value = "inactive"
descriptionText = '{{ device.displayName }} was inactive'
}
def isStateChange = isStateChange(device, name, value) def isStateChange = isStateChange(device, name, value)
return [ [
name: name, name: name,
value: value, value: value,
descriptionText: descriptionText, descriptionText: descriptionText,
isStateChange: isStateChange, isStateChange: isStateChange
translatable: true
] ]
} }
@@ -471,15 +451,15 @@ def configure() {
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500", "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zcl mfg-code ${manufacturerCode}", "delay 200", "zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global send-me-a-report 0xFC02 0x0012 0x29 1 3600 {0100}", "delay 200", "zcl global send-me-a-report 0xFC02 0x0012 0x29 1 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500", "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zcl mfg-code ${manufacturerCode}", "delay 200", "zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global send-me-a-report 0xFC02 0x0013 0x29 1 3600 {0100}", "delay 200", "zcl global send-me-a-report 0xFC02 0x0013 0x29 1 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500", "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zcl mfg-code ${manufacturerCode}", "delay 200", "zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global send-me-a-report 0xFC02 0x0014 0x29 1 3600 {0100}", "delay 200", "zcl global send-me-a-report 0xFC02 0x0014 0x29 1 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500" "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500"
] ]
@@ -548,9 +528,10 @@ def garageEvent(zValue) {
garageValue = 'garage-open' garageValue = 'garage-open'
} }
if (contactValue != null){ if (contactValue != null){
def descriptionText = contactValue == 'open' ? '{{ device.displayName }} was opened' :'{{ device.displayName }} was closed' def linkText = getLinkText(device)
sendEvent(name: 'contact', value: contactValue, descriptionText: descriptionText, displayed:false, translatable: true) def descriptionText = "${linkText} was ${contactValue == 'open' ? 'opened' : 'closed'}"
sendEvent(name: 'status', value: garageValue, descriptionText: descriptionText, translatable: true) sendEvent(name: 'contact', value: contactValue, descriptionText: descriptionText, displayed:false)
sendEvent(name: 'status', value: garageValue, descriptionText: descriptionText)
} }
} }

View File

@@ -22,8 +22,6 @@ metadata {
capability "Battery" capability "Battery"
fingerprint profileId: "FC01", deviceId: "0139" fingerprint profileId: "FC01", deviceId: "0139"
attribute "status", "string"
} }
simulator { simulator {
@@ -101,7 +99,7 @@ def parse(String description) {
} }
private List parseSingleMessage(description) { private Map parseSingleMessage(description) {
def name = parseName(description) def name = parseName(description)
def value = parseValue(description) def value = parseValue(description)
@@ -110,9 +108,8 @@ private List parseSingleMessage(description) {
def handlerName = value == 'open' ? 'opened' : value def handlerName = value == 'open' ? 'opened' : value
def isStateChange = isStateChange(device, name, value) def isStateChange = isStateChange(device, name, value)
def results = [] def results = [
results << createEvent( name: name,
name: "contact",
value: value, value: value,
unit: null, unit: null,
linkText: linkText, linkText: linkText,
@@ -120,18 +117,8 @@ private List parseSingleMessage(description) {
handlerName: handlerName, handlerName: handlerName,
isStateChange: isStateChange, isStateChange: isStateChange,
displayed: displayed(description, isStateChange) displayed: displayed(description, isStateChange)
) ]
log.debug "Parse results for $device: $results"
results << createEvent(
name: "status",
value: value,
unit: null,
linkText: linkText,
descriptionText: descriptionText,
handlerName: handlerName,
isStateChange: isStateChange,
displayed: displayed(description, isStateChange)
)
results results
} }
@@ -282,7 +269,7 @@ private List parseRssiLqiMessage(String description) {
results results
} }
private List getContactResult(part, description) { private getContactResult(part, description) {
def name = "contact" def name = "contact"
def value = part.endsWith("1") ? "open" : "closed" def value = part.endsWith("1") ? "open" : "closed"
def handlerName = value == 'open' ? 'opened' : value def handlerName = value == 'open' ? 'opened' : value
@@ -290,30 +277,16 @@ private List getContactResult(part, description) {
def descriptionText = "$linkText was $handlerName" def descriptionText = "$linkText was $handlerName"
def isStateChange = isStateChange(device, name, value) def isStateChange = isStateChange(device, name, value)
def results = [] [
results << createEvent( name: name,
name: "contact", 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:false ]
)
results << createEvent(
name: "status",
value: value,
unit: null,
linkText: linkText,
descriptionText: descriptionText,
handlerName: handlerName,
isStateChange: isStateChange,
displayed: displayed(description, isStateChange)
)
results
} }
private getAccelerationResult(part, description) { private getAccelerationResult(part, description) {
@@ -476,7 +449,6 @@ private Boolean isOrientationMessage(String description) {
description ==~ /x:.*y:.*z:.*rssi:.*lqi:.*/ description ==~ /x:.*y:.*z:.*rssi:.*lqi:.*/
} }
//Note: Not using this method anymore
private String parseName(String description) { private String parseName(String description) {
if (isSupportedDescription(description)) { if (isSupportedDescription(description)) {
return "contact" return "contact"

View File

@@ -67,11 +67,11 @@ mappings {
def listAllDevices() { def listAllDevices() {
def resp = [] def resp = []
switches.each { switches.each {
resp << [name: it.name, label: it.label, value: it.currentValue("switch"), type: "switch", id: it.id, hub: it.hub?.name] resp << [name: it.name, label: it.label, value: it.currentValue("switch"), type: "switch", id: it.id, hub: it.hub.name]
} }
locks.each { locks.each {
resp << [name: it.name, label: it.label, value: it.currentValue("lock"), type: "lock", id: it.id, hub: it.hub?.name] resp << [name: it.name, label: it.label, value: it.currentValue("lock"), type: "lock", id: it.id, hub: it.hub.name]
} }
return resp return resp
} }

View File

@@ -463,32 +463,29 @@ def pollChildren(child = null) {
} }
// Poll Child is invoked from the Child Device itself as part of the Poll Capability // Poll Child is invoked from the Child Device itself as part of the Poll Capability
def pollChild(){ def pollChild(child){
def devices = getChildDevices() if (pollChildren(child)){
if (!child.device.deviceNetworkId.startsWith("ecobee_sensor")){
if (pollChildren()){ if(atomicState.thermostats[child.device.deviceNetworkId] != null) {
devices.each { child -> def tData = atomicState.thermostats[child.device.deviceNetworkId]
if (!child.device.deviceNetworkId.startsWith("ecobee_sensor")){ log.info "pollChild(child)>> data for ${child.device.deviceNetworkId} : ${tData.data}"
if(atomicState.thermostats[child.device.deviceNetworkId] != null) { child.generateEvent(tData.data) //parse received message from parent
def tData = atomicState.thermostats[child.device.deviceNetworkId] } else if(atomicState.thermostats[child.device.deviceNetworkId] == null) {
log.info "pollChild(child)>> data for ${child.device.deviceNetworkId} : ${tData.data}" log.error "ERROR: Device connection removed? no data for ${child.device.deviceNetworkId}"
child.generateEvent(tData.data) //parse received message from parent return null
} else if(atomicState.thermostats[child.device.deviceNetworkId] == null) {
log.error "ERROR: Device connection removed? no data for ${child.device.deviceNetworkId}"
return null
}
} }
} }
} else { } else {
log.info "ERROR: pollChildren()" log.info "ERROR: pollChildren(child) for ${child.device.deviceNetworkId} after polling"
return null return null
} }
} }
void poll() { void poll() {
pollChild() def devices = getChildDevices()
devices.each {pollChild(it)}
} }
def availableModes(child) { def availableModes(child) {

View File

@@ -24,7 +24,7 @@ definition(
category: "SmartThings Labs", category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png", iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png", iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png",
singleInstance: true //singleInstance: true
) )
preferences { preferences {
@@ -643,25 +643,21 @@ def setColorTemperature(childDevice, huesettings) {
def setColor(childDevice, huesettings) { def setColor(childDevice, huesettings) {
log.debug "Executing 'setColor($huesettings)'" log.debug "Executing 'setColor($huesettings)'"
def hue = null def hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
def sat = null def sat = Math.min(Math.round(huesettings.saturation * 255 / 100), 255)
def xy = null
if (huesettings.hex) {
xy = getHextoXY(huesettings.hex)
} else if (huesettings.hue && huesettings.saturation) {
hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
sat = Math.min(Math.round(huesettings.saturation * 255 / 100), 255)
}
def alert = huesettings.alert ? huesettings.alert : "none" def alert = huesettings.alert ? huesettings.alert : "none"
def transition = huesettings.transition ? huesettings.transition : 4 def transition = huesettings.transition ? huesettings.transition : 4
def value = [xy: xy, sat: sat, hue: hue, alert: alert, transitiontime: transition, on: true] def value = [sat: sat, hue: hue, alert: alert, transitiontime: transition]
if (huesettings.level != null) { if (huesettings.level != null) {
if (huesettings.level == 1) value.bri = 1 else value.bri = Math.min(Math.round(huesettings.level * 255 / 100), 255) if (huesettings.level == 1) value.bri = 1 else value.bri = Math.min(Math.round(huesettings.level * 255 / 100), 255)
value.on = value.bri > 0 value.on = value.bri > 0
} }
if (huesettings.switch) {
value.on = huesettings.switch == "on"
}
log.debug "sending command $value" log.debug "sending command $value"
put("lights/${getId(childDevice)}/state", value) put("lights/${getId(childDevice)}/state", value)
} }
@@ -747,59 +743,6 @@ private getBridgeIP() {
return host return host
} }
private getHextoXY(String colorStr) {
// For the hue bulb the corners of the triangle are:
// -Red: 0.675, 0.322
// -Green: 0.4091, 0.518
// -Blue: 0.167, 0.04
def cred = Integer.valueOf( colorStr.substring( 1, 3 ), 16 )
def cgreen = Integer.valueOf( colorStr.substring( 3, 5 ), 16 )
def cblue = Integer.valueOf( colorStr.substring( 5, 7 ), 16 )
double[] normalizedToOne = new double[3];
normalizedToOne[0] = (cred / 255);
normalizedToOne[1] = (cgreen / 255);
normalizedToOne[2] = (cblue / 255);
float red, green, blue;
// Make red more vivid
if (normalizedToOne[0] > 0.04045) {
red = (float) Math.pow(
(normalizedToOne[0] + 0.055) / (1.0 + 0.055), 2.4);
} else {
red = (float) (normalizedToOne[0] / 12.92);
}
// Make green more vivid
if (normalizedToOne[1] > 0.04045) {
green = (float) Math.pow((normalizedToOne[1] + 0.055)
/ (1.0 + 0.055), 2.4);
} else {
green = (float) (normalizedToOne[1] / 12.92);
}
// Make blue more vivid
if (normalizedToOne[2] > 0.04045) {
blue = (float) Math.pow((normalizedToOne[2] + 0.055)
/ (1.0 + 0.055), 2.4);
} else {
blue = (float) (normalizedToOne[2] / 12.92);
}
float X = (float) (red * 0.649926 + green * 0.103455 + blue * 0.197109);
float Y = (float) (red * 0.234327 + green * 0.743075 + blue * 0.022598);
float Z = (float) (red * 0.0000000 + green * 0.053077 + blue * 1.035763);
float x = X / (X + Y + Z);
float y = Y / (X + Y + Z);
double[] xy = new double[2];
xy[0] = x;
xy[1] = y;
return xy;
}
private Integer convertHexToInt(hex) { private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16) Integer.parseInt(hex,16)
} }

View File

@@ -1,31 +1,31 @@
'''Acceleration Detected'''.ko=가속 감지되었을 때 '''Acceleration Detected'''.ko=가속 감지
'''Arrival Of'''.ko=도착했을 때 '''Arrival Of'''.ko=도착
'''Both Push and SMS?'''.ko=푸시 알람과 SMS 모두 사용 '''Both Push and SMS?'''.ko=푸시 메시지와 SMS 모두 사용하시겠습니까?
'''Button Pushed'''.ko=버튼이 눌렸을 때 '''Button Pushed'''.ko=버튼이 눌렸습니다
'''Contact Closes'''.ko=닫힘이 감지되었을 때 '''Contact Closes'''.ko=접점 닫힘
'''Contact Opens'''.ko=열림이 감지되었을 때 '''Contact Opens'''.ko=접점 열림
'''Departure Of'''.ko=출발할 때 '''Departure Of'''.ko=출발
'''Message Text'''.ko=문자 메시지 '''Message Text'''.ko=문자 메시지
'''Minutes'''.ko=메시지 전송 간격(분) '''Minutes'''.ko=
'''Motion Here'''.ko=움직임이 감지되었을 때 '''Motion Here'''.ko=동작
'''Phone Number (for SMS, optional)'''.ko=전화번호 (옵션) '''Phone Number (for SMS, optional)'''.ko=휴대전화 번호(문자 메시지 - 옵션)
'''Receive notifications when anything happens in your home.'''.ko=집 안에 무슨 일이 일어나면 알림이 전송됩니다. '''Receive notifications when anything happens in your home.'''.ko=집 안에 무슨 일이 일어나면 알림이 전송됩니다.
'''Smoke Detected'''.ko=연기가 감지되었을 때 '''Smoke Detected'''.ko=연기가 감지되었습니다
'''Switch Turned Off'''.ko=스위치졌을 때 '''Switch Turned Off'''.ko=스위치 꺼
'''Switch Turned On'''.ko=스위치가 켜졌을 때 '''Switch Turned On'''.ko=스위치 꺼짐
'''Choose one or more, when...'''.ko=다음 상황 중 하나 이상 선택 '''Choose one or more, when...'''.ko=다음의 경우 하나 이상 선택
'''Yes'''.ko= '''Yes'''.ko=
'''No'''.ko=아니요 '''No'''.ko=아니요
'''Send this message (optional, sends standard status message if not specified)'''.ko=메시지 작성 (작성하지 않 경우 디폴트 메시지 전송) '''Send this message (optional, sends standard status message if not specified)'''.ko=메시지 전송(선택적, 지정되지 않 경우 표준 상태 메시지를 보냅니다)
'''Via a push notification and/or an SMS message'''.ko=푸시 알 SMS 설정 '''Via a push notification and/or an SMS message'''.ko=푸시 알/또는 문자 메시지를 통해
'''Set for specific mode(s)'''.ko=특정 상태 설정 '''Set for specific mode(s)'''.ko=특정 모드 설정
'''Tap to set'''.ko=눌러서 설정 '''Tap to set'''.ko=눌러서 설정
'''Minimum time between messages (optional, defaults to every message)'''.ko=메시지 전송 간격 설정 '''Minimum time between messages (optional, defaults to every message)'''.ko=메시지작 간 최소 시간(선택 사항, 모든 메시지의 기본 설정)
'''If outside the US please make sure to enter the proper country code'''.ko=미국 이외 국가에 거주한다면 국가 코드와 함께 입력하여 주세요. '''If outside the US please make sure to enter the proper country code'''.ko=미국 이외 거주자는 적절한 국가 코드를 입력했는지 확인하십시오
'''Water Sensor Wet'''.ko=누수가 감지되었을 때 '''Water Sensor Wet'''.ko=Water Sensor에서 물이 감지되었습니다
'''{{ triggerEvent.linkText }} has arrived at the {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}에 도착했습니다 '''{{ triggerEvent.linkText }} has arrived at the {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}에 도착했습니다
'''{{ triggerEvent.linkText }} has arrived at {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}에 도착했습니다 '''{{ triggerEvent.linkText }} has arrived at {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}에 도착했습니다
'''{{ triggerEvent.linkText }} has left the {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}을(를) 떠났습니다 '''{{ triggerEvent.linkText }} has left the {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}을(를) 떠났습니다
'''{{ triggerEvent.linkText }} has left {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}을(를) 떠났습니다 '''{{ triggerEvent.linkText }} has left {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}을(를) 떠났습니다
'''Assign a name'''.ko=이름 '''Assign a name'''.ko=이름
'''Choose Modes'''.ko=상태 선택 '''Choose Modes'''.ko=모드 선택

View File

@@ -234,7 +234,7 @@ def addSwitches() {
def d def d
if (selectedSwitch) { if (selectedSwitch) {
d = getChildDevices()?.find { d = getChildDevices()?.find {
it.deviceNetworkId == selectedSwitch.value.mac || it.device.getDataValue("mac") == selectedSwitch.value.mac it.dni == selectedSwitch.value.mac || it.device.getDataValue("mac") == selectedSwitch.value.mac
} }
} }
@@ -265,7 +265,7 @@ def addMotions() {
def d def d
if (selectedMotion) { if (selectedMotion) {
d = getChildDevices()?.find { d = getChildDevices()?.find {
it.deviceNetworkId == selectedMotion.value.mac || it.device.getDataValue("mac") == selectedMotion.value.mac it.dni == selectedMotion.value.mac || it.device.getDataValue("mac") == selectedMotion.value.mac
} }
} }
@@ -296,7 +296,7 @@ def addLightSwitches() {
def d def d
if (selectedLightSwitch) { if (selectedLightSwitch) {
d = getChildDevices()?.find { d = getChildDevices()?.find {
it.deviceNetworkId == selectedLightSwitch.value.mac || it.device.getDataValue("mac") == selectedLightSwitch.value.mac it.dni == selectedLightSwitch.value.mac || it.device.getDataValue("mac") == selectedLightSwitch.value.mac
} }
} }