From 04941dfa2123d2fc0c1a93deac20f65170a04208 Mon Sep 17 00:00:00 2001 From: twack Date: Sat, 5 Mar 2016 22:23:08 -0800 Subject: [PATCH] i18n groovy alignment for smartsense-moisture-sensor --- .../i18n/messages.properties | 46 +++- .../smartsense-moisture-sensor.groovy | 259 ++++++++++-------- 2 files changed, 176 insertions(+), 129 deletions(-) diff --git a/devicetypes/smartthings/smartsense-moisture-sensor.src/i18n/messages.properties b/devicetypes/smartthings/smartsense-moisture-sensor.src/i18n/messages.properties index 307fbb8..aa32ea0 100644 --- a/devicetypes/smartthings/smartsense-moisture-sensor.src/i18n/messages.properties +++ b/devicetypes/smartthings/smartsense-moisture-sensor.src/i18n/messages.properties @@ -1,14 +1,40 @@ - -# Generated on Wed Feb 24 14:28:26 CST 2016 by dylan -'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오 -'''Degrees'''.ko=온도 -'''Temperature Offset'''.ko=온도 직접 설정 -'''This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.'''.ko=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다. -'''battery'''.ko=배터리 +#============================================================================== +# 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: 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=건조 '''wet'''.ko=누수 -'''{{ device.displayName }} battery has too much power: (> 3.5) volts.'''.ko={{ device.displayName }} 배터리 전력이 너무 높습니다(3.5볼트 초과). -'''{{ device.displayName }} battery was {{ value }}'''.ko={{ device.displayName }} 배터리가 {{ value }}였습니다 -'''{{ device.displayName }} is {{ value | translate }}'''.ko={{ device.displayName }}이(가) {{ value | translate }}입니다 +'''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=몇 도씩 온도를 조절하십시오 +'''Give your device a name'''.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 }}°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 }}% +#============================================================================== \ No newline at end of file diff --git a/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy b/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy index 1c38e23..a8034bb 100644 --- a/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy +++ b/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy @@ -1,18 +1,29 @@ -/** - * SmartSense Moisture Sensor +/* +=============================================================================== + * Copyright 2016 SmartThings * - * Copyright 2014 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: + * 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. + * 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 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 { definition (name: "SmartSense Moisture Sensor",namespace: "smartthings", author: "SmartThings") { capability "Configuration" @@ -20,18 +31,17 @@ metadata { capability "Refresh" capability "Temperature Measurement" capability "Water Sensor" - - command "enrollResponse" - + + command "enrollResponse" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-S", deviceJoinName: "Water Leak Sensor" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-Seu", deviceJoinName: "Water Leak Sensor" fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "moisturev4", deviceJoinName: "Water Leak Sensor" } - + simulator { - + } preferences { @@ -43,11 +53,11 @@ metadata { ]) } 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 } } - + tiles(scale: 2) { multiAttributeTile(name:"water", type: "generic", width: 6, height: 4){ tileAttribute ("device.water", key: "PRIMARY_CONTROL") { @@ -56,7 +66,7 @@ metadata { } } valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) { - state "temperature", label:'${currentValue}°', + state "temperature", label:'${currentValue}', backgroundColors:[ [value: 31, color: "#153591"], [value: 44, color: "#1e9cbb"], @@ -78,7 +88,7 @@ metadata { details(["water", "temperature", "battery", "refresh"]) } } - + def parse(String description) { log.debug "description: $description" @@ -92,59 +102,59 @@ def parse(String description) { else if (description?.startsWith('temperature: ')) { map = parseCustomMessage(description) } - else if (description?.startsWith('zone status')) { - map = parseIasMessage(description) - } - + else if (description?.startsWith('zone status')) { + map = parseIasMessage(description) + } + log.debug "Parse returned $map" def result = map ? createEvent(map) : null - - if (description?.startsWith('enroll request')) { - List cmds = enrollResponse() - log.debug "enroll response: ${cmds}" - result = cmds?.collect { new physicalgraph.device.HubAction(it) } - } - return result + + if (description?.startsWith('enroll request')) { + List cmds = enrollResponse() + log.debug "enroll response: ${cmds}" + result = cmds?.collect { new physicalgraph.device.HubAction(it) } + } + return result } - + private Map parseCatchAllMessage(String description) { - Map resultMap = [:] - def cluster = zigbee.parse(description) - if (shouldProcessMessage(cluster)) { - switch(cluster.clusterId) { - case 0x0001: - resultMap = getBatteryResult(cluster.data.last()) - break + Map resultMap = [:] + def cluster = zigbee.parse(description) + if (shouldProcessMessage(cluster)) { + switch(cluster.clusterId) { + case 0x0001: + resultMap = getBatteryResult(cluster.data.last()) + break - case 0x0402: - // temp is last 2 data values. reverse to swap endian - String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join() - def value = getTemperature(temp) - resultMap = getTemperatureResult(value) - break - } - } + case 0x0402: + // temp is last 2 data values. reverse to swap endian + String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join() + def value = getTemperature(temp) + resultMap = getTemperatureResult(value) + break + } + } - return resultMap + return resultMap } private boolean shouldProcessMessage(cluster) { - // 0x0B is default response indicating message got through - // 0x07 is bind message - boolean ignoredMessage = cluster.profileId != 0x0104 || - cluster.command == 0x0B || - cluster.command == 0x07 || - (cluster.data.size() > 0 && cluster.data.first() == 0x3e) - return !ignoredMessage + // 0x0B is default response indicating message got through + // 0x07 is bind message + boolean ignoredMessage = cluster.profileId != 0x0104 || + cluster.command == 0x0B || + cluster.command == 0x07 || + (cluster.data.size() > 0 && cluster.data.first() == 0x3e) + return !ignoredMessage } - + private Map parseReportAttributeMessage(String description) { Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param -> def nameAndValue = param.split(":") map += [(nameAndValue[0].trim()):nameAndValue[1].trim()] } log.debug "Desc Map: $descMap" - + Map resultMap = [:] if (descMap.cluster == "0402" && descMap.attrId == "0000") { def value = getTemperature(descMap.value) @@ -153,10 +163,10 @@ private Map parseReportAttributeMessage(String description) { else if (descMap.cluster == "0001" && descMap.attrId == "0020") { resultMap = getBatteryResult(Integer.parseInt(descMap.value, 16)) } - + return resultMap } - + private Map parseCustomMessage(String description) { Map resultMap = [:] if (description?.startsWith('temperature: ')) { @@ -167,42 +177,42 @@ private Map parseCustomMessage(String description) { } private Map parseIasMessage(String description) { - List parsedMsg = description.split(' ') - String msgCode = parsedMsg[2] + List parsedMsg = description.split(' ') + String msgCode = parsedMsg[2] + + Map resultMap = [:] + switch(msgCode) { + case '0x0020': // Closed/No Motion/Dry + resultMap = getMoistureResult('dry') + break - Map resultMap = [:] - switch(msgCode) { - case '0x0020': // Closed/No Motion/Dry - resultMap = getMoistureResult('dry') - break + case '0x0021': // Open/Motion/Wet + resultMap = getMoistureResult('wet') + break - case '0x0021': // Open/Motion/Wet - resultMap = getMoistureResult('wet') - break + case '0x0022': // Tamper Alarm + break - case '0x0022': // Tamper Alarm - break + case '0x0023': // Battery Alarm + break - case '0x0023': // Battery Alarm - break + case '0x0024': // Supervision Report + log.debug 'dry with tamper alarm' + resultMap = getMoistureResult('dry') + break - case '0x0024': // Supervision Report - log.debug 'dry with tamper alarm' - resultMap = getMoistureResult('dry') - break + case '0x0025': // Restore Report + log.debug 'water with tamper alarm' + resultMap = getMoistureResult('wet') + break - case '0x0025': // Restore Report - log.debug 'water with tamper alarm' - resultMap = getMoistureResult('wet') - break + case '0x0026': // Trouble/Failure + break - case '0x0026': // Trouble/Failure - break - - case '0x0028': // Test Mode - break - } - return resultMap + case '0x0028': // Test Mode + break + } + return resultMap } def getTemperature(value) { @@ -220,7 +230,8 @@ private Map getBatteryResult(rawValue) { def result = [ name: 'battery', - value: '--' + value: '--', + translatable: true ] def volts = rawValue / 10 @@ -228,10 +239,10 @@ private Map getBatteryResult(rawValue) { if (rawValue == 0 || rawValue == 255) {} else { if (volts > 3.5) { - result.descriptionText = "${linkText} battery has too much power (${volts} volts)." + result.descriptionText = "{{ device.displayName }} battery has too much power: (> 3.5) volts." } else { - if (device.getDataValue("manufacturer") == "SmartThings") { + if (device.getDataValue("manufacturer") == "SmartThings") { volts = rawValue // For the batteryMap to work the key needs to be an int def batteryMap = [28:100, 27:100, 26:100, 25:90, 24:90, 23:70, 22:70, 21:50, 20:50, 19:30, 18:30, 17:15, 16:1, 15:0] @@ -245,7 +256,8 @@ private Map getBatteryResult(rawValue) { def pct = batteryMap[volts] if (pct != null) { result.value = pct - result.descriptionText = "${linkText} battery was ${result.value}%" + def value = pct + result.descriptionText = "{{ device.displayName }} battery was {{ value }}" } } else { @@ -253,44 +265,53 @@ private Map getBatteryResult(rawValue) { def maxVolts = 3.0 def pct = (volts - minVolts) / (maxVolts - minVolts) result.value = Math.min(100, (int) pct * 100) - result.descriptionText = "${linkText} battery was ${result.value}%" + result.descriptionText = "{{ device.displayName }} battery was {{ value }}" } } } return result } - private Map getTemperatureResult(value) { log.debug 'TEMP' - def linkText = getLinkText(device) if (tempOffset) { def offset = tempOffset as int def v = value as int value = v + offset } - def descriptionText = "${linkText} was ${value}°${temperatureScale}" + def descriptionText + if ( temperatureScale == 'C' ) + descriptionText = '{{ device.displayName }} was {{ value }}C' + else + descriptionText = '{{ device.displayName }} was {{ value }}F' + return [ name: 'temperature', value: value, - descriptionText: descriptionText + descriptionText: descriptionText, + translatable: true ] } private Map getMoistureResult(value) { - log.debug 'water' - String descriptionText = "${device.displayName} is ${value}" + log.debug "water" + def descriptionText + if ( value == "wet" ) + descriptionText = '{{ device.displayName }} is wet' + else + descriptionText = '{{ device.displayName }} is dry' return [ name: 'water', value: value, - descriptionText: descriptionText + descriptionText: descriptionText, + translatable: true ] } def refresh() { log.debug "Refreshing Temperature and Battery" def refreshCmds = [ - "st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200", + "st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200", "st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200" ] @@ -300,32 +321,32 @@ def refresh() { def configure() { String zigbeeEui = swapEndianHex(device.hub.zigbeeEui) log.debug "Configuring Reporting, IAS CIE, and Bindings." - def configCmds = [ + def configCmds = [ "zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200", "send 0x${device.deviceNetworkId} 1 1", "delay 500", "zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 1 {${device.zigbeeId}} {}", "delay 500", "zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", //checkin time 6 hrs - "send 0x${device.deviceNetworkId} 1 1", "delay 500", + "send 0x${device.deviceNetworkId} 1 1", "delay 500", "zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0x402 {${device.zigbeeId}} {}", "delay 500", - "zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}", - "send 0x${device.deviceNetworkId} 1 1", "delay 500" + "zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}", + "send 0x${device.deviceNetworkId} 1 1", "delay 500" ] - return configCmds + refresh() // send refresh cmds as part of config + return configCmds + refresh() // send refresh cmds as part of config } def enrollResponse() { log.debug "Sending enroll response" String zigbeeEui = swapEndianHex(device.hub.zigbeeEui) - [ + [ //Resending the CIE in case the enroll request is sent before CIE is written "zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200", "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500", //Enroll Response "raw 0x500 {01 23 00 00 00}", "send 0x${device.deviceNetworkId} 1 1", "delay 200" - ] + ] } private getEndpointId() { @@ -337,19 +358,19 @@ private hex(value) { } private String swapEndianHex(String hex) { - reverseArray(hex.decodeHex()).encodeHex() + reverseArray(hex.decodeHex()).encodeHex() } private byte[] reverseArray(byte[] array) { - int i = 0; - int j = array.length - 1; - byte tmp; - while (j > i) { - tmp = array[j]; - array[j] = array[i]; - array[i] = tmp; - j--; - i++; - } - return array -} + int i = 0; + int j = array.length - 1; + byte tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + return array +} \ No newline at end of file