mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-09 13:21:53 +00:00
Compare commits
1 Commits
PROD_2017.
...
MSA-1718-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
363f438bbf |
@@ -11,6 +11,7 @@
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
metadata {
|
||||
definition (name: "Arrival Sensor HA", namespace: "smartthings", author: "SmartThings") {
|
||||
capability "Tone"
|
||||
@@ -59,7 +60,7 @@ def updated() {
|
||||
}
|
||||
|
||||
def configure() {
|
||||
def cmds = zigbee.batteryConfig(20, 20, 0x01)
|
||||
def cmds = zigbee.configureReporting(0x0001, 0x0020, 0x20, 20, 20, 0x01)
|
||||
log.debug "configure -- cmds: ${cmds}"
|
||||
return cmds
|
||||
}
|
||||
|
||||
@@ -81,47 +81,51 @@ metadata {
|
||||
// parse events into attributes
|
||||
def parse(String description) {
|
||||
log.debug "Parse description $description"
|
||||
List result = []
|
||||
def descMap = zigbee.parseDescriptionAsMap(description)
|
||||
log.debug "Desc Map: $descMap"
|
||||
List attrData = [[cluster: descMap.cluster ,attrId: descMap.attrId, value: descMap.value]]
|
||||
descMap.additionalAttrs.each {
|
||||
attrData << [cluster: descMap.cluster, attrId: it.attrId, value: it.value]
|
||||
}
|
||||
attrData.each {
|
||||
def map = [:]
|
||||
if (it.cluster == "0201" && it.attrId == "0000") {
|
||||
def map = [:]
|
||||
if (description?.startsWith("read attr -")) {
|
||||
def descMap = parseDescriptionAsMap(description)
|
||||
log.debug "Desc Map: $descMap"
|
||||
if (descMap.cluster == "0201" && descMap.attrId == "0000") {
|
||||
log.debug "TEMP"
|
||||
map.name = "temperature"
|
||||
map.value = getTemperature(it.value)
|
||||
map.value = getTemperature(descMap.value)
|
||||
map.unit = temperatureScale
|
||||
} else if (it.cluster == "0201" && it.attrId == "0011") {
|
||||
} else if (descMap.cluster == "0201" && descMap.attrId == "0011") {
|
||||
log.debug "COOLING SETPOINT"
|
||||
map.name = "coolingSetpoint"
|
||||
map.value = getTemperature(it.value)
|
||||
map.value = getTemperature(descMap.value)
|
||||
map.unit = temperatureScale
|
||||
} else if (it.cluster == "0201" && it.attrId == "0012") {
|
||||
} else if (descMap.cluster == "0201" && descMap.attrId == "0012") {
|
||||
log.debug "HEATING SETPOINT"
|
||||
map.name = "heatingSetpoint"
|
||||
map.value = getTemperature(it.value)
|
||||
map.value = getTemperature(descMap.value)
|
||||
map.unit = temperatureScale
|
||||
} else if (it.cluster == "0201" && it.attrId == "001c") {
|
||||
} else if (descMap.cluster == "0201" && descMap.attrId == "001c") {
|
||||
log.debug "MODE"
|
||||
map.name = "thermostatMode"
|
||||
map.value = getModeMap()[it.value]
|
||||
} else if (it.cluster == "0202" && it.attrId == "0000") {
|
||||
map.value = getModeMap()[descMap.value]
|
||||
} else if (descMap.cluster == "0202" && descMap.attrId == "0000") {
|
||||
log.debug "FAN MODE"
|
||||
map.name = "thermostatFanMode"
|
||||
map.value = getFanModeMap()[it.value]
|
||||
map.value = getFanModeMap()[descMap.value]
|
||||
}
|
||||
if (map) {
|
||||
result << createEvent(map)
|
||||
}
|
||||
log.debug "Parse returned $map"
|
||||
}
|
||||
|
||||
def result = null
|
||||
if (map) {
|
||||
result = createEvent(map)
|
||||
}
|
||||
log.debug "Parse returned $map"
|
||||
return result
|
||||
}
|
||||
|
||||
def parseDescriptionAsMap(description) {
|
||||
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
||||
def nameAndValue = param.split(":")
|
||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
||||
}
|
||||
}
|
||||
|
||||
def getModeMap() { [
|
||||
"00":"off",
|
||||
"03":"cool",
|
||||
|
||||
@@ -23,7 +23,6 @@ metadata {
|
||||
capability "Switch"
|
||||
capability "Switch Level"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
|
||||
fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0000,0019"
|
||||
}
|
||||
@@ -83,7 +82,7 @@ def on() {
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
||||
zigbee.setLevel(value) + ["delay 500"] + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,6 @@ metadata {
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
|
||||
fingerprint mfr:"0063", prod:"4457", deviceJoinName: "GE In-Wall Smart Dimmer "
|
||||
fingerprint mfr:"0063", prod:"4944", deviceJoinName: "GE In-Wall Smart Dimmer "
|
||||
|
||||
@@ -17,7 +17,6 @@ metadata {
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
|
||||
command "setAdjustedColor"
|
||||
command "reset"
|
||||
@@ -58,7 +57,7 @@ metadata {
|
||||
}
|
||||
|
||||
void installed() {
|
||||
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}", displayed: false)
|
||||
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}")
|
||||
}
|
||||
|
||||
// parse events into attributes
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
metadata {
|
||||
// Automatically generated. Make future change here.
|
||||
definition (name: "Hue Bridge", namespace: "smartthings", author: "SmartThings") {
|
||||
capability "Bridge"
|
||||
capability "Health Check"
|
||||
|
||||
attribute "networkAddress", "string"
|
||||
@@ -46,7 +45,7 @@ metadata {
|
||||
}
|
||||
|
||||
void installed() {
|
||||
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}", displayed: false)
|
||||
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}")
|
||||
}
|
||||
|
||||
// parse events into attributes
|
||||
|
||||
@@ -18,7 +18,6 @@ metadata {
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
|
||||
command "setAdjustedColor"
|
||||
command "reset"
|
||||
@@ -67,7 +66,7 @@ metadata {
|
||||
}
|
||||
|
||||
void installed() {
|
||||
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}", displayed: false)
|
||||
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}")
|
||||
}
|
||||
|
||||
// parse events into attributes
|
||||
|
||||
@@ -14,8 +14,7 @@ metadata {
|
||||
capability "Switch"
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
capability "Health Check"
|
||||
|
||||
command "refresh"
|
||||
}
|
||||
@@ -51,7 +50,7 @@ metadata {
|
||||
}
|
||||
|
||||
void installed() {
|
||||
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}", displayed: false)
|
||||
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}")
|
||||
}
|
||||
|
||||
// parse events into attributes
|
||||
|
||||
@@ -16,7 +16,6 @@ metadata {
|
||||
capability "Switch"
|
||||
capability "Refresh"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
|
||||
command "refresh"
|
||||
}
|
||||
@@ -56,7 +55,7 @@ metadata {
|
||||
}
|
||||
|
||||
void installed() {
|
||||
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}", displayed: false)
|
||||
sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device.hub.hardwareID}\"}")
|
||||
}
|
||||
|
||||
// parse events into attributes
|
||||
|
||||
@@ -14,7 +14,6 @@ metadata {
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
}
|
||||
|
||||
simulator {
|
||||
|
||||
@@ -13,7 +13,6 @@ metadata {
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
}
|
||||
|
||||
simulator {
|
||||
|
||||
@@ -36,7 +36,6 @@ metadata {
|
||||
capability "Switch"
|
||||
capability "Refresh"
|
||||
capability "Contact Sensor"
|
||||
capability "Light"
|
||||
|
||||
attribute "powered", "string"
|
||||
|
||||
|
||||
@@ -40,11 +40,14 @@ metadata {
|
||||
|
||||
// Parse incoming device messages to generate events
|
||||
def parse(String description) {
|
||||
def resMap
|
||||
if (description.startsWith("zone")) {
|
||||
resMap = createEvent(name: "contact", value: zigbee.parseZoneStatus(description).isAlarm1Set() ? "open" : "closed")
|
||||
def name = null
|
||||
def value = description
|
||||
if (zigbee.isZoneType19(description)) {
|
||||
name = "contact"
|
||||
value = zigbee.translateStatusZoneType19(description) ? "open" : "closed"
|
||||
}
|
||||
|
||||
log.debug "Parse returned $resMap"
|
||||
return resMap
|
||||
def result = createEvent(name: name, value: value)
|
||||
log.debug "Parse returned ${result?.descriptionText}"
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ metadata {
|
||||
capability "Refresh"
|
||||
capability "Actuator"
|
||||
capability "Sensor"
|
||||
capability "Outlet"
|
||||
|
||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-ZHAC"
|
||||
|
||||
@@ -70,36 +69,292 @@ metadata {
|
||||
def parse(String description) {
|
||||
log.debug "description is $description"
|
||||
|
||||
def event = zigbee.getEvent(description)
|
||||
if (!event) {
|
||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||
log.debug zigbee.parseDescriptionAsMap(description)
|
||||
} else if (event.name == "power") {
|
||||
/*
|
||||
Dividing by 10 as the Divisor is 10000 and unit is kW for the device. Simplifying to 10 power level is an integer.
|
||||
*/
|
||||
event.value = event.value / 10
|
||||
}
|
||||
def event = [:]
|
||||
def finalResult = isKnownDescription(description)
|
||||
if (finalResult) {
|
||||
log.info finalResult
|
||||
if (finalResult.type == "update") {
|
||||
log.info "$device updates: ${finalResult.value}"
|
||||
event = null
|
||||
}
|
||||
else if (finalResult.type == "power") {
|
||||
def powerValue = (finalResult.value as Integer)/10
|
||||
event = createEvent(name: "power", value: powerValue)
|
||||
|
||||
return event ? createEvent(event) : event
|
||||
/*
|
||||
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
|
||||
to account for the different Divisor value (AttrId: 0302) and POWER Unit (AttrId: 0300). CLUSTER for simple metering is 0702
|
||||
*/
|
||||
}
|
||||
else {
|
||||
event = createEvent(name: finalResult.type, value: finalResult.value)
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||
log.debug parseDescriptionAsMap(description)
|
||||
}
|
||||
return event
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
zigbee.setLevel(value)
|
||||
// Commands to device
|
||||
def zigbeeCommand(cluster, attribute){
|
||||
"st cmd 0x${device.deviceNetworkId} ${endpointId} ${cluster} ${attribute} {}"
|
||||
}
|
||||
|
||||
def off() {
|
||||
zigbee.off()
|
||||
zigbeeCommand("6", "0")
|
||||
}
|
||||
|
||||
def on() {
|
||||
zigbee.on()
|
||||
zigbeeCommand("6", "1")
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
value = value as Integer
|
||||
if (value == 0) {
|
||||
off()
|
||||
}
|
||||
else {
|
||||
if (device.latestValue("switch") == "off") {
|
||||
sendEvent(name: "switch", value: "on")
|
||||
}
|
||||
sendEvent(name: "level", value: value)
|
||||
setLevelWithRate(value, "0000") //value is between 0 to 100
|
||||
}
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.electricMeasurementPowerRefresh()
|
||||
[
|
||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 6 0", "delay 2000",
|
||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 8 0", "delay 2000",
|
||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 0x0B04 0x050B", "delay 2000"
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
def configure() {
|
||||
refresh() + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.electricMeasurementPowerConfig()
|
||||
refresh() + onOffConfig() + levelConfig() + powerConfig()
|
||||
}
|
||||
|
||||
|
||||
private getEndpointId() {
|
||||
new BigInteger(device.endpointId, 16).toString()
|
||||
}
|
||||
|
||||
private hex(value, width=2) {
|
||||
def s = new BigInteger(Math.round(value).toString()).toString(16)
|
||||
while (s.size() < width) {
|
||||
s = "0" + s
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
private String swapEndianHex(String hex) {
|
||||
reverseArray(hex.decodeHex()).encodeHex()
|
||||
}
|
||||
|
||||
private Integer convertHexToInt(hex) {
|
||||
Integer.parseInt(hex,16)
|
||||
}
|
||||
|
||||
//Need to reverse array of size 2
|
||||
private byte[] reverseArray(byte[] array) {
|
||||
byte tmp;
|
||||
tmp = array[1];
|
||||
array[1] = array[0];
|
||||
array[0] = tmp;
|
||||
return array
|
||||
}
|
||||
|
||||
def parseDescriptionAsMap(description) {
|
||||
if (description?.startsWith("read attr -")) {
|
||||
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
||||
def nameAndValue = param.split(":")
|
||||
map += [(nameAndValue[0].trim()): nameAndValue[1].trim()]
|
||||
}
|
||||
}
|
||||
else if (description?.startsWith("catchall: ")) {
|
||||
def seg = (description - "catchall: ").split(" ")
|
||||
def zigbeeMap = [:]
|
||||
zigbeeMap += [raw: (description - "catchall: ")]
|
||||
zigbeeMap += [profileId: seg[0]]
|
||||
zigbeeMap += [clusterId: seg[1]]
|
||||
zigbeeMap += [sourceEndpoint: seg[2]]
|
||||
zigbeeMap += [destinationEndpoint: seg[3]]
|
||||
zigbeeMap += [options: seg[4]]
|
||||
zigbeeMap += [messageType: seg[5]]
|
||||
zigbeeMap += [dni: seg[6]]
|
||||
zigbeeMap += [isClusterSpecific: Short.valueOf(seg[7], 16) != 0]
|
||||
zigbeeMap += [isManufacturerSpecific: Short.valueOf(seg[8], 16) != 0]
|
||||
zigbeeMap += [manufacturerId: seg[9]]
|
||||
zigbeeMap += [command: seg[10]]
|
||||
zigbeeMap += [direction: seg[11]]
|
||||
zigbeeMap += [data: seg.size() > 12 ? seg[12].split("").findAll { it }.collate(2).collect {
|
||||
it.join('')
|
||||
} : []]
|
||||
|
||||
zigbeeMap
|
||||
}
|
||||
}
|
||||
|
||||
def isKnownDescription(description) {
|
||||
if ((description?.startsWith("catchall:")) || (description?.startsWith("read attr -"))) {
|
||||
def descMap = parseDescriptionAsMap(description)
|
||||
if (descMap.cluster == "0006" || descMap.clusterId == "0006") {
|
||||
isDescriptionOnOff(descMap)
|
||||
}
|
||||
else if (descMap.cluster == "0008" || descMap.clusterId == "0008"){
|
||||
isDescriptionLevel(descMap)
|
||||
}
|
||||
else if (descMap.cluster == "0B04" || descMap.clusterId == "0B04"){
|
||||
isDescriptionPower(descMap)
|
||||
}
|
||||
else {
|
||||
return [:]
|
||||
}
|
||||
}
|
||||
else if(description?.startsWith("on/off:")) {
|
||||
def switchValue = description?.endsWith("1") ? "on" : "off"
|
||||
return [type: "switch", value : switchValue]
|
||||
}
|
||||
else {
|
||||
return [:]
|
||||
}
|
||||
}
|
||||
|
||||
def isDescriptionOnOff(descMap) {
|
||||
def switchValue = "undefined"
|
||||
if (descMap.cluster == "0006") { //cluster info from read attr
|
||||
value = descMap.value
|
||||
if (value == "01"){
|
||||
switchValue = "on"
|
||||
}
|
||||
else if (value == "00"){
|
||||
switchValue = "off"
|
||||
}
|
||||
}
|
||||
else if (descMap.clusterId == "0006") {
|
||||
//cluster info from catch all
|
||||
//command 0B is Default response and the last two bytes are [on/off][success]. on/off=00, success=00
|
||||
//command 01 is Read attr response. the last two bytes are [datatype][value]. boolean datatype=10; on/off value = 01/00
|
||||
if ((descMap.command=="0B" && descMap.raw.endsWith("0100")) || (descMap.command=="01" && descMap.raw.endsWith("1001"))){
|
||||
switchValue = "on"
|
||||
}
|
||||
else if ((descMap.command=="0B" && descMap.raw.endsWith("0000")) || (descMap.command=="01" && descMap.raw.endsWith("1000"))){
|
||||
switchValue = "off"
|
||||
}
|
||||
else if(descMap.command=="07"){
|
||||
return [type: "update", value : "switch (0006) capability configured successfully"]
|
||||
}
|
||||
}
|
||||
|
||||
if (switchValue != "undefined"){
|
||||
return [type: "switch", value : switchValue]
|
||||
}
|
||||
else {
|
||||
return [:]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//@return - false or "success" or level [0-100]
|
||||
def isDescriptionLevel(descMap) {
|
||||
def dimmerValue = -1
|
||||
if (descMap.cluster == "0008"){
|
||||
//TODO: the message returned with catchall is command 0B with clusterId 0008. That is just a confirmation message
|
||||
def value = convertHexToInt(descMap.value)
|
||||
dimmerValue = Math.round(value * 100 / 255)
|
||||
if(dimmerValue==0 && value > 0) {
|
||||
dimmerValue = 1 //handling for non-zero hex value less than 3
|
||||
}
|
||||
}
|
||||
else if(descMap.clusterId == "0008") {
|
||||
if(descMap.command=="0B"){
|
||||
return [type: "update", value : "level updated successfully"] //device updating the level change was successful. no value sent.
|
||||
}
|
||||
else if(descMap.command=="07"){
|
||||
return [type: "update", value : "level (0008) capability configured successfully"]
|
||||
}
|
||||
}
|
||||
|
||||
if (dimmerValue != -1){
|
||||
return [type: "level", value : dimmerValue]
|
||||
}
|
||||
else {
|
||||
return [:]
|
||||
}
|
||||
}
|
||||
|
||||
def isDescriptionPower(descMap) {
|
||||
def powerValue = "undefined"
|
||||
if (descMap.cluster == "0B04") {
|
||||
if (descMap.attrId == "050b") {
|
||||
if(descMap.value!="ffff")
|
||||
powerValue = convertHexToInt(descMap.value)
|
||||
}
|
||||
}
|
||||
else if (descMap.clusterId == "0B04") {
|
||||
if(descMap.command=="07"){
|
||||
return [type: "update", value : "power (0B04) capability configured successfully"]
|
||||
}
|
||||
}
|
||||
|
||||
if (powerValue != "undefined"){
|
||||
return [type: "power", value : powerValue]
|
||||
}
|
||||
else {
|
||||
return [:]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def onOffConfig() {
|
||||
[
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 6 {${device.zigbeeId}} {}", "delay 2000",
|
||||
"zcl global send-me-a-report 6 0 0x10 0 600 {01}", "delay 200",
|
||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000"
|
||||
]
|
||||
}
|
||||
|
||||
//level config for devices with min reporting interval as 5 seconds and reporting interval if no activity as 1hour (3600s)
|
||||
//min level change is 01
|
||||
def levelConfig() {
|
||||
[
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 8 {${device.zigbeeId}} {}", "delay 2000",
|
||||
"zcl global send-me-a-report 8 0 0x20 5 3600 {01}", "delay 200",
|
||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000"
|
||||
]
|
||||
}
|
||||
|
||||
//power config for devices with min reporting interval as 1 seconds and reporting interval if no activity as 10min (600s)
|
||||
//min change in value is 05
|
||||
def powerConfig() {
|
||||
[
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x0B04 {${device.zigbeeId}} {}", "delay 2000",
|
||||
"zcl global send-me-a-report 0x0B04 0x050B 0x29 1 600 {05 00}", //The send-me-a-report is custom to the attribute type for CentraLite
|
||||
"delay 200",
|
||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000"
|
||||
]
|
||||
}
|
||||
|
||||
def setLevelWithRate(level, rate) {
|
||||
if(rate == null){
|
||||
rate = "0000"
|
||||
}
|
||||
level = convertToHexString(level * 255 / 100) //Converting the 0-100 range to 0-FF range in hex
|
||||
[
|
||||
"st cmd 0x${device.deviceNetworkId} ${endpointId} 8 4 {$level $rate}",
|
||||
"delay 2000"
|
||||
]
|
||||
}
|
||||
|
||||
String convertToHexString(value, width=2) {
|
||||
def s = new BigInteger(Math.round(value).toString()).toString(16)
|
||||
while (s.size() < width) {
|
||||
s = "0" + s
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ metadata {
|
||||
capability "Actuator"
|
||||
capability "Switch"
|
||||
capability "Sensor"
|
||||
capability "Outlet"
|
||||
|
||||
fingerprint profileId: "0104", inClusters: "0006, 0004, 0003, 0000, 0005", outClusters: "0019", manufacturer: "Compacta International, Ltd", model: "ZBMPlug15", deviceJoinName: "SmartPower Outlet V1"
|
||||
}
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
metadata {
|
||||
// Automatically generated. Make future change here.
|
||||
definition(name: "SmartPower Outlet", namespace: "smartthings", author: "SmartThings") {
|
||||
definition (name: "SmartPower Outlet", namespace: "smartthings", author: "SmartThings") {
|
||||
capability "Actuator"
|
||||
capability "Switch"
|
||||
capability "Power Meter"
|
||||
@@ -23,12 +24,10 @@ metadata {
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
capability "Outlet"
|
||||
|
||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200", deviceJoinName: "Outlet"
|
||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200-Sgb", deviceJoinName: "Outlet"
|
||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-RZHAC", deviceJoinName: "Outlet"
|
||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200", deviceJoinName: "Outlet"
|
||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200-Sgb", deviceJoinName: "Outlet"
|
||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-RZHAC", deviceJoinName: "Outlet"
|
||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019"
|
||||
}
|
||||
|
||||
@@ -46,32 +45,32 @@ metadata {
|
||||
preferences {
|
||||
section {
|
||||
image(name: 'educationalcontent', multiple: true, images: [
|
||||
"http://cdn.device-gse.smartthings.com/Outlet/US/OutletUS1.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Outlet/US/OutletUS2.jpg"
|
||||
])
|
||||
"http://cdn.device-gse.smartthings.com/Outlet/US/OutletUS1.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Outlet/US/OutletUS2.jpg"
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
// UI tile definitions
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name: "switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) {
|
||||
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
|
||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||
attributeState "on", label: 'On', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
|
||||
attributeState "off", label: 'Off', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
|
||||
attributeState "turningOn", label: 'Turning On', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
|
||||
attributeState "turningOff", label: 'Turning Off', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
|
||||
}
|
||||
tileAttribute("power", key: "SECONDARY_CONTROL") {
|
||||
attributeState "power", label: '${currentValue} W'
|
||||
tileAttribute ("power", key: "SECONDARY_CONTROL") {
|
||||
attributeState "power", label:'${currentValue} W'
|
||||
}
|
||||
}
|
||||
|
||||
standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||
state "default", label: '', action: "refresh.refresh", icon: "st.secondary.refresh"
|
||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
main "switch"
|
||||
details(["switch", "refresh"])
|
||||
details(["switch","refresh"])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,33 +78,52 @@ metadata {
|
||||
def parse(String description) {
|
||||
log.debug "description is $description"
|
||||
|
||||
def event = zigbee.getEvent(description)
|
||||
def finalResult = zigbee.getKnownDescription(description)
|
||||
def event = [:]
|
||||
|
||||
if (event) {
|
||||
if (event.name == "power") {
|
||||
def value = (event.value as Integer) / 10
|
||||
event = createEvent(name: event.name, value: value, descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true)
|
||||
} else if (event.name == "switch") {
|
||||
def descriptionText = event.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off'
|
||||
event = createEvent(name: event.name, value: event.value, descriptionText: descriptionText, translatable: true)
|
||||
//TODO: Remove this after getKnownDescription can parse it automatically
|
||||
if (!finalResult && description!="updated")
|
||||
finalResult = getPowerDescription(zigbee.parseDescriptionAsMap(description))
|
||||
|
||||
if (finalResult) {
|
||||
log.info "final result = $finalResult"
|
||||
if (finalResult.type == "update") {
|
||||
log.info "$device updates: ${finalResult.value}"
|
||||
event = null
|
||||
}
|
||||
} else {
|
||||
else if (finalResult.type == "power") {
|
||||
def powerValue = (finalResult.value as Integer)/10
|
||||
event = createEvent(name: "power", value: powerValue, descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true)
|
||||
/*
|
||||
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
|
||||
to account for the different Divisor value (AttrId: 0302) and POWER Unit (AttrId: 0300). CLUSTER for simple metering is 0702
|
||||
*/
|
||||
}
|
||||
else {
|
||||
def descriptionText = finalResult.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off'
|
||||
event = createEvent(name: finalResult.type, value: finalResult.value, descriptionText: descriptionText, translatable: true)
|
||||
}
|
||||
}
|
||||
else {
|
||||
def cluster = zigbee.parse(description)
|
||||
|
||||
if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
|
||||
if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07){
|
||||
if (cluster.data[0] == 0x00) {
|
||||
log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster
|
||||
event = createEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
||||
event = null
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||
log.debug "${cluster}"
|
||||
}
|
||||
}
|
||||
return event ? createEvent(event) : event
|
||||
return event
|
||||
}
|
||||
|
||||
def off() {
|
||||
@@ -132,6 +150,43 @@ def configure() {
|
||||
sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
|
||||
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||
refresh() + zigbee.onOffConfig(0, 300) + zigbee.electricMeasurementPowerConfig()
|
||||
refresh() + zigbee.onOffConfig(0, 300) + powerConfig()
|
||||
}
|
||||
|
||||
//power config for devices with min reporting interval as 1 seconds and reporting interval if no activity as 10min (600s)
|
||||
//min change in value is 01
|
||||
def powerConfig() {
|
||||
[
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x0B04 {${device.zigbeeId}} {}", "delay 2000",
|
||||
"zcl global send-me-a-report 0x0B04 0x050B 0x29 1 600 {05 00}", //The send-me-a-report is custom to the attribute type for CentraLite
|
||||
"delay 200",
|
||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000"
|
||||
]
|
||||
}
|
||||
|
||||
private getEndpointId() {
|
||||
new BigInteger(device.endpointId, 16).toString()
|
||||
}
|
||||
|
||||
//TODO: Remove this after getKnownDescription can parse it automatically
|
||||
def getPowerDescription(descMap) {
|
||||
def powerValue = "undefined"
|
||||
if (descMap.cluster == "0B04") {
|
||||
if (descMap.attrId == "050b") {
|
||||
if(descMap.value!="ffff")
|
||||
powerValue = zigbee.convertHexToInt(descMap.value)
|
||||
}
|
||||
}
|
||||
else if (descMap.clusterId == "0B04") {
|
||||
if(descMap.command=="07"){
|
||||
return [type: "update", value : "power (0B04) capability configured successfully"]
|
||||
}
|
||||
}
|
||||
|
||||
if (powerValue != "undefined"){
|
||||
return [type: "power", value : powerValue]
|
||||
}
|
||||
else {
|
||||
return [:]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ def parse(String description) {
|
||||
log.debug "parse($description)"
|
||||
def results = [:]
|
||||
|
||||
if (!isSupportedDescription(description) || description.startsWith("zone")) {
|
||||
if (!isSupportedDescription(description) || zigbee.isZoneType19(description)) {
|
||||
// Ignore this in favor of orientation-based state
|
||||
// results = parseSingleMessage(description)
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ def parse(String description) {
|
||||
log.debug "parse($description)"
|
||||
def results = null
|
||||
|
||||
if (!isSupportedDescription(description) || description.startsWith("zone")) {
|
||||
if (!isSupportedDescription(description) || zigbee.isZoneType19(description)) {
|
||||
// Ignore this in favor of orientation-based state
|
||||
// results = parseSingleMessage(description)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
|
||||
|
||||
|
||||
metadata {
|
||||
definition(name: "SmartSense Moisture Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||
definition (name: "SmartSense Moisture Sensor",namespace: "smartthings", author: "SmartThings") {
|
||||
capability "Configuration"
|
||||
capability "Battery"
|
||||
capability "Refresh"
|
||||
@@ -43,10 +43,10 @@ metadata {
|
||||
preferences {
|
||||
section {
|
||||
image(name: 'educationalcontent', multiple: true, images: [
|
||||
"http://cdn.device-gse.smartthings.com/Moisture/Moisture1.png",
|
||||
"http://cdn.device-gse.smartthings.com/Moisture/Moisture2.png",
|
||||
"http://cdn.device-gse.smartthings.com/Moisture/Moisture3.png"
|
||||
])
|
||||
"http://cdn.device-gse.smartthings.com/Moisture/Moisture1.png",
|
||||
"http://cdn.device-gse.smartthings.com/Moisture/Moisture2.png",
|
||||
"http://cdn.device-gse.smartthings.com/Moisture/Moisture3.png"
|
||||
])
|
||||
}
|
||||
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"
|
||||
@@ -55,32 +55,32 @@ metadata {
|
||||
}
|
||||
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name: "water", type: "generic", width: 6, height: 4) {
|
||||
tileAttribute("device.water", key: "PRIMARY_CONTROL") {
|
||||
attributeState "dry", label: "Dry", icon: "st.alarm.water.dry", backgroundColor: "#ffffff"
|
||||
attributeState "wet", label: "Wet", icon: "st.alarm.water.wet", backgroundColor: "#53a7c0"
|
||||
multiAttributeTile(name:"water", type: "generic", width: 6, height: 4){
|
||||
tileAttribute ("device.water", key: "PRIMARY_CONTROL") {
|
||||
attributeState "dry", label: "Dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
|
||||
attributeState "wet", label: "Wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
|
||||
}
|
||||
}
|
||||
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "temperature", label: '${currentValue}°',
|
||||
backgroundColors: [
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
state "temperature", label:'${currentValue}°',
|
||||
backgroundColors:[
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
}
|
||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "battery", label: '${currentValue}% battery', unit: ""
|
||||
state "battery", label:'${currentValue}% battery', unit:""
|
||||
}
|
||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||
state "default", action: "refresh.refresh", icon: "st.secondary.refresh"
|
||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
main(["water", "temperature"])
|
||||
main (["water", "temperature"])
|
||||
details(["water", "temperature", "battery", "refresh"])
|
||||
}
|
||||
}
|
||||
@@ -88,43 +88,117 @@ metadata {
|
||||
def parse(String description) {
|
||||
log.debug "description: $description"
|
||||
|
||||
// getEvent will handle temperature and humidity
|
||||
Map map = zigbee.getEvent(description)
|
||||
if (!map) {
|
||||
if (description?.startsWith('zone status')) {
|
||||
map = parseIasMessage(description)
|
||||
} else {
|
||||
Map descMap = zigbee.parseDescriptionAsMap(description)
|
||||
if (descMap.clusterInt == 0x0001 && descMap.commandInt != 0x07 && descMap?.value) {
|
||||
map = getBatteryResult(Integer.parseInt(descMap.value, 16))
|
||||
} else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
|
||||
if (descMap.data[0] == "00") {
|
||||
log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap"
|
||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
} else {
|
||||
log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
|
||||
}
|
||||
}
|
||||
}
|
||||
Map map = [:]
|
||||
if (description?.startsWith('catchall:')) {
|
||||
map = parseCatchAllMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('read attr -')) {
|
||||
map = parseReportAttributeMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('temperature: ')) {
|
||||
map = parseCustomMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('zone status')) {
|
||||
map = parseIasMessage(description)
|
||||
}
|
||||
|
||||
log.debug "Parse returned $map"
|
||||
def result = map ? createEvent(map) : [:]
|
||||
|
||||
if (description?.startsWith('enroll request')) {
|
||||
List cmds = zigbee.enrollResponse()
|
||||
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:
|
||||
// 0x07 - configure reporting
|
||||
if (cluster.command != 0x07) {
|
||||
resultMap = getBatteryResult(cluster.data.last())
|
||||
}
|
||||
break
|
||||
|
||||
case 0x0402:
|
||||
if (cluster.command == 0x07) {
|
||||
if (cluster.data[0] == 0x00){
|
||||
log.debug "TEMP REPORTING CONFIG RESPONSE" + cluster
|
||||
resultMap = [name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]]
|
||||
}
|
||||
else {
|
||||
log.warn "TEMP REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 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
|
||||
}
|
||||
|
||||
private boolean shouldProcessMessage(cluster) {
|
||||
// 0x0B is default response indicating message got through
|
||||
boolean ignoredMessage = cluster.profileId != 0x0104 ||
|
||||
cluster.command == 0x0B ||
|
||||
(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)
|
||||
resultMap = getTemperatureResult(value)
|
||||
}
|
||||
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: ')) {
|
||||
def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())
|
||||
resultMap = getTemperatureResult(value)
|
||||
}
|
||||
return resultMap
|
||||
}
|
||||
|
||||
private Map parseIasMessage(String description) {
|
||||
ZoneStatus zs = zigbee.parseZoneStatus(description)
|
||||
|
||||
return zs.isAlarm1Set() ? getMoistureResult('wet') : getMoistureResult('dry')
|
||||
}
|
||||
|
||||
def getTemperature(value) {
|
||||
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
||||
if(getTemperatureScale() == "C"){
|
||||
return Math.round(celsius)
|
||||
} else {
|
||||
return Math.round(celsiusToFahrenheit(celsius))
|
||||
}
|
||||
}
|
||||
|
||||
private Map getBatteryResult(rawValue) {
|
||||
log.debug "Battery rawValue = ${rawValue}"
|
||||
def linkText = getLinkText(device)
|
||||
@@ -165,18 +239,40 @@ private Map getBatteryResult(rawValue) {
|
||||
return result
|
||||
}
|
||||
|
||||
private Map getTemperatureResult(value) {
|
||||
log.debug 'TEMP'
|
||||
if (tempOffset) {
|
||||
def offset = tempOffset as int
|
||||
def v = value as int
|
||||
value = v + offset
|
||||
}
|
||||
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,
|
||||
translatable: true,
|
||||
unit: temperatureScale
|
||||
]
|
||||
}
|
||||
|
||||
private Map getMoistureResult(value) {
|
||||
log.debug "water"
|
||||
def descriptionText
|
||||
if (value == "wet")
|
||||
descriptionText = '{{ device.displayName }} is wet'
|
||||
else
|
||||
descriptionText = '{{ device.displayName }} is dry'
|
||||
def descriptionText
|
||||
if ( value == "wet" )
|
||||
descriptionText = '{{ device.displayName }} is wet'
|
||||
else
|
||||
descriptionText = '{{ device.displayName }} is dry'
|
||||
return [
|
||||
name : 'water',
|
||||
value : value,
|
||||
descriptionText: descriptionText,
|
||||
translatable : true
|
||||
name: 'water',
|
||||
value: value,
|
||||
descriptionText: descriptionText,
|
||||
translatable: true
|
||||
]
|
||||
}
|
||||
|
||||
@@ -189,10 +285,12 @@ def ping() {
|
||||
|
||||
def refresh() {
|
||||
log.debug "Refreshing Temperature and Battery"
|
||||
def refreshCmds = zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) +
|
||||
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020)
|
||||
def refreshCmds = [
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 2000",
|
||||
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 2000"
|
||||
]
|
||||
|
||||
return refreshCmds + zigbee.enrollResponse()
|
||||
return refreshCmds + enrollResponse()
|
||||
}
|
||||
|
||||
def configure() {
|
||||
@@ -204,3 +302,42 @@ def configure() {
|
||||
// battery minReport 30 seconds, maxReportTime 6 hrs by default
|
||||
return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // 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 2000",
|
||||
//Enroll Response
|
||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
||||
"send 0x${device.deviceNetworkId} 1 1", "delay 2000"
|
||||
]
|
||||
}
|
||||
|
||||
private getEndpointId() {
|
||||
new BigInteger(device.endpointId, 16).toString()
|
||||
}
|
||||
|
||||
private hex(value) {
|
||||
new BigInteger(Math.round(value).toString()).toString(16)
|
||||
}
|
||||
|
||||
private String swapEndianHex(String hex) {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
|
||||
|
||||
|
||||
metadata {
|
||||
definition(name: "SmartSense Motion Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||
definition (name: "SmartSense Motion Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||
capability "Motion Sensor"
|
||||
capability "Configuration"
|
||||
capability "Battery"
|
||||
@@ -45,10 +45,10 @@ metadata {
|
||||
preferences {
|
||||
section {
|
||||
image(name: 'educationalcontent', multiple: true, images: [
|
||||
"http://cdn.device-gse.smartthings.com/Motion/Motion1.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Motion/Motion2.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Motion/Motion3.jpg"
|
||||
])
|
||||
"http://cdn.device-gse.smartthings.com/Motion/Motion1.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Motion/Motion2.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Motion/Motion3.jpg"
|
||||
])
|
||||
}
|
||||
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"
|
||||
@@ -57,30 +57,30 @@ metadata {
|
||||
}
|
||||
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name: "motion", type: "generic", width: 6, height: 4) {
|
||||
tileAttribute("device.motion", key: "PRIMARY_CONTROL") {
|
||||
attributeState "active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#53a7c0"
|
||||
attributeState "inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#ffffff"
|
||||
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
|
||||
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
|
||||
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
||||
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
||||
}
|
||||
}
|
||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||
state("temperature", label: '${currentValue}°', unit: "F",
|
||||
backgroundColors: [
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
state("temperature", label:'${currentValue}°', unit:"F",
|
||||
backgroundColors:[
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
)
|
||||
}
|
||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "battery", label: '${currentValue}% battery', unit: ""
|
||||
state "battery", label:'${currentValue}% battery', unit:""
|
||||
}
|
||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||
state "default", action: "refresh.refresh", icon: "st.secondary.refresh"
|
||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
main(["motion", "temperature"])
|
||||
@@ -90,40 +90,116 @@ metadata {
|
||||
|
||||
def parse(String description) {
|
||||
log.debug "description: $description"
|
||||
Map map = zigbee.getEvent(description)
|
||||
if (!map) {
|
||||
if (description?.startsWith('zone status')) {
|
||||
map = parseIasMessage(description)
|
||||
} else {
|
||||
Map descMap = zigbee.parseDescriptionAsMap(description)
|
||||
if (descMap?.clusterInt == 0x0001 && descMap.commandInt != 0x07 && descMap?.value) {
|
||||
map = getBatteryResult(Integer.parseInt(descMap.value, 16))
|
||||
} else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
|
||||
if (descMap.data[0] == "00") {
|
||||
log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap"
|
||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
} else {
|
||||
log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
|
||||
}
|
||||
} else if (descMap.clusterInt == 0x0406 && descMap.attrInt == 0x0000) {
|
||||
def value = descMap.value.endsWith("01") ? "active" : "inactive"
|
||||
log.warn "Doing a read attr motion event"
|
||||
resultMap = getMotionResult(value)
|
||||
}
|
||||
}
|
||||
|
||||
Map map = [:]
|
||||
if (description?.startsWith('catchall:')) {
|
||||
map = parseCatchAllMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('read attr -')) {
|
||||
map = parseReportAttributeMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('temperature: ')) {
|
||||
map = parseCustomMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('zone status')) {
|
||||
map = parseIasMessage(description)
|
||||
}
|
||||
|
||||
log.debug "Parse returned $map"
|
||||
def result = map ? createEvent(map) : [:]
|
||||
|
||||
if (description?.startsWith('enroll request')) {
|
||||
List cmds = zigbee.enrollResponse()
|
||||
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:
|
||||
// 0x07 - configure reporting
|
||||
if (cluster.command != 0x07) {
|
||||
resultMap = getBatteryResult(cluster.data.last())
|
||||
}
|
||||
break
|
||||
|
||||
case 0x0402:
|
||||
if (cluster.command == 0x07) {
|
||||
if (cluster.data[0] == 0x00) {
|
||||
log.debug "TEMP REPORTING CONFIG RESPONSE" + cluster
|
||||
resultMap = [name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]]
|
||||
}
|
||||
else {
|
||||
log.warn "TEMP REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
// 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 0x0406:
|
||||
// 0x07 - configure reporting
|
||||
if (cluster.command != 0x07) {
|
||||
log.debug 'motion'
|
||||
resultMap.name = 'motion'
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return resultMap
|
||||
}
|
||||
|
||||
private boolean shouldProcessMessage(cluster) {
|
||||
// 0x0B is default response indicating message got through
|
||||
boolean ignoredMessage = cluster.profileId != 0x0104 ||
|
||||
cluster.command == 0x0B ||
|
||||
(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)
|
||||
resultMap = getTemperatureResult(value)
|
||||
}
|
||||
else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
|
||||
resultMap = getBatteryResult(Integer.parseInt(descMap.value, 16))
|
||||
}
|
||||
else if (descMap.cluster == "0406" && descMap.attrId == "0000") {
|
||||
def value = descMap.value.endsWith("01") ? "active" : "inactive"
|
||||
resultMap = getMotionResult(value)
|
||||
}
|
||||
|
||||
return resultMap
|
||||
}
|
||||
|
||||
private Map parseCustomMessage(String description) {
|
||||
Map resultMap = [:]
|
||||
if (description?.startsWith('temperature: ')) {
|
||||
def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())
|
||||
resultMap = getTemperatureResult(value)
|
||||
}
|
||||
return resultMap
|
||||
}
|
||||
|
||||
private Map parseIasMessage(String description) {
|
||||
ZoneStatus zs = zigbee.parseZoneStatus(description)
|
||||
|
||||
@@ -131,6 +207,15 @@ private Map parseIasMessage(String description) {
|
||||
return (zs.isAlarm1Set() || zs.isAlarm2Set()) ? getMotionResult('active') : getMotionResult('inactive')
|
||||
}
|
||||
|
||||
def getTemperature(value) {
|
||||
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
||||
if(getTemperatureScale() == "C"){
|
||||
return Math.round(celsius)
|
||||
} else {
|
||||
return Math.round(celsiusToFahrenheit(celsius))
|
||||
}
|
||||
}
|
||||
|
||||
private Map getBatteryResult(rawValue) {
|
||||
log.debug "Battery rawValue = ${rawValue}"
|
||||
def linkText = getLinkText(device)
|
||||
@@ -170,14 +255,36 @@ private Map getBatteryResult(rawValue) {
|
||||
return result
|
||||
}
|
||||
|
||||
private Map getTemperatureResult(value) {
|
||||
log.debug 'TEMP'
|
||||
if (tempOffset) {
|
||||
def offset = tempOffset as int
|
||||
def v = value as int
|
||||
value = v + offset
|
||||
}
|
||||
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,
|
||||
translatable: true,
|
||||
unit: temperatureScale
|
||||
]
|
||||
}
|
||||
|
||||
private Map getMotionResult(value) {
|
||||
log.debug 'motion'
|
||||
String descriptionText = value == 'active' ? "{{ device.displayName }} detected motion" : "{{ device.displayName }} motion has stopped"
|
||||
return [
|
||||
name : 'motion',
|
||||
value : value,
|
||||
descriptionText: descriptionText,
|
||||
translatable : true
|
||||
name: 'motion',
|
||||
value: value,
|
||||
descriptionText: descriptionText,
|
||||
translatable: true
|
||||
]
|
||||
}
|
||||
|
||||
@@ -185,16 +292,17 @@ private Map getMotionResult(value) {
|
||||
* PING is used by Device-Watch in attempt to reach the Device
|
||||
* */
|
||||
def ping() {
|
||||
return zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) // Read the Battery Level
|
||||
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
log.debug "refresh called"
|
||||
def refreshCmds = [
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 2000",
|
||||
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 2000"
|
||||
]
|
||||
|
||||
def refreshCmds = zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) +
|
||||
zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000)
|
||||
|
||||
return refreshCmds + zigbee.enrollResponse()
|
||||
return refreshCmds + enrollResponse()
|
||||
}
|
||||
|
||||
def configure() {
|
||||
@@ -206,3 +314,42 @@ def configure() {
|
||||
// battery minReport 30 seconds, maxReportTime 6 hrs by default
|
||||
return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // 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 2000",
|
||||
//Enroll Response
|
||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
||||
"send 0x${device.deviceNetworkId} 1 1", "delay 2000"
|
||||
]
|
||||
}
|
||||
|
||||
private getEndpointId() {
|
||||
new BigInteger(device.endpointId, 16).toString()
|
||||
}
|
||||
|
||||
private hex(value) {
|
||||
new BigInteger(Math.round(value).toString()).toString(16)
|
||||
}
|
||||
|
||||
private String swapEndianHex(String hex) {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ metadata {
|
||||
|
||||
def parse(String description) {
|
||||
def results = [:]
|
||||
if (description.startsWith("zone") || !isSupportedDescription(description)) {
|
||||
if (isZoneType19(description) || !isSupportedDescription(description)) {
|
||||
results = parseBasicMessage(description)
|
||||
}
|
||||
else if (isMotionStatusMessage(description)){
|
||||
@@ -87,12 +87,16 @@ private String parseName(String description) {
|
||||
}
|
||||
|
||||
private String parseValue(String description) {
|
||||
def zs = zigbee.parseZoneStatus(description)
|
||||
if (zs) {
|
||||
zs.isAlarm1Set() ? "active" : "inactive"
|
||||
} else {
|
||||
description
|
||||
if (isZoneType19(description)) {
|
||||
if (translateStatusZoneType19(description)) {
|
||||
return "active"
|
||||
}
|
||||
else {
|
||||
return "inactive"
|
||||
}
|
||||
}
|
||||
|
||||
description
|
||||
}
|
||||
|
||||
private parseDescriptionText(String linkText, String value, String description) {
|
||||
|
||||
@@ -14,23 +14,22 @@
|
||||
* under the License.
|
||||
*/
|
||||
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
|
||||
import physicalgraph.zigbee.zcl.DataType
|
||||
|
||||
metadata {
|
||||
definition(name: "SmartSense Multi Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||
definition (name: "SmartSense Multi Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||
|
||||
capability "Three Axis"
|
||||
capability "Battery"
|
||||
capability "Configuration"
|
||||
capability "Sensor"
|
||||
capability "Contact Sensor"
|
||||
capability "Acceleration Sensor"
|
||||
capability "Refresh"
|
||||
capability "Temperature Measurement"
|
||||
capability "Contact Sensor"
|
||||
capability "Acceleration Sensor"
|
||||
capability "Refresh"
|
||||
capability "Temperature Measurement"
|
||||
capability "Health Check"
|
||||
|
||||
command "enrollResponse"
|
||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320"
|
||||
command "enrollResponse"
|
||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320"
|
||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321"
|
||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321-S", deviceJoinName: "Multipurpose Sensor"
|
||||
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500,FC02", outClusters: "0019", manufacturer: "SmartThings", model: "multiv4", deviceJoinName: "Multipurpose Sensor"
|
||||
@@ -58,11 +57,11 @@ metadata {
|
||||
preferences {
|
||||
section {
|
||||
image(name: 'educationalcontent', multiple: true, images: [
|
||||
"http://cdn.device-gse.smartthings.com/Multi/Multi1.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Multi/Multi2.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Multi/Multi3.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Multi/Multi4.jpg"
|
||||
])
|
||||
"http://cdn.device-gse.smartthings.com/Multi/Multi1.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Multi/Multi2.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Multi/Multi3.jpg",
|
||||
"http://cdn.device-gse.smartthings.com/Multi/Multi4.jpg"
|
||||
])
|
||||
}
|
||||
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"
|
||||
@@ -74,170 +73,211 @@ metadata {
|
||||
}
|
||||
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name: "status", type: "generic", width: 6, height: 4) {
|
||||
tileAttribute("device.status", key: "PRIMARY_CONTROL") {
|
||||
attributeState "open", label: 'Open', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
|
||||
attributeState "closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
|
||||
attributeState "garage-open", label: 'Open', icon: "st.doors.garage.garage-open", backgroundColor: "#ffa81e"
|
||||
attributeState "garage-closed", label: 'Closed', icon: "st.doors.garage.garage-closed", backgroundColor: "#79b821"
|
||||
multiAttributeTile(name:"status", type: "generic", width: 6, height: 4){
|
||||
tileAttribute ("device.status", key: "PRIMARY_CONTROL") {
|
||||
attributeState "open", label:'Open', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
|
||||
attributeState "closed", label:'Closed', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
|
||||
attributeState "garage-open", label:'Open', icon:"st.doors.garage.garage-open", backgroundColor:"#ffa81e"
|
||||
attributeState "garage-closed", label:'Closed', icon:"st.doors.garage.garage-closed", backgroundColor:"#79b821"
|
||||
}
|
||||
}
|
||||
standardTile("contact", "device.contact", width: 2, height: 2) {
|
||||
state("open", label: 'Open', icon: "st.contact.contact.open", backgroundColor: "#ffa81e")
|
||||
state("closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#79b821")
|
||||
state("open", label:'Open', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
||||
state("closed", label:'Closed', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
||||
}
|
||||
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
|
||||
state("active", label: 'Active', icon: "st.motion.acceleration.active", backgroundColor: "#53a7c0")
|
||||
state("inactive", label: 'Inactive', icon: "st.motion.acceleration.inactive", backgroundColor: "#ffffff")
|
||||
state("active", label:'Active', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
|
||||
state("inactive", label:'Inactive', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
|
||||
}
|
||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||
state("temperature", label: '${currentValue}°',
|
||||
backgroundColors: [
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
state("temperature", label:'${currentValue}°',
|
||||
backgroundColors:[
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
)
|
||||
}
|
||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "battery", label: '${currentValue}% battery', unit: ""
|
||||
state "battery", label:'${currentValue}% battery', unit:""
|
||||
}
|
||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||
state "default", action: "refresh.refresh", icon: "st.secondary.refresh"
|
||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
|
||||
main(["status", "acceleration", "temperature"])
|
||||
details(["status", "acceleration", "temperature", "battery", "refresh"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def parse(String description) {
|
||||
def maps = []
|
||||
maps << zigbee.getEvent(description)
|
||||
if (!maps[0]) {
|
||||
maps = []
|
||||
if (description?.startsWith('zone status')) {
|
||||
maps += parseIasMessage(description)
|
||||
} else {
|
||||
Map descMap = zigbee.parseDescriptionAsMap(description)
|
||||
if (descMap?.clusterInt == 0x0001 && descMap.commandInt != 0x07 && descMap?.value) {
|
||||
maps << getBatteryResult(Integer.parseInt(descMap.value, 16))
|
||||
} else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
|
||||
if (descMap.data[0] == "00") {
|
||||
log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap"
|
||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
} else {
|
||||
log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
|
||||
}
|
||||
} else {
|
||||
|
||||
maps += handleAcceleration(descMap)
|
||||
}
|
||||
}
|
||||
} else if (maps[0].name == "temperature") {
|
||||
def map = maps[0]
|
||||
if (tempOffset) {
|
||||
map.value = (int) map.value + (int) tempOffset
|
||||
}
|
||||
map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F'
|
||||
map.translatable = true
|
||||
Map map = [:]
|
||||
if (description?.startsWith('catchall:')) {
|
||||
map = parseCatchAllMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('temperature: ')) {
|
||||
map = parseCustomMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('zone status')) {
|
||||
map = parseIasMessage(description)
|
||||
}
|
||||
|
||||
def result = maps.inject([]) {acc, it ->
|
||||
if (it) {
|
||||
acc << createEvent(it)
|
||||
}
|
||||
}
|
||||
def result = map ? createEvent(map) : [:]
|
||||
|
||||
if (description?.startsWith('enroll request')) {
|
||||
List cmds = zigbee.enrollResponse()
|
||||
List cmds = enrollResponse()
|
||||
log.debug "enroll response: ${cmds}"
|
||||
result = cmds?.collect { new physicalgraph.device.HubAction(it) }
|
||||
}
|
||||
else if (description?.startsWith('read attr -')) {
|
||||
result = parseReportAttributeMessage(description).each { createEvent(it) }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private List<Map> handleAcceleration(descMap) {
|
||||
def result = []
|
||||
if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0010) {
|
||||
def value = descMap.value == "01" ? "active" : "inactive"
|
||||
log.debug "Acceleration $value"
|
||||
result << [
|
||||
name : "acceleration",
|
||||
value : value,
|
||||
descriptionText: "{{ device.displayName }} was $value",
|
||||
isStateChange : isStateChange(device, "acceleration", value),
|
||||
translatable : true
|
||||
]
|
||||
private Map parseCatchAllMessage(String description) {
|
||||
Map resultMap = [:]
|
||||
def cluster = zigbee.parse(description)
|
||||
log.debug cluster
|
||||
if (shouldProcessMessage(cluster)) {
|
||||
switch(cluster.clusterId) {
|
||||
case 0x0001:
|
||||
// 0x07 - configure reporting
|
||||
if (cluster.command != 0x07) {
|
||||
resultMap = getBatteryResult(cluster.data.last())
|
||||
}
|
||||
break
|
||||
|
||||
if (descMap.additionalAttrs) {
|
||||
result += parseAxis(descMap.additionalAttrs)
|
||||
case 0xFC02:
|
||||
log.debug 'ACCELERATION'
|
||||
break
|
||||
|
||||
case 0x0402:
|
||||
if (cluster.command == 0x07) {
|
||||
if(cluster.data[0] == 0x00) {
|
||||
log.debug "TEMP REPORTING CONFIG RESPONSE" + cluster
|
||||
resultMap = [name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]]
|
||||
}
|
||||
else {
|
||||
log.warn "TEMP REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 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
|
||||
}
|
||||
} else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012) {
|
||||
def addAttrs = descMap.additionalAttrs
|
||||
addAttrs << ["attrInt": descMap.attrInt, "value": descMap.value]
|
||||
result += parseAxis(addAttrs)
|
||||
}
|
||||
|
||||
return resultMap
|
||||
}
|
||||
|
||||
private boolean shouldProcessMessage(cluster) {
|
||||
// 0x0B is default response indicating message got through
|
||||
boolean ignoredMessage = cluster.profileId != 0x0104 ||
|
||||
cluster.command == 0x0B ||
|
||||
(cluster.data.size() > 0 && cluster.data.first() == 0x3e)
|
||||
return !ignoredMessage
|
||||
}
|
||||
|
||||
private List parseReportAttributeMessage(String description) {
|
||||
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
||||
def nameAndValue = param.split(":")
|
||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
||||
}
|
||||
|
||||
List result = []
|
||||
if (descMap.cluster == "0402" && descMap.attrId == "0000") {
|
||||
def value = getTemperature(descMap.value)
|
||||
result << getTemperatureResult(value)
|
||||
}
|
||||
else if (descMap.cluster == "FC02" && descMap.attrId == "0010") {
|
||||
if (descMap.value.size() == 32) {
|
||||
// value will look like 00ae29001403e2290013001629001201
|
||||
// breaking this apart and swapping byte order where appropriate, this breaks down to:
|
||||
// X (0x0012) = 0x0016
|
||||
// Y (0x0013) = 0x03E2
|
||||
// Z (0x0014) = 0x00AE
|
||||
// note that there is a known bug in that the x,y,z attributes are interpreted in the wrong order
|
||||
// this will be fixed in a future update
|
||||
def threeAxisAttributes = descMap.value[0..-9]
|
||||
result << parseAxis(threeAxisAttributes)
|
||||
descMap.value = descMap.value[-2..-1]
|
||||
}
|
||||
result << getAccelerationResult(descMap.value)
|
||||
}
|
||||
else if (descMap.cluster == "FC02" && descMap.attrId == "0012" && descMap.value.size() == 24) {
|
||||
// The size is checked to ensure the attribute report contains X, Y and Z values
|
||||
// If all three axis are not included then the attribute report is ignored
|
||||
result << parseAxis(descMap.value)
|
||||
}
|
||||
else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
|
||||
result << getBatteryResult(Integer.parseInt(descMap.value, 16))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private List<Map> parseAxis(List<Map> attrData) {
|
||||
def results = []
|
||||
def x = hexToSignedInt(attrData.find { it.attrInt == 0x0012 }?.value)
|
||||
def y = hexToSignedInt(attrData.find { it.attrInt == 0x0013 }?.value)
|
||||
def z = hexToSignedInt(attrData.find { it.attrInt == 0x0014 }?.value)
|
||||
|
||||
def xyzResults = [:]
|
||||
if (device.getDataValue("manufacturer") == "SmartThings") {
|
||||
// This mapping matches the current behavior of the Device Handler for the Centralite sensors
|
||||
xyzResults.x = z
|
||||
xyzResults.y = y
|
||||
xyzResults.z = -x
|
||||
} else {
|
||||
// The axises reported by the Device Handler differ from the axises reported by the sensor
|
||||
// This may change in the future
|
||||
xyzResults.x = z
|
||||
xyzResults.y = x
|
||||
xyzResults.z = y
|
||||
private Map parseCustomMessage(String description) {
|
||||
Map resultMap = [:]
|
||||
if (description?.startsWith('temperature: ')) {
|
||||
def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())
|
||||
resultMap = getTemperatureResult(value)
|
||||
}
|
||||
|
||||
log.debug "parseAxis -- ${xyzResults}"
|
||||
|
||||
if (garageSensor == "Yes")
|
||||
results += garageEvent(xyzResults.z)
|
||||
|
||||
def value = "${xyzResults.x},${xyzResults.y},${xyzResults.z}"
|
||||
results << [
|
||||
name : "threeAxis",
|
||||
value : value,
|
||||
linkText : getLinkText(device),
|
||||
descriptionText: "${getLinkText(device)} was ${value}",
|
||||
handlerName : name,
|
||||
isStateChange : isStateChange(device, "threeAxis", value),
|
||||
displayed : false
|
||||
]
|
||||
results
|
||||
return resultMap
|
||||
}
|
||||
|
||||
private List<Map> parseIasMessage(String description) {
|
||||
private Map parseIasMessage(String description) {
|
||||
ZoneStatus zs = zigbee.parseZoneStatus(description)
|
||||
List<Map> results = []
|
||||
Map resultMap = [:]
|
||||
|
||||
if (garageSensor != "Yes") {
|
||||
def value = zs.isAlarm1Set() ? 'open' : 'closed'
|
||||
log.debug "Contact: ${device.displayName} value = ${value}"
|
||||
def descriptionText = value == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed'
|
||||
results << [name: 'contact', value: value, descriptionText: descriptionText, displayed: false, translatable: true]
|
||||
results << [name: 'status', value: value, descriptionText: descriptionText, translatable: true]
|
||||
}
|
||||
if (garageSensor != "Yes"){
|
||||
resultMap = zs.isAlarm1Set() ? getContactResult('open') : getContactResult('closed')
|
||||
}
|
||||
|
||||
return results
|
||||
return resultMap
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "updated called"
|
||||
log.info "garage value : $garageSensor"
|
||||
if (garageSensor == "Yes") {
|
||||
def descriptionText = "Updating device to garage sensor"
|
||||
if (device.latestValue("status") == "open") {
|
||||
sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true)
|
||||
}
|
||||
else if (device.latestValue("status") == "closed") {
|
||||
sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true)
|
||||
}
|
||||
}
|
||||
else {
|
||||
def descriptionText = "Updating device to open/close sensor"
|
||||
if (device.latestValue("status") == "garage-open") {
|
||||
sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true)
|
||||
}
|
||||
else if (device.latestValue("status") == "garage-closed") {
|
||||
sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def getTemperature(value) {
|
||||
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
||||
if(getTemperatureScale() == "C"){
|
||||
return Math.round(celsius)
|
||||
} else {
|
||||
return Math.round(celsiusToFahrenheit(celsius))
|
||||
}
|
||||
}
|
||||
|
||||
private Map getBatteryResult(rawValue) {
|
||||
log.debug "Battery rawValue = ${rawValue}"
|
||||
|
||||
@@ -276,24 +316,54 @@ private Map getBatteryResult(rawValue) {
|
||||
return result
|
||||
}
|
||||
|
||||
List<Map> garageEvent(zValue) {
|
||||
List<Map> results = []
|
||||
def absValue = zValue.abs()
|
||||
def contactValue = null
|
||||
def garageValue = null
|
||||
if (absValue > 900) {
|
||||
contactValue = 'closed'
|
||||
garageValue = 'garage-closed'
|
||||
} else if (absValue < 100) {
|
||||
contactValue = 'open'
|
||||
garageValue = 'garage-open'
|
||||
private Map getTemperatureResult(value) {
|
||||
log.debug "Temperature"
|
||||
if (tempOffset) {
|
||||
def offset = tempOffset as int
|
||||
def v = value as int
|
||||
value = v + offset
|
||||
}
|
||||
if (contactValue != null) {
|
||||
def descriptionText = contactValue == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed'
|
||||
results << [name: 'contact', value: contactValue, descriptionText: descriptionText, displayed: false, translatable: true]
|
||||
results << [name: 'status', value: garageValue, descriptionText: descriptionText, translatable: true]
|
||||
}
|
||||
results
|
||||
def descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C':
|
||||
'{{ device.displayName }} was {{ value }}°F'
|
||||
|
||||
return [
|
||||
name: 'temperature',
|
||||
value: value,
|
||||
descriptionText: descriptionText,
|
||||
translatable: true,
|
||||
unit: temperatureScale
|
||||
]
|
||||
}
|
||||
|
||||
private Map getContactResult(value) {
|
||||
log.debug "Contact: ${device.displayName} value = ${value}"
|
||||
def descriptionText = value == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed'
|
||||
sendEvent(name: 'contact', value: value, descriptionText: descriptionText, displayed: false, translatable: true)
|
||||
return [name: 'status', value: value, descriptionText: descriptionText, translatable: true]
|
||||
}
|
||||
|
||||
private getAccelerationResult(numValue) {
|
||||
log.debug "Acceleration"
|
||||
def name = "acceleration"
|
||||
def value
|
||||
def descriptionText
|
||||
|
||||
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)
|
||||
return [
|
||||
name: name,
|
||||
value: value,
|
||||
descriptionText: descriptionText,
|
||||
isStateChange: isStateChange,
|
||||
translatable: true
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -306,21 +376,7 @@ def ping() {
|
||||
def refresh() {
|
||||
log.debug "Refreshing Values "
|
||||
|
||||
def refreshCmds = zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) +
|
||||
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) +
|
||||
zigbee.readAttribute(0xFC02, 0x0010, [mfgCode: manufacturerCode]) +
|
||||
zigbee.enrollResponse()
|
||||
|
||||
return refreshCmds
|
||||
}
|
||||
|
||||
def configure() {
|
||||
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
||||
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
|
||||
log.debug "Configuring Reporting"
|
||||
def configCmds = []
|
||||
def refreshCmds = []
|
||||
|
||||
if (device.getDataValue("manufacturer") == "SmartThings") {
|
||||
log.debug "Refreshing Values for manufacturer: SmartThings "
|
||||
@@ -329,45 +385,81 @@ def configure() {
|
||||
Separating these out in a separate if-else because I do not want to touch Centralite part
|
||||
as of now.
|
||||
*/
|
||||
configCmds += zigbee.writeAttribute(0xFC02, 0x0000, 0x20, 0x01, [mfgCode: manufacturerCode])
|
||||
configCmds += zigbee.writeAttribute(0xFC02, 0x0002, 0x21, 0x0276, [mfgCode: manufacturerCode])
|
||||
refreshCmds += zigbee.writeAttribute(0xFC02, 0x0000, 0x20, 0x01, [mfgCode: manufacturerCode])
|
||||
refreshCmds += zigbee.writeAttribute(0xFC02, 0x0002, 0x21, 0x0276, [mfgCode: manufacturerCode])
|
||||
} else {
|
||||
// Write a motion threshold of 2 * .063g = .126g
|
||||
// Currently due to a Centralite firmware issue, this will cause a read attribute response that
|
||||
// indicates acceleration even when there isn't.
|
||||
configCmds += zigbee.writeAttribute(0xFC02, 0x0000, 0x20, 0x02, [mfgCode: manufacturerCode])
|
||||
refreshCmds += zigbee.writeAttribute(0xFC02, 0x0000, 0x20, 0x02, [mfgCode: manufacturerCode])
|
||||
}
|
||||
|
||||
//Common refresh commands
|
||||
refreshCmds += zigbee.readAttribute(0x0402, 0x0000) +
|
||||
zigbee.readAttribute(0x0001, 0x0020) +
|
||||
zigbee.readAttribute(0xFC02, 0x0010, [mfgCode: manufacturerCode])
|
||||
|
||||
return refreshCmds + enrollResponse()
|
||||
}
|
||||
|
||||
def configure() {
|
||||
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
|
||||
// enrolls with default periodic reporting until newer 5 min interval is confirmed
|
||||
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
|
||||
log.debug "Configuring Reporting"
|
||||
|
||||
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||
// battery minReport 30 seconds, maxReportTime 6 hrs by default
|
||||
configCmds += zigbee.batteryConfig() +
|
||||
def configCmds = zigbee.batteryConfig() +
|
||||
zigbee.temperatureConfig(30, 300) +
|
||||
zigbee.configureReporting(0xFC02, 0x0010, DataType.BITMAP8, 10, 3600, 0x01, [mfgCode: manufacturerCode]) +
|
||||
zigbee.configureReporting(0xFC02, 0x0012, DataType.INT16, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) +
|
||||
zigbee.configureReporting(0xFC02, 0x0013, DataType.INT16, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) +
|
||||
zigbee.configureReporting(0xFC02, 0x0014, DataType.INT16, 1, 3600, 0x0001, [mfgCode: manufacturerCode])
|
||||
zigbee.configureReporting(0xFC02, 0x0010, 0x18, 10, 3600, 0x01, [mfgCode: manufacturerCode]) +
|
||||
zigbee.configureReporting(0xFC02, 0x0012, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) +
|
||||
zigbee.configureReporting(0xFC02, 0x0013, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) +
|
||||
zigbee.configureReporting(0xFC02, 0x0014, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode])
|
||||
|
||||
return refresh() + configCmds
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "updated called"
|
||||
log.info "garage value : $garageSensor"
|
||||
if (garageSensor == "Yes") {
|
||||
def descriptionText = "Updating device to garage sensor"
|
||||
if (device.latestValue("status") == "open") {
|
||||
sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true)
|
||||
} else if (device.latestValue("status") == "closed") {
|
||||
sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true)
|
||||
}
|
||||
private getEndpointId() {
|
||||
new BigInteger(device.endpointId, 16).toString()
|
||||
}
|
||||
|
||||
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 2000",
|
||||
//Enroll Response
|
||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
||||
"send 0x${device.deviceNetworkId} 1 1", "delay 2000"
|
||||
]
|
||||
}
|
||||
|
||||
private Map parseAxis(String description) {
|
||||
def z = hexToSignedInt(description[0..3])
|
||||
def y = hexToSignedInt(description[10..13])
|
||||
def x = hexToSignedInt(description[20..23])
|
||||
def xyzResults = [x: x, y: y, z: z]
|
||||
|
||||
if (device.getDataValue("manufacturer") == "SmartThings") {
|
||||
// This mapping matches the current behavior of the Device Handler for the Centralite sensors
|
||||
xyzResults.x = z
|
||||
xyzResults.y = y
|
||||
xyzResults.z = -x
|
||||
} else {
|
||||
def descriptionText = "Updating device to open/close sensor"
|
||||
if (device.latestValue("status") == "garage-open") {
|
||||
sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true)
|
||||
} else if (device.latestValue("status") == "garage-closed") {
|
||||
sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true)
|
||||
}
|
||||
// The axises reported by the Device Handler differ from the axises reported by the sensor
|
||||
// This may change in the future
|
||||
xyzResults.x = z
|
||||
xyzResults.y = x
|
||||
xyzResults.z = y
|
||||
}
|
||||
|
||||
log.debug "parseAxis -- ${xyzResults}"
|
||||
|
||||
if (garageSensor == "Yes")
|
||||
garageEvent(xyzResults.z)
|
||||
|
||||
getXyzResult(xyzResults, description)
|
||||
}
|
||||
|
||||
private hexToSignedInt(hexVal) {
|
||||
@@ -375,6 +467,44 @@ private hexToSignedInt(hexVal) {
|
||||
unsignedVal > 32767 ? unsignedVal - 65536 : unsignedVal
|
||||
}
|
||||
|
||||
def garageEvent(zValue) {
|
||||
def absValue = zValue.abs()
|
||||
def contactValue = null
|
||||
def garageValue = null
|
||||
if (absValue>900) {
|
||||
contactValue = 'closed'
|
||||
garageValue = 'garage-closed'
|
||||
}
|
||||
else if (absValue < 100) {
|
||||
contactValue = 'open'
|
||||
garageValue = 'garage-open'
|
||||
}
|
||||
if (contactValue != null){
|
||||
def descriptionText = contactValue == 'open' ? '{{ device.displayName }} was opened' :'{{ device.displayName }} was closed'
|
||||
sendEvent(name: 'contact', value: contactValue, descriptionText: descriptionText, displayed:false, translatable: true)
|
||||
sendEvent(name: 'status', value: garageValue, descriptionText: descriptionText, translatable: true)
|
||||
}
|
||||
}
|
||||
|
||||
private Map getXyzResult(results, description) {
|
||||
def name = "threeAxis"
|
||||
def value = "${results.x},${results.y},${results.z}"
|
||||
def linkText = getLinkText(device)
|
||||
def descriptionText = "$linkText was $value"
|
||||
def isStateChange = isStateChange(device, name, value)
|
||||
|
||||
[
|
||||
name: name,
|
||||
value: value,
|
||||
unit: null,
|
||||
linkText: linkText,
|
||||
descriptionText: descriptionText,
|
||||
handlerName: name,
|
||||
isStateChange: isStateChange,
|
||||
displayed: false
|
||||
]
|
||||
}
|
||||
|
||||
private getManufacturerCode() {
|
||||
if (device.getDataValue("manufacturer") == "SmartThings") {
|
||||
return "0x110A"
|
||||
@@ -386,3 +516,25 @@ private getManufacturerCode() {
|
||||
private hexToInt(value) {
|
||||
new BigInteger(value, 16)
|
||||
}
|
||||
|
||||
private hex(value) {
|
||||
new BigInteger(Math.round(value).toString()).toString(16)
|
||||
}
|
||||
|
||||
private String swapEndianHex(String hex) {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ metadata {
|
||||
def parse(String description) {
|
||||
def results
|
||||
|
||||
if (!isSupportedDescription(description) || description.startsWith("zone")) {
|
||||
if (!isSupportedDescription(description) || zigbee.isZoneType19(description)) {
|
||||
results = parseSingleMessage(description)
|
||||
}
|
||||
else if (description == 'updated') {
|
||||
@@ -488,7 +488,12 @@ private String parseValue(String description) {
|
||||
if (!isSupportedDescription(description)) {
|
||||
return description
|
||||
}
|
||||
return zigbee.parseZoneStatus(description)?.isAlarm1Set() ? "open" : "closed"
|
||||
else if (zigbee.translateStatusZoneType19(description)) {
|
||||
return "open"
|
||||
}
|
||||
else {
|
||||
return "closed"
|
||||
}
|
||||
}
|
||||
|
||||
private parseDescriptionText(String linkText, String value, String description) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
|
||||
|
||||
metadata {
|
||||
definition(name: "SmartSense Open/Closed Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||
definition (name: "SmartSense Open/Closed Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||
capability "Battery"
|
||||
capability "Configuration"
|
||||
capability "Contact Sensor"
|
||||
@@ -43,77 +43,155 @@ metadata {
|
||||
}
|
||||
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name: "contact", type: "generic", width: 6, height: 4) {
|
||||
tileAttribute("device.contact", key: "PRIMARY_CONTROL") {
|
||||
attributeState "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
|
||||
attributeState "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
|
||||
multiAttributeTile(name:"contact", type: "generic", width: 6, height: 4){
|
||||
tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
|
||||
attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
|
||||
attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
|
||||
}
|
||||
}
|
||||
|
||||
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "temperature", label: '${currentValue}°',
|
||||
backgroundColors: [
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
state "temperature", label:'${currentValue}°',
|
||||
backgroundColors:[
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
}
|
||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "battery", label: '${currentValue}% battery', unit: ""
|
||||
state "battery", label:'${currentValue}% battery', unit:""
|
||||
}
|
||||
|
||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||
state "default", action: "refresh.refresh", icon: "st.secondary.refresh"
|
||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
main(["contact", "temperature"])
|
||||
details(["contact", "temperature", "battery", "refresh"])
|
||||
main (["contact", "temperature"])
|
||||
details(["contact","temperature","battery","refresh"])
|
||||
}
|
||||
}
|
||||
|
||||
def parse(String description) {
|
||||
log.debug "description: $description"
|
||||
|
||||
Map map = zigbee.getEvent(description)
|
||||
if (!map) {
|
||||
if (description?.startsWith('zone status')) {
|
||||
map = parseIasMessage(description)
|
||||
} else {
|
||||
Map descMap = zigbee.parseDescriptionAsMap(description)
|
||||
if (descMap?.clusterInt == 0x0001 && descMap.commandInt != 0x07 && descMap?.value) {
|
||||
map = getBatteryResult(Integer.parseInt(descMap.value, 16))
|
||||
} else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
|
||||
if (descMap.data[0] == "00") {
|
||||
log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap"
|
||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
} else {
|
||||
log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
|
||||
}
|
||||
}
|
||||
}
|
||||
Map map = [:]
|
||||
if (description?.startsWith('catchall:')) {
|
||||
map = parseCatchAllMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('read attr -')) {
|
||||
map = parseReportAttributeMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('temperature: ')) {
|
||||
map = parseCustomMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('zone status')) {
|
||||
map = parseIasMessage(description)
|
||||
}
|
||||
|
||||
log.debug "Parse returned $map"
|
||||
def result = map ? createEvent(map) : [:]
|
||||
|
||||
if (description?.startsWith('enroll request')) {
|
||||
List cmds = zigbee.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:
|
||||
// 0x07 - configure reporting
|
||||
if (cluster.command != 0x07) {
|
||||
resultMap = getBatteryResult(cluster.data.last())
|
||||
}
|
||||
break
|
||||
|
||||
case 0x0402:
|
||||
if (cluster.command == 0x07){
|
||||
if (cluster.data[0] == 0x00) {
|
||||
log.debug "TEMP REPORTING CONFIG RESPONSE" + cluster
|
||||
resultMap = [name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]]
|
||||
}
|
||||
else {
|
||||
log.warn "TEMP REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 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
|
||||
}
|
||||
|
||||
private boolean shouldProcessMessage(cluster) {
|
||||
// 0x0B is default response indicating message got through
|
||||
boolean ignoredMessage = cluster.profileId != 0x0104 ||
|
||||
cluster.command == 0x0B ||
|
||||
(cluster.data.size() > 0 && cluster.data.first() == 0x3e)
|
||||
return !ignoredMessage
|
||||
}
|
||||
|
||||
private int getHumidity(value) {
|
||||
return Math.round(Double.parseDouble(value))
|
||||
}
|
||||
|
||||
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)
|
||||
resultMap = getTemperatureResult(value)
|
||||
}
|
||||
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: ')) {
|
||||
def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())
|
||||
resultMap = getTemperatureResult(value)
|
||||
}
|
||||
return resultMap
|
||||
}
|
||||
|
||||
private Map parseIasMessage(String description) {
|
||||
ZoneStatus zs = zigbee.parseZoneStatus(description)
|
||||
return zs.isAlarm1Set() ? getContactResult('open') : getContactResult('closed')
|
||||
}
|
||||
|
||||
def getTemperature(value) {
|
||||
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
||||
if(getTemperatureScale() == "C"){
|
||||
return celsius
|
||||
} else {
|
||||
return celsiusToFahrenheit(celsius) as Integer
|
||||
}
|
||||
}
|
||||
|
||||
private Map getBatteryResult(rawValue) {
|
||||
log.debug 'Battery'
|
||||
def linkText = getLinkText(device)
|
||||
@@ -126,8 +204,8 @@ private Map getBatteryResult(rawValue) {
|
||||
def maxVolts = 3.0
|
||||
def pct = (volts - minVolts) / (maxVolts - minVolts)
|
||||
def roundedPct = Math.round(pct * 100)
|
||||
if (roundedPct <= 0)
|
||||
roundedPct = 1
|
||||
if (roundedPct <= 0)
|
||||
roundedPct = 1
|
||||
result.value = Math.min(100, roundedPct)
|
||||
result.descriptionText = "${linkText} battery was ${result.value}%"
|
||||
result.name = 'battery'
|
||||
@@ -136,14 +214,31 @@ private Map getBatteryResult(rawValue) {
|
||||
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}"
|
||||
return [
|
||||
name: 'temperature',
|
||||
value: value,
|
||||
descriptionText: descriptionText,
|
||||
unit: temperatureScale
|
||||
]
|
||||
}
|
||||
|
||||
private Map getContactResult(value) {
|
||||
log.debug 'Contact Status'
|
||||
def linkText = getLinkText(device)
|
||||
def descriptionText = "${linkText} was ${value == 'open' ? 'opened' : 'closed'}"
|
||||
return [
|
||||
name : 'contact',
|
||||
value : value,
|
||||
descriptionText: descriptionText
|
||||
name: 'contact',
|
||||
value: value,
|
||||
descriptionText: descriptionText
|
||||
]
|
||||
}
|
||||
|
||||
@@ -156,10 +251,12 @@ def ping() {
|
||||
|
||||
def refresh() {
|
||||
log.debug "Refreshing Temperature and Battery"
|
||||
def refreshCmds = zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) +
|
||||
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020)
|
||||
def refreshCmds = [
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 2000",
|
||||
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 2000"
|
||||
]
|
||||
|
||||
return refreshCmds + zigbee.enrollResponse()
|
||||
return refreshCmds + enrollResponse()
|
||||
}
|
||||
|
||||
def configure() {
|
||||
@@ -171,5 +268,44 @@ def configure() {
|
||||
|
||||
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||
// battery minReport 30 seconds, maxReportTime 6 hrs by default
|
||||
return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // send refresh cmds as part of config
|
||||
return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // 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 2000",
|
||||
//Enroll Response
|
||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
||||
"send 0x${device.deviceNetworkId} 1 1", "delay 2000"
|
||||
]
|
||||
}
|
||||
|
||||
private getEndpointId() {
|
||||
new BigInteger(device.endpointId, 16).toString()
|
||||
}
|
||||
|
||||
private hex(value) {
|
||||
new BigInteger(Math.round(value).toString()).toString(16)
|
||||
}
|
||||
|
||||
private String swapEndianHex(String hex) {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -13,10 +13,8 @@
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
import physicalgraph.zigbee.zcl.DataType
|
||||
|
||||
metadata {
|
||||
definition(name: "SmartSense Temp/Humidity Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||
definition (name: "SmartSense Temp/Humidity Sensor",namespace: "smartthings", author: "SmartThings") {
|
||||
capability "Configuration"
|
||||
capability "Battery"
|
||||
capability "Refresh"
|
||||
@@ -33,7 +31,7 @@ metadata {
|
||||
status 'H 45': 'catchall: 0104 FC45 01 01 0140 00 D9B9 00 04 C2DF 0A 01 0000218911'
|
||||
status 'H 57': 'catchall: 0104 FC45 01 01 0140 00 4E55 00 04 C2DF 0A 01 0000211316'
|
||||
status 'H 53': 'catchall: 0104 FC45 01 01 0140 00 20CD 00 04 C2DF 0A 01 0000219814'
|
||||
status 'H 43': 'read attr - raw: BF7601FC450C00000021A410, dni: BF76, endpoint: 01, cluster: FC45, size: 0C, attrId: 0000, result: success, encoding: 21, value: 10a4'
|
||||
status 'H 43': 'read attr - raw: BF7601FC450C00000021A410, dni: BF76, endpoint: 01, cluster: FC45, size: 0C, attrId: 0000, result: success, encoding: 21, value: 10a4'
|
||||
}
|
||||
|
||||
preferences {
|
||||
@@ -42,28 +40,28 @@ metadata {
|
||||
}
|
||||
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name: "temperature", type: "generic", width: 6, height: 4) {
|
||||
tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
|
||||
attributeState "temperature", label: '${currentValue}°',
|
||||
backgroundColors: [
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
multiAttributeTile(name:"temperature", type: "generic", width: 6, height: 4){
|
||||
tileAttribute ("device.temperature", key: "PRIMARY_CONTROL") {
|
||||
attributeState "temperature", label:'${currentValue}°',
|
||||
backgroundColors:[
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
}
|
||||
}
|
||||
valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "humidity", label: '${currentValue}% humidity', unit: ""
|
||||
state "humidity", label:'${currentValue}% humidity', unit:""
|
||||
}
|
||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "battery", label: '${currentValue}% battery'
|
||||
state "battery", label:'${currentValue}% battery'
|
||||
}
|
||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||
state "default", action: "refresh.refresh", icon: "st.secondary.refresh"
|
||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
main "temperature", "humidity"
|
||||
@@ -74,31 +72,142 @@ metadata {
|
||||
def parse(String description) {
|
||||
log.debug "description: $description"
|
||||
|
||||
// getEvent will handle temperature and humidity
|
||||
Map map = zigbee.getEvent(description)
|
||||
if (!map) {
|
||||
Map descMap = zigbee.parseDescriptionAsMap(description)
|
||||
if (descMap.clusterInt == 0x0001 && descMap.commandInt != 0x07 && descMap?.value) {
|
||||
map = getBatteryResult(Integer.parseInt(descMap.value, 16))
|
||||
} else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
|
||||
if (descMap.data[0] == "00") {
|
||||
log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap"
|
||||
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
} else {
|
||||
log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
|
||||
}
|
||||
}
|
||||
Map map = [:]
|
||||
if (description?.startsWith('catchall:')) {
|
||||
map = parseCatchAllMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('read attr -')) {
|
||||
map = parseReportAttributeMessage(description)
|
||||
}
|
||||
else if (description?.startsWith('temperature: ') || description?.startsWith('humidity: ')) {
|
||||
map = parseCustomMessage(description)
|
||||
}
|
||||
|
||||
log.debug "Parse returned $map"
|
||||
return map ? createEvent(map) : [:]
|
||||
}
|
||||
|
||||
private Map parseCatchAllMessage(String description) {
|
||||
Map resultMap = [:]
|
||||
def cluster = zigbee.parse(description)
|
||||
if (shouldProcessMessage(cluster)) {
|
||||
switch(cluster.clusterId) {
|
||||
case 0x0001:
|
||||
// 0x07 - configure reporting
|
||||
if (cluster.command != 0x07) {
|
||||
resultMap = getBatteryResult(cluster.data.last())
|
||||
}
|
||||
break
|
||||
|
||||
case 0x0402:
|
||||
if (cluster.command == 0x07) {
|
||||
if (cluster.data[0] == 0x00){
|
||||
log.debug "TEMP REPORTING CONFIG RESPONSE" + cluster
|
||||
resultMap = [name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]]
|
||||
}
|
||||
else {
|
||||
log.warn "TEMP REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 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 0xFC45:
|
||||
// 0x07 - configure reporting
|
||||
if (cluster.command != 0x07) {
|
||||
String pctStr = cluster.data[-1, -2].collect { Integer.toHexString(it) }.join('')
|
||||
String display = Math.round(Integer.valueOf(pctStr, 16) / 100)
|
||||
resultMap = getHumidityResult(display)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return resultMap
|
||||
}
|
||||
|
||||
private boolean shouldProcessMessage(cluster) {
|
||||
// 0x0B is default response indicating message got through
|
||||
boolean ignoredMessage = cluster.profileId != 0x0104 ||
|
||||
cluster.command == 0x0B ||
|
||||
(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)
|
||||
resultMap = getTemperatureResult(value)
|
||||
}
|
||||
else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
|
||||
resultMap = getBatteryResult(Integer.parseInt(descMap.value, 16))
|
||||
}
|
||||
else if (descMap.cluster == "FC45" && descMap.attrId == "0000") {
|
||||
def value = getReportAttributeHumidity(descMap.value)
|
||||
resultMap = getHumidityResult(value)
|
||||
}
|
||||
|
||||
return resultMap
|
||||
}
|
||||
|
||||
def getReportAttributeHumidity(String value) {
|
||||
def humidity = null
|
||||
if (value?.trim()) {
|
||||
try {
|
||||
// value is hex with no decimal
|
||||
def pct = Integer.parseInt(value.trim(), 16) / 100
|
||||
humidity = String.format('%.0f', pct)
|
||||
} catch(NumberFormatException nfe) {
|
||||
log.debug "Error converting $value to humidity"
|
||||
}
|
||||
}
|
||||
return humidity
|
||||
}
|
||||
|
||||
private Map parseCustomMessage(String description) {
|
||||
Map resultMap = [:]
|
||||
if (description?.startsWith('temperature: ')) {
|
||||
def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())
|
||||
resultMap = getTemperatureResult(value)
|
||||
}
|
||||
else if (description?.startsWith('humidity: ')) {
|
||||
def pct = (description - "humidity: " - "%").trim()
|
||||
if (pct.isNumber()) {
|
||||
def value = Math.round(new BigDecimal(pct)).toString()
|
||||
resultMap = getHumidityResult(value)
|
||||
} else {
|
||||
log.error "invalid humidity: ${pct}"
|
||||
}
|
||||
}
|
||||
return resultMap
|
||||
}
|
||||
|
||||
def getTemperature(value) {
|
||||
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
||||
if(getTemperatureScale() == "C"){
|
||||
return celsius
|
||||
} else {
|
||||
return celsiusToFahrenheit(celsius) as Integer
|
||||
}
|
||||
}
|
||||
|
||||
private Map getBatteryResult(rawValue) {
|
||||
log.debug 'Battery'
|
||||
def linkText = getLinkText(device)
|
||||
|
||||
def result = [:]
|
||||
def result = [:]
|
||||
|
||||
def volts = rawValue / 10
|
||||
if (!(rawValue == 0 || rawValue == 255)) {
|
||||
@@ -117,22 +226,41 @@ private Map getBatteryResult(rawValue) {
|
||||
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}"
|
||||
return [
|
||||
name: 'temperature',
|
||||
value: value,
|
||||
descriptionText: descriptionText,
|
||||
unit: temperatureScale
|
||||
]
|
||||
}
|
||||
|
||||
private Map getHumidityResult(value) {
|
||||
log.debug 'Humidity'
|
||||
return value ? [name: 'humidity', value: value, unit: '%'] : [:]
|
||||
}
|
||||
|
||||
/**
|
||||
* PING is used by Device-Watch in attempt to reach the Device
|
||||
* */
|
||||
def ping() {
|
||||
return zigbee.readAttribute(0x0001, 0x0020) // Read the Battery Level
|
||||
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
def refresh()
|
||||
{
|
||||
log.debug "refresh temperature, humidity, and battery"
|
||||
return zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0x104E]) + // New firmware
|
||||
zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0xC2DF]) + // Original firmware
|
||||
zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) +
|
||||
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) +
|
||||
zigbee.configureReporting(0xFC45, 0x0000, DataType.INT16, 30, 3600, 100) +
|
||||
zigbee.batteryConfig() +
|
||||
zigbee.temperatureConfig(30, 300)
|
||||
return zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0xC2DF]) + // Original firmware
|
||||
zigbee.readAttribute(0x0402, 0x0000) +
|
||||
zigbee.readAttribute(0x0001, 0x0020)
|
||||
}
|
||||
|
||||
def configure() {
|
||||
@@ -141,8 +269,35 @@ def configure() {
|
||||
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
|
||||
log.debug "Configuring Reporting and Bindings."
|
||||
def humidityConfigCmds = [
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0xFC45 {${device.zigbeeId}} {}", "delay 2000",
|
||||
"zcl global send-me-a-report 0xFC45 0 0x29 30 3600 {6400}", "delay 200",
|
||||
"send 0x${device.deviceNetworkId} 1 1", "delay 2000"
|
||||
]
|
||||
|
||||
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||
// battery minReport 30 seconds, maxReportTime 6 hrs by default
|
||||
return refresh()
|
||||
return refresh() + humidityConfigCmds + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // send refresh cmds as part of config
|
||||
}
|
||||
|
||||
private hex(value) {
|
||||
new BigInteger(Math.round(value).toString()).toString(16)
|
||||
}
|
||||
|
||||
private String swapEndianHex(String hex) {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ metadata {
|
||||
def parse(String description) {
|
||||
def results
|
||||
|
||||
if (!isSupportedDescription(description) || description.startsWith("zone")) {
|
||||
if (!isSupportedDescription(description) || zigbee.isZoneType19(description)) {
|
||||
// Ignore this in favor of orientation-based state
|
||||
// results = parseSingleMessage(description)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*
|
||||
*/
|
||||
metadata {
|
||||
|
||||
|
||||
definition (name: "Simulated Switch", namespace: "smartthings/testing", author: "bob") {
|
||||
capability "Switch"
|
||||
capability "Relay Switch"
|
||||
@@ -39,7 +39,9 @@ metadata {
|
||||
}
|
||||
}
|
||||
|
||||
def parse(description) {
|
||||
def parse(String description) {
|
||||
def pair = description.split(":")
|
||||
createEvent(name: pair[0].trim(), value: pair[1].trim())
|
||||
}
|
||||
|
||||
def on() {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
import physicalgraph.zigbee.zcl.DataType
|
||||
|
||||
metadata {
|
||||
definition (name: "ZigBee Button", namespace: "smartthings", author: "Mitch Pond") {
|
||||
@@ -83,7 +82,7 @@ def parse(String description) {
|
||||
def result = event ? createEvent(event) : []
|
||||
|
||||
if (description?.startsWith('enroll request')) {
|
||||
List cmds = zigbee.enrollResponse()
|
||||
List cmds = enrollResponse()
|
||||
result = cmds?.collect { new physicalgraph.device.HubAction(it) }
|
||||
}
|
||||
return result
|
||||
@@ -118,38 +117,15 @@ private Map getBatteryResult(rawValue) {
|
||||
private Map parseNonIasButtonMessage(Map descMap){
|
||||
def buttonState = ""
|
||||
def buttonNumber = 0
|
||||
if ((device.getDataValue("model") == "3460-L") &&(descMap.clusterInt == 0x0006)) {
|
||||
if (descMap.commandInt == 1) {
|
||||
if (((device.getDataValue("model") == "3460-L") || (device.getDataValue("model") == "3450-L"))
|
||||
&&(descMap.clusterInt == 0x0006)) {
|
||||
if (descMap.command == "01") {
|
||||
getButtonResult("press")
|
||||
}
|
||||
else if (descMap.commandInt == 0) {
|
||||
else if (descMap.command == "00") {
|
||||
getButtonResult("release")
|
||||
}
|
||||
}
|
||||
else if ((device.getDataValue("model") == "3450-L") && (descMap.clusterInt == 0x0006)) {
|
||||
if (descMap.commandInt == 1) {
|
||||
getButtonResult("press")
|
||||
}
|
||||
else if (descMap.commandInt == 0) {
|
||||
def button = 1
|
||||
switch(descMap.sourceEndpoint) {
|
||||
case "01":
|
||||
button = 4
|
||||
break
|
||||
case "02":
|
||||
button = 3
|
||||
break
|
||||
case "03":
|
||||
button = 1
|
||||
break
|
||||
case "04":
|
||||
button = 2
|
||||
break
|
||||
}
|
||||
|
||||
getButtonResult("release", button)
|
||||
}
|
||||
}
|
||||
else if (descMap.clusterInt == 0x0006) {
|
||||
buttonState = "pushed"
|
||||
if (descMap.command == "01") {
|
||||
@@ -184,7 +160,7 @@ private Map parseNonIasButtonMessage(Map descMap){
|
||||
def refresh() {
|
||||
log.debug "Refreshing Battery"
|
||||
|
||||
return zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x20) +
|
||||
return zigbee.readAttribute(0x0001, 0x20) +
|
||||
zigbee.enrollResponse()
|
||||
}
|
||||
|
||||
@@ -201,9 +177,9 @@ def configure() {
|
||||
}
|
||||
return zigbee.onOffConfig() +
|
||||
zigbee.levelConfig() +
|
||||
zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x20, DataType.UINT8, 30, 21600, 0x01) +
|
||||
zigbee.configureReporting(0x0001, 0x20, 0x20, 30, 21600, 0x01) +
|
||||
zigbee.enrollResponse() +
|
||||
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x20) +
|
||||
zigbee.readAttribute(0x0001, 0x20) +
|
||||
cmds
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ Works with:
|
||||
* **Switch** - can detect state (possible values: on/off)
|
||||
* **Switch Level** - represents current light level, usually 0-100 in percent
|
||||
* **Health Check** - indicates ability to get device health notifications
|
||||
* **Light** - indicates that the device belongs to Light category.
|
||||
|
||||
## Device Health
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ metadata {
|
||||
capability "Switch"
|
||||
capability "Switch Level"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702"
|
||||
@@ -98,7 +97,7 @@ def on() {
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
zigbee.setLevel(value) + (value?.toInteger() > 0 ? zigbee.on() : [])
|
||||
zigbee.setLevel(value)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,6 @@ metadata {
|
||||
capability "Switch"
|
||||
capability "Switch Level"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
|
||||
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008"
|
||||
@@ -29,10 +28,6 @@ metadata {
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05", outClusters: "0019", manufacturer: "OSRAM SYLVANIA", model: "iQBR30", deviceJoinName: "Sylvania Ultra iQ"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY PAR38 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart PAR38 Soft White"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart BR30 Soft White"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-G13", deviceJoinName: "Sengled Element Classic"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL6HD", deviceJoinName: "Leviton Dimmer Switch"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL3HL", deviceJoinName: "Leviton Lumina RF Plug-In Dimmer"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL1KD", deviceJoinName: "Leviton Lumina RF Dimmer Switch"
|
||||
}
|
||||
|
||||
tiles(scale: 2) {
|
||||
@@ -94,13 +89,7 @@ def on() {
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
def additionalCmds = []
|
||||
if (device.getDataValue("model") == "iQBR30" && value.toInteger() > 0) { // Handle iQ bulb not following spec
|
||||
additionalCmds = zigbee.on()
|
||||
} else if (device.getDataValue("manufacturer") == "MRVL") { // Handle marvel stack not reporting
|
||||
additionalCmds = refresh()
|
||||
}
|
||||
zigbee.setLevel(value) + additionalCmds
|
||||
zigbee.setLevel(value)
|
||||
}
|
||||
/**
|
||||
* PING is used by Device-Watch in attempt to reach the Device
|
||||
@@ -110,15 +99,7 @@ def ping() {
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh()
|
||||
}
|
||||
|
||||
def installed() {
|
||||
if (((device.getDataValue("manufacturer") == "MRVL") && (device.getDataValue("model") == "MZ100")) || (device.getDataValue("manufacturer") == "OSRAM SYLVANIA") || (device.getDataValue("manufacturer") == "OSRAM")) {
|
||||
if ((device.currentState("level")?.value == null) || (device.currentState("level")?.value == 0)) {
|
||||
sendEvent(name: "level", value: 100)
|
||||
}
|
||||
}
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig()
|
||||
}
|
||||
|
||||
def configure() {
|
||||
@@ -128,5 +109,5 @@ def configure() {
|
||||
sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
|
||||
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||
refresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig()
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig()
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
import physicalgraph.zigbee.zcl.DataType
|
||||
|
||||
metadata {
|
||||
definition (name: "ZigBee Lock", namespace: "smartthings", author: "SmartThings")
|
||||
{
|
||||
@@ -73,6 +71,9 @@ private getDOORLOCK_CMD_UNLOCK_DOOR() { 0x01 }
|
||||
private getDOORLOCK_ATTR_LOCKSTATE() { 0x0000 }
|
||||
private getPOWER_ATTR_BATTERY_PERCENTAGE_REMAINING() { 0x0021 }
|
||||
|
||||
private getTYPE_U8() { 0x20 }
|
||||
private getTYPE_ENUM8() { 0x30 }
|
||||
|
||||
// Public methods
|
||||
def installed() {
|
||||
log.trace "installed()"
|
||||
@@ -85,9 +86,9 @@ def uninstalled() {
|
||||
def configure() {
|
||||
def cmds =
|
||||
zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE,
|
||||
DataType.ENUM8, 0, 3600, null) +
|
||||
TYPE_ENUM8, 0, 3600, null) +
|
||||
zigbee.configureReporting(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING,
|
||||
DataType.UINT8, 600, 21600, 0x01)
|
||||
TYPE_U8, 600, 21600, 0x01)
|
||||
log.info "configure() --- cmds: $cmds"
|
||||
return refresh() + cmds // send refresh cmds as part of config
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*
|
||||
* This DTH should serve as the generic DTH to handle RGB ZigBee HA devices (For color bulbs with no color temperature)
|
||||
*/
|
||||
import physicalgraph.zigbee.zcl.DataType
|
||||
|
||||
metadata {
|
||||
definition (name: "ZigBee RGB Bulb", namespace: "smartthings", author: "SmartThings") {
|
||||
@@ -28,7 +27,6 @@ metadata {
|
||||
capability "Switch"
|
||||
capability "Switch Level"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
|
||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Gardenspot RGB", deviceJoinName: "SYLVANIA Smart Gardenspot mini RGB"
|
||||
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Gardenspot RGB", deviceJoinName: "SYLVANIA Smart Gardenspot mini RGB"
|
||||
@@ -123,7 +121,7 @@ def ping() {
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01)
|
||||
}
|
||||
|
||||
def configure() {
|
||||
@@ -133,7 +131,7 @@ def configure() {
|
||||
sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
|
||||
|
||||
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
|
||||
zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01) + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01) + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*
|
||||
* This DTH should serve as the generic DTH to handle RGBW ZigBee HA devices
|
||||
*/
|
||||
import physicalgraph.zigbee.zcl.DataType
|
||||
|
||||
metadata {
|
||||
definition (name: "ZigBee RGBW Bulb", namespace: "smartthings", author: "SmartThings") {
|
||||
@@ -29,7 +28,6 @@ metadata {
|
||||
capability "Switch"
|
||||
capability "Switch Level"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
|
||||
attribute "colorName", "string"
|
||||
command "setGenericName"
|
||||
@@ -141,7 +139,7 @@ def ping() {
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
|
||||
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01)
|
||||
}
|
||||
|
||||
def configure() {
|
||||
|
||||
@@ -21,7 +21,6 @@ metadata {
|
||||
capability "Sensor"
|
||||
capability "Switch"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702"
|
||||
|
||||
@@ -22,8 +22,6 @@ metadata {
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0003, 0006, 0019, 0406", manufacturer: "Leviton", model: "ZSS-10", deviceJoinName: "Leviton Switch"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "000A", manufacturer: "HAI", model: "65A21-1", deviceJoinName: "Leviton Wireless Load Control Module-30amp"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL15A", deviceJoinName: "Leviton Lumina RF Plug-In Appliance Module"
|
||||
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL15S", deviceJoinName: "Leviton Lumina RF Switch"
|
||||
}
|
||||
|
||||
// simulator metadata
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
import physicalgraph.zigbee.zcl.DataType
|
||||
|
||||
metadata {
|
||||
definition (name: "ZigBee Valve", namespace: "smartthings", author: "SmartThings") {
|
||||
@@ -67,6 +66,8 @@ private getCLUSTER_BASIC() { 0x0000 }
|
||||
private getBASIC_ATTR_POWER_SOURCE() { 0x0007 }
|
||||
private getCLUSTER_POWER() { 0x0001 }
|
||||
private getPOWER_ATTR_BATTERY_PERCENTAGE_REMAINING() { 0x0021 }
|
||||
private getTYPE_U8() { 0x20 }
|
||||
private getTYPE_ENUM8() { 0x30 }
|
||||
|
||||
// Parse incoming device messages to generate events
|
||||
def parse(String description) {
|
||||
@@ -127,8 +128,8 @@ def refresh() {
|
||||
zigbee.readAttribute(CLUSTER_BASIC, BASIC_ATTR_POWER_SOURCE) +
|
||||
zigbee.readAttribute(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) +
|
||||
zigbee.onOffConfig() +
|
||||
zigbee.configureReporting(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING, DataType.UINT8, 600, 21600, 1) +
|
||||
zigbee.configureReporting(CLUSTER_BASIC, BASIC_ATTR_POWER_SOURCE, DataType.ENUM8, 5, 21600, 1)
|
||||
zigbee.configureReporting(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING, TYPE_U8, 600, 21600, 1) +
|
||||
zigbee.configureReporting(CLUSTER_BASIC, BASIC_ATTR_POWER_SOURCE, TYPE_ENUM8, 5, 21600, 1)
|
||||
}
|
||||
|
||||
def configure() {
|
||||
|
||||
@@ -26,7 +26,6 @@ metadata {
|
||||
capability "Refresh"
|
||||
capability "Switch"
|
||||
capability "Switch Level"
|
||||
capability "Light"
|
||||
|
||||
attribute "colorName", "string"
|
||||
command "setGenericName"
|
||||
|
||||
@@ -89,7 +89,7 @@ def on() {
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
||||
zigbee.setLevel(value) + ["delay 1500"] + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
import physicalgraph.zigbee.zcl.DataType
|
||||
|
||||
metadata {
|
||||
definition (name: "ZLL RGB Bulb", namespace: "smartthings", author: "SmartThings") {
|
||||
@@ -108,7 +107,7 @@ def configure() {
|
||||
}
|
||||
|
||||
def configureAttributes() {
|
||||
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
|
||||
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01)
|
||||
}
|
||||
|
||||
def refreshAttributes() {
|
||||
@@ -116,7 +115,7 @@ def refreshAttributes() {
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
||||
zigbee.setLevel(value) + ["delay 1500"] + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
||||
}
|
||||
|
||||
def setColor(value){
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
import physicalgraph.zigbee.zcl.DataType
|
||||
|
||||
metadata {
|
||||
definition (name: "ZLL RGBW Bulb", namespace: "smartthings", author: "SmartThings") {
|
||||
@@ -124,7 +123,7 @@ def configure() {
|
||||
}
|
||||
|
||||
def configureAttributes() {
|
||||
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
|
||||
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01)
|
||||
}
|
||||
|
||||
def refreshAttributes() {
|
||||
@@ -136,7 +135,7 @@ def setColorTemperature(value) {
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
||||
zigbee.setLevel(value) + ["delay 1500"] + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
|
||||
}
|
||||
|
||||
def setColor(value){
|
||||
|
||||
@@ -90,7 +90,7 @@ def on() {
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh()
|
||||
zigbee.setLevel(value) + ["delay 1500"] + zigbee.levelRefresh()
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
|
||||
@@ -6,12 +6,6 @@ Works with:
|
||||
|
||||
* [Leviton Plug-in Lamp Dimmer Module (DZPD3-1LW)](https://www.smartthings.com/works-with-smartthings/outlets/leviton-plug-in-lamp-dimmer-module)
|
||||
* [Leviton Universal Dimmer (DZMX1-LZ)](https://www.smartthings.com/works-with-smartthings/switches-and-dimmers/leviton-universal-dimmer)
|
||||
* [Leviton 1000W Incandescent Dimmer](https://www.smartthings.com/works-with-smartthings/leviton/leviton-1000w-incandescent-dimmer)
|
||||
* [Leviton 600W Incandescent Dimmer](https://www.smartthings.com/works-with-smartthings/leviton/leviton-600w-incandescent-dimmer)
|
||||
* [Enerwave In-Wall Dimmer](https://www.smartthings.com/works-with-smartthings/enerwave/enerwave-in-wall-dimmer-zw500d)
|
||||
* [Leviton 3-Speed Fan Controller](https://www.smartthings.com/works-with-smartthings/leviton/leviton-3-speed-fan-controller)
|
||||
* [Leviton Magnetic Low Voltage Dimmer](https://www.smartthings.com/works-with-smartthings/leviton/leviton-magnetic-low-voltage-dimmer)
|
||||
* [Remotec Technology Plug-In Dimmer](https://www.smartthings.com/works-with-smartthings/remotec-technology/remotec-technology-plug-in-dimmer)
|
||||
|
||||
## Table of contents
|
||||
|
||||
@@ -46,9 +40,4 @@ If the device doesn't pair when trying from the SmartThings mobile app, it is po
|
||||
Pairing needs to be tried again by placing the device closer to the hub.
|
||||
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
|
||||
* [Leviton Plug-in Lamp Dimmer Module (DZPD3-1LW) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices)
|
||||
* [Leviton Universal Dimmer (DZMX1-LZ) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices)
|
||||
* [Leviton 1000W Incandescent Dimmer Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices)
|
||||
* [Leviton 600W Incandescent Dimmer Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices)
|
||||
* [Leviton 3-Speed Fan Controller Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices)
|
||||
* [Enerwave In-Wall Dimmer Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204854176-How-to-connect-Enerwave-switches-and-dimmers)
|
||||
* [Remotec Technology Plug-In Dimmer Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202295150-Remotec-Technology-Plug-In-Dimmer-ZDS-100-)
|
||||
* [Leviton Universal Dimmer (DZMX1-LZ) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206171053-How-to-connect-Leviton-Z-Wave-devices)
|
||||
@@ -20,7 +20,6 @@ metadata {
|
||||
capability "Polling"
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Light"
|
||||
|
||||
fingerprint inClusters: "0x26", deviceJoinName: "Z-Wave Dimmer"
|
||||
fingerprint mfr:"001D", prod:"1902", deviceJoinName: "Z-Wave Dimmer"
|
||||
@@ -29,8 +28,6 @@ metadata {
|
||||
fingerprint mfr:"001D", prod:"1001", model:"0334", deviceJoinName: "Leviton 3-Speed Fan Controller"
|
||||
fingerprint mfr:"001D", prod:"0602", model:"0334", deviceJoinName: "Leviton Magnetic Low Voltage Dimmer"
|
||||
fingerprint mfr:"001D", prod:"0401", model:"0334", deviceJoinName: "Leviton 600W Incandescent Dimmer"
|
||||
fingerprint mfr:"0111", prod:"8200", model:"0200", deviceJoinName: "Remotec Technology Plug-In Dimmer"
|
||||
fingerprint mfr:"1104", prod:"001D", model:"0501", deviceJoinName: "Leviton 1000W Incandescant Dimmer"
|
||||
}
|
||||
|
||||
simulator {
|
||||
|
||||
@@ -25,7 +25,6 @@ metadata {
|
||||
capability "Switch Level"
|
||||
capability "Sensor"
|
||||
capability "Actuator"
|
||||
capability "Light"
|
||||
|
||||
command "reset"
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ metadata {
|
||||
capability "Refresh"
|
||||
capability "Configuration"
|
||||
capability "Sensor"
|
||||
capability "Light"
|
||||
|
||||
command "reset"
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ metadata {
|
||||
capability "Polling"
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Light"
|
||||
|
||||
fingerprint inClusters: "0x25", deviceJoinName: "Z-Wave Switch"
|
||||
fingerprint mfr:"001D", prod:"1A02", model:"0334", deviceJoinName: "Leviton Appliance Module"
|
||||
@@ -27,8 +26,6 @@ metadata {
|
||||
fingerprint mfr:"001D", prod:"1D04", model:"0334", deviceJoinName: "Leviton Outlet"
|
||||
fingerprint mfr:"001D", prod:"1C02", model:"0334", deviceJoinName: "Leviton Switch"
|
||||
fingerprint mfr:"001D", prod:"0301", model:"0334", deviceJoinName: "Leviton 15A Switch"
|
||||
fingerprint mfr:"001D", prod:"0F01", model:"0334", deviceJoinName: "Leviton 5A Incandescent Switch"
|
||||
fingerprint mfr:"001D", prod:"1603", model:"0334", deviceJoinName: "Leviton 15A Split Duplex Receptacle"
|
||||
fingerprint mfr:"011A", prod:"0101", model:"0102", deviceJoinName: "Enerwave On/Off Switch"
|
||||
fingerprint mfr:"011A", prod:"0101", model:"0603", deviceJoinName: "Enerwave Duplex Receptacle"
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ metadata {
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Health Check"
|
||||
capability "Light"
|
||||
|
||||
fingerprint mfr:"0063", prod:"4952", deviceJoinName: "Z-Wave Wall Switch"
|
||||
fingerprint mfr:"0063", prod:"5257", deviceJoinName: "Z-Wave Wall Switch"
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.text.DecimalFormat
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
private getApiUrl() { "https://api.netatmo.com" }
|
||||
private getVendorName() { "netatmo" }
|
||||
private getVendorAuthPath() { "${apiUrl}/oauth2/authorize?" }
|
||||
private getVendorTokenPath(){ "${apiUrl}/oauth2/token" }
|
||||
private getVendorIcon() { "https://s3.amazonaws.com/smartapp-icons/Partner/netamo-icon-1%402x.png" }
|
||||
@@ -13,13 +14,14 @@ private getClientSecret() { appSettings.clientSecret }
|
||||
private getServerUrl() { appSettings.serverUrl }
|
||||
private getShardUrl() { return getApiServerUrl() }
|
||||
private getCallbackUrl() { "${serverUrl}/oauth/callback" }
|
||||
private getBuildRedirectUrl() { "${serverUrl}/oauth/initialize?appId=${app.id}&access_token=${atomicState.accessToken}&apiServerUrl=${shardUrl}" }
|
||||
private getBuildRedirectUrl() { "${serverUrl}/oauth/initialize?appId=${app.id}&access_token=${state.accessToken}&apiServerUrl=${shardUrl}" }
|
||||
|
||||
// Automatically generated. Make future change here.
|
||||
definition(
|
||||
name: "Netatmo (Connect)",
|
||||
namespace: "dianoga",
|
||||
author: "Brian Steere",
|
||||
description: "Integrate your Netatmo devices with SmartThings",
|
||||
description: "Netatmo Integration",
|
||||
category: "SmartThings Labs",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/netamo-icon-1.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/netamo-icon-1%402x.png",
|
||||
@@ -42,16 +44,15 @@ mappings {
|
||||
}
|
||||
|
||||
def authPage() {
|
||||
// log.debug "running authPage()"
|
||||
log.debug "In authPage"
|
||||
|
||||
def description
|
||||
def uninstallAllowed = false
|
||||
def oauthTokenProvided = false
|
||||
|
||||
// If an access token doesn't exist, create one
|
||||
if (!atomicState.accessToken) {
|
||||
atomicState.accessToken = createAccessToken()
|
||||
log.debug "Created access token"
|
||||
if (!state.accessToken) {
|
||||
log.debug "About to create access token."
|
||||
state.accessToken = createAccessToken()
|
||||
}
|
||||
|
||||
if (canInstallLabs()) {
|
||||
@@ -59,32 +60,36 @@ def authPage() {
|
||||
def redirectUrl = getBuildRedirectUrl()
|
||||
// log.debug "Redirect url = ${redirectUrl}"
|
||||
|
||||
if (atomicState.authToken) {
|
||||
description = "Tap 'Next' to select devices"
|
||||
if (state.authToken) {
|
||||
description = "Tap 'Next' to proceed"
|
||||
uninstallAllowed = true
|
||||
oauthTokenProvided = true
|
||||
} else {
|
||||
description = "Tap to enter credentials"
|
||||
description = "Click to enter Credentials."
|
||||
}
|
||||
|
||||
if (!oauthTokenProvided) {
|
||||
log.debug "Showing the login page"
|
||||
log.debug "Show the login page"
|
||||
return dynamicPage(name: "Credentials", title: "Authorize Connection", nextPage:"listDevices", uninstall: uninstallAllowed, install:false) {
|
||||
section() {
|
||||
paragraph "Tap below to login to Netatmo and authorize SmartThings access"
|
||||
href url:redirectUrl, style:"embedded", required:false, title:"Connect to Netatmo", description:description
|
||||
paragraph "Tap below to log in to the netatmo and authorize SmartThings access."
|
||||
href url:redirectUrl, style:"embedded", required:false, title:"Connect to ${getVendorName()}:", description:description
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.debug "Showing the devices page"
|
||||
return dynamicPage(name: "Credentials", title: "Connected", nextPage:"listDevices", uninstall: uninstallAllowed, install:false) {
|
||||
log.debug "Show the devices page"
|
||||
return dynamicPage(name: "Credentials", title: "Credentials Accepted!", nextPage:"listDevices", uninstall: uninstallAllowed, install:false) {
|
||||
section() {
|
||||
input(name:"Devices", style:"embedded", required:false, title:"Netatmo is connected to SmartThings", description:description)
|
||||
input(name:"Devices", style:"embedded", required:false, title:"${getVendorName()} is now connected to SmartThings!", description:description)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
def upgradeNeeded = """To use SmartThings Labs, your Hub should be completely up to date. To update your Hub, access Location Settings in the Main Menu (tap the gear next to your location name), select your Hub, and choose "Update Hub"."""
|
||||
def upgradeNeeded = """To use SmartThings Labs, your Hub should be completely up to date.
|
||||
|
||||
To update your Hub, access Location Settings in the Main Menu (tap the gear next to your location name), select your Hub, and choose "Update Hub"."""
|
||||
|
||||
|
||||
return dynamicPage(name:"Credentials", title:"Upgrade needed!", nextPage:"", install:false, uninstall: true) {
|
||||
section {
|
||||
paragraph "$upgradeNeeded"
|
||||
@@ -95,15 +100,15 @@ def authPage() {
|
||||
}
|
||||
|
||||
def oauthInitUrl() {
|
||||
// log.debug "runing oauthInitUrl()"
|
||||
log.debug "In oauthInitUrl"
|
||||
|
||||
atomicState.oauthInitState = UUID.randomUUID().toString()
|
||||
state.oauthInitState = UUID.randomUUID().toString()
|
||||
|
||||
def oauthParams = [
|
||||
response_type: "code",
|
||||
client_id: getClientId(),
|
||||
client_secret: getClientSecret(),
|
||||
state: atomicState.oauthInitState,
|
||||
state: state.oauthInitState,
|
||||
redirect_uri: getCallbackUrl(),
|
||||
scope: "read_station"
|
||||
]
|
||||
@@ -114,72 +119,73 @@ def oauthInitUrl() {
|
||||
}
|
||||
|
||||
def callback() {
|
||||
// log.debug "running callback()"
|
||||
// log.debug "callback()>> params: $params, params.code ${params.code}"
|
||||
|
||||
def code = params.code
|
||||
def oauthState = params.state
|
||||
|
||||
if (oauthState == atomicState.oauthInitState) {
|
||||
if (oauthState == state.oauthInitState) {
|
||||
|
||||
def tokenParams = [
|
||||
grant_type: "authorization_code",
|
||||
client_secret: getClientSecret(),
|
||||
client_id : getClientId(),
|
||||
grant_type: "authorization_code",
|
||||
redirect_uri: getCallbackUrl(),
|
||||
code: code,
|
||||
scope: "read_station",
|
||||
redirect_uri: getCallbackUrl()
|
||||
scope: "read_station"
|
||||
]
|
||||
|
||||
// log.debug "TOKEN URL: ${getVendorTokenPath() + toQueryString(tokenParams)}"
|
||||
|
||||
def tokenUrl = getVendorTokenPath()
|
||||
def requestTokenParams = [
|
||||
def params = [
|
||||
uri: tokenUrl,
|
||||
requestContentType: 'application/x-www-form-urlencoded',
|
||||
contentType: 'application/x-www-form-urlencoded',
|
||||
body: tokenParams
|
||||
]
|
||||
|
||||
// log.debug "PARAMS: ${requestTokenParams}"
|
||||
|
||||
try {
|
||||
httpPost(requestTokenParams) { resp ->
|
||||
//log.debug "Data: ${resp.data}"
|
||||
atomicState.refreshToken = resp.data.refresh_token
|
||||
atomicState.authToken = resp.data.access_token
|
||||
// resp.data.expires_in is in milliseconds so we need to convert it to seconds
|
||||
atomicState.tokenExpires = now() + (resp.data.expires_in * 1000)
|
||||
}
|
||||
} catch (e) {
|
||||
log.debug "callback() failed: $e"
|
||||
}
|
||||
// log.debug "PARAMS: ${params}"
|
||||
|
||||
// If we successfully got an authToken run sucess(), else fail()
|
||||
if (atomicState.authToken) {
|
||||
httpPost(params) { resp ->
|
||||
|
||||
def slurper = new JsonSlurper()
|
||||
|
||||
resp.data.each { key, value ->
|
||||
def data = slurper.parseText(key)
|
||||
|
||||
state.refreshToken = data.refresh_token
|
||||
state.authToken = data.access_token
|
||||
state.tokenExpires = now() + (data.expires_in * 1000)
|
||||
// log.debug "swapped token: $resp.data"
|
||||
}
|
||||
}
|
||||
|
||||
// Handle success and failure here, and render stuff accordingly
|
||||
if (state.authToken) {
|
||||
success()
|
||||
} else {
|
||||
fail()
|
||||
}
|
||||
|
||||
} else {
|
||||
log.error "callback() failed oauthState != atomicState.oauthInitState"
|
||||
log.error "callback() failed oauthState != state.oauthInitState"
|
||||
}
|
||||
}
|
||||
|
||||
def success() {
|
||||
log.debug "OAuth flow succeeded"
|
||||
log.debug "in success"
|
||||
def message = """
|
||||
<p>Success!</p>
|
||||
<p>Tap 'Done' to continue</p>
|
||||
<p>We have located your """ + getVendorName() + """ account.</p>
|
||||
<p>Tap 'Done' to continue to Devices.</p>
|
||||
"""
|
||||
connectionStatus(message)
|
||||
}
|
||||
|
||||
def fail() {
|
||||
log.debug "OAuth flow failed"
|
||||
atomicState.authToken = null
|
||||
log.debug "in fail"
|
||||
def message = """
|
||||
<p>Error</p>
|
||||
<p>Tap 'Done' to return</p>
|
||||
<p>The connection could not be established!</p>
|
||||
<p>Click 'Done' to return to the menu.</p>
|
||||
"""
|
||||
connectionStatus(message)
|
||||
}
|
||||
@@ -191,12 +197,13 @@ def connectionStatus(message, redirectUrl = null) {
|
||||
<meta http-equiv="refresh" content="3; url=${redirectUrl}" />
|
||||
"""
|
||||
}
|
||||
|
||||
def html = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Netatmo Connection</title>
|
||||
<title>${getVendorName()} Connection</title>
|
||||
<style type="text/css">
|
||||
* { box-sizing: border-box; }
|
||||
@font-face {
|
||||
@@ -222,6 +229,7 @@ def connectionStatus(message, redirectUrl = null) {
|
||||
.container {
|
||||
width: 100%;
|
||||
padding: 40px;
|
||||
/*background: #eee;*/
|
||||
text-align: center;
|
||||
}
|
||||
img {
|
||||
@@ -237,9 +245,14 @@ def connectionStatus(message, redirectUrl = null) {
|
||||
color: #666666;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
/*
|
||||
p:last-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
*/
|
||||
span {
|
||||
font-family: 'Swiss 721 W01 Light';
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -256,47 +269,46 @@ def connectionStatus(message, redirectUrl = null) {
|
||||
}
|
||||
|
||||
def refreshToken() {
|
||||
// Check if atomicState has a refresh token
|
||||
if (atomicState.refreshToken) {
|
||||
log.debug "running refreshToken()"
|
||||
log.debug "In refreshToken"
|
||||
|
||||
def oauthParams = [
|
||||
grant_type: "refresh_token",
|
||||
refresh_token: atomicState.refreshToken,
|
||||
client_secret: getClientSecret(),
|
||||
client_id: getClientId(),
|
||||
]
|
||||
def oauthParams = [
|
||||
client_secret: getClientSecret(),
|
||||
client_id: getClientId(),
|
||||
grant_type: "refresh_token",
|
||||
refresh_token: state.refreshToken
|
||||
]
|
||||
|
||||
def tokenUrl = getVendorTokenPath()
|
||||
|
||||
def requestOauthParams = [
|
||||
uri: tokenUrl,
|
||||
requestContentType: 'application/x-www-form-urlencoded',
|
||||
body: oauthParams
|
||||
]
|
||||
|
||||
// log.debug "PARAMS: ${requestOauthParams}"
|
||||
def tokenUrl = getVendorTokenPath()
|
||||
def params = [
|
||||
uri: tokenUrl,
|
||||
contentType: 'application/x-www-form-urlencoded',
|
||||
body: oauthParams,
|
||||
]
|
||||
|
||||
try {
|
||||
httpPost(requestOauthParams) { resp ->
|
||||
//log.debug "Data: ${resp.data}"
|
||||
atomicState.refreshToken = resp.data.refresh_token
|
||||
atomicState.authToken = resp.data.access_token
|
||||
// resp.data.expires_in is in milliseconds so we need to convert it to seconds
|
||||
atomicState.tokenExpires = now() + (resp.data.expires_in * 1000)
|
||||
return true
|
||||
}
|
||||
} catch (e) {
|
||||
log.debug "refreshToken() failed: $e"
|
||||
}
|
||||
// OAuth Step 2: Request access token with our client Secret and OAuth "Code"
|
||||
try {
|
||||
httpPost(params) { response ->
|
||||
def slurper = new JsonSlurper();
|
||||
|
||||
// If we didn't get an authToken
|
||||
if (!atomicState.authToken) {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
response.data.each {key, value ->
|
||||
def data = slurper.parseText(key);
|
||||
// log.debug "Data: $data"
|
||||
|
||||
state.refreshToken = data.refresh_token
|
||||
state.accessToken = data.access_token
|
||||
state.tokenExpires = now() + (data.expires_in * 1000)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug "Error: $e"
|
||||
}
|
||||
|
||||
// We didn't get an access token
|
||||
if ( !state.accessToken ) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
String toQueryString(Map m) {
|
||||
@@ -305,11 +317,13 @@ String toQueryString(Map m) {
|
||||
|
||||
def installed() {
|
||||
log.debug "Installed with settings: ${settings}"
|
||||
|
||||
initialize()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "Updated with settings: ${settings}"
|
||||
|
||||
unsubscribe()
|
||||
unschedule()
|
||||
initialize()
|
||||
@@ -317,9 +331,9 @@ def updated() {
|
||||
|
||||
def initialize() {
|
||||
log.debug "Initialized with settings: ${settings}"
|
||||
|
||||
|
||||
// Pull the latest device info into state
|
||||
getDeviceList()
|
||||
getDeviceList();
|
||||
|
||||
settings.devices.each {
|
||||
def deviceId = it
|
||||
@@ -353,56 +367,57 @@ def initialize() {
|
||||
def delete = getChildDevices().findAll { !settings.devices.contains(it.deviceNetworkId) }
|
||||
log.debug "Delete: $delete"
|
||||
delete.each { deleteChildDevice(it.deviceNetworkId) }
|
||||
|
||||
// Run initial poll and schedule future polls
|
||||
|
||||
// Do the initial poll
|
||||
poll()
|
||||
// Schedule it to run every 5 minutes
|
||||
runEvery5Minutes("poll")
|
||||
}
|
||||
|
||||
def uninstalled() {
|
||||
log.debug "Uninstalling"
|
||||
log.debug "In uninstalled"
|
||||
|
||||
removeChildDevices(getChildDevices())
|
||||
}
|
||||
|
||||
def getDeviceList() {
|
||||
if (atomicState.authToken) {
|
||||
|
||||
log.debug "Getting stations data"
|
||||
log.debug "In getDeviceList"
|
||||
|
||||
def deviceList = [:]
|
||||
state.deviceDetail = [:]
|
||||
state.deviceState = [:]
|
||||
def deviceList = [:]
|
||||
state.deviceDetail = [:]
|
||||
state.deviceState = [:]
|
||||
|
||||
apiGet("/api/getstationsdata") { resp ->
|
||||
resp.data.body.devices.each { value ->
|
||||
def key = value._id
|
||||
deviceList[key] = "${value.station_name}: ${value.module_name}"
|
||||
state.deviceDetail[key] = value
|
||||
state.deviceState[key] = value.dashboard_data
|
||||
value.modules.each { value2 ->
|
||||
def key2 = value2._id
|
||||
deviceList[key2] = "${value.station_name}: ${value2.module_name}"
|
||||
state.deviceDetail[key2] = value2
|
||||
state.deviceState[key2] = value2.dashboard_data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deviceList.sort() { it.value.toLowerCase() }
|
||||
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
apiGet("/api/devicelist") { response ->
|
||||
response.data.body.devices.each { value ->
|
||||
def key = value._id
|
||||
deviceList[key] = "${value.station_name}: ${value.module_name}"
|
||||
state.deviceDetail[key] = value
|
||||
state.deviceState[key] = value.dashboard_data
|
||||
}
|
||||
response.data.body.modules.each { value ->
|
||||
def key = value._id
|
||||
deviceList[key] = "${state.deviceDetail[value.main_device].station_name}: ${value.module_name}"
|
||||
state.deviceDetail[key] = value
|
||||
state.deviceState[key] = value.dashboard_data
|
||||
}
|
||||
}
|
||||
|
||||
return deviceList.sort() { it.value.toLowerCase() }
|
||||
}
|
||||
|
||||
private removeChildDevices(delete) {
|
||||
log.debug "Removing ${delete.size()} devices"
|
||||
log.debug "In removeChildDevices"
|
||||
|
||||
log.debug "deleting ${delete.size()} devices"
|
||||
|
||||
delete.each {
|
||||
deleteChildDevice(it.deviceNetworkId)
|
||||
}
|
||||
}
|
||||
|
||||
def createChildDevice(deviceFile, dni, name, label) {
|
||||
log.debug "In createChildDevice"
|
||||
|
||||
try {
|
||||
def existingDevice = getChildDevice(dni)
|
||||
if(!existingDevice) {
|
||||
@@ -417,13 +432,13 @@ def createChildDevice(deviceFile, dni, name, label) {
|
||||
}
|
||||
|
||||
def listDevices() {
|
||||
log.debug "Listing devices"
|
||||
log.debug "In listDevices"
|
||||
|
||||
def devices = getDeviceList()
|
||||
|
||||
dynamicPage(name: "listDevices", title: "Choose Devices", install: true) {
|
||||
dynamicPage(name: "listDevices", title: "Choose devices", install: true) {
|
||||
section("Devices") {
|
||||
input "devices", "enum", title: "Select Devices", required: false, multiple: true, options: devices
|
||||
input "devices", "enum", title: "Select Device(s)", required: false, multiple: true, options: devices
|
||||
}
|
||||
|
||||
section("Preferences") {
|
||||
@@ -433,36 +448,30 @@ def listDevices() {
|
||||
}
|
||||
|
||||
def apiGet(String path, Map query, Closure callback) {
|
||||
log.debug "running apiGet()"
|
||||
|
||||
// If the current time is over the expiration time, request a new token
|
||||
if(now() >= atomicState.tokenExpires) {
|
||||
atomicState.authToken = null
|
||||
refreshToken()
|
||||
if(now() >= state.tokenExpires) {
|
||||
refreshToken();
|
||||
}
|
||||
|
||||
def queryParam = [
|
||||
access_token: atomicState.authToken
|
||||
]
|
||||
|
||||
def apiGetParams = [
|
||||
query['access_token'] = state.accessToken
|
||||
def params = [
|
||||
uri: getApiUrl(),
|
||||
path: path,
|
||||
query: queryParam
|
||||
'query': query
|
||||
]
|
||||
|
||||
// log.debug "apiGet(): $apiGetParams"
|
||||
// log.debug "API Get: $params"
|
||||
|
||||
try {
|
||||
httpGet(apiGetParams) { resp ->
|
||||
callback.call(resp)
|
||||
httpGet(params) { response ->
|
||||
callback.call(response)
|
||||
}
|
||||
} catch (e) {
|
||||
log.debug "apiGet() failed: $e"
|
||||
// Netatmo API has rate limits so a failure here doesn't necessarily mean our token has expired, but we will check anyways
|
||||
if(now() >= atomicState.tokenExpires) {
|
||||
atomicState.authToken = null
|
||||
refreshToken()
|
||||
} catch (Exception e) {
|
||||
// This is most likely due to an invalid token. Try to refresh it and try again.
|
||||
log.debug "apiGet: Call failed $e"
|
||||
if(refreshToken()) {
|
||||
log.debug "apiGet: Trying again after refreshing token"
|
||||
httpGet(params) { response ->
|
||||
callback.call(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -472,12 +481,10 @@ def apiGet(String path, Closure callback) {
|
||||
}
|
||||
|
||||
def poll() {
|
||||
log.debug "Polling..."
|
||||
|
||||
getDeviceList()
|
||||
|
||||
log.debug "In Poll"
|
||||
getDeviceList();
|
||||
def children = getChildDevices()
|
||||
//log.debug "State: ${state.deviceState}"
|
||||
log.debug "State: ${state.deviceState}"
|
||||
|
||||
settings.devices.each { deviceId ->
|
||||
def detail = state?.deviceDetail[deviceId]
|
||||
@@ -533,13 +540,15 @@ def rainToPref(rain) {
|
||||
}
|
||||
|
||||
def debugEvent(message, displayEvent) {
|
||||
|
||||
def results = [
|
||||
name: "appdebug",
|
||||
descriptionText: message,
|
||||
displayed: displayEvent
|
||||
]
|
||||
log.debug "Generating AppDebug Event: ${results}"
|
||||
sendEvent(results)
|
||||
sendEvent (results)
|
||||
|
||||
}
|
||||
|
||||
private Boolean canInstallLabs() {
|
||||
@@ -552,4 +561,4 @@ private Boolean hasAllHubsOver(String desiredFirmware) {
|
||||
|
||||
private List getRealHubFirmwareVersions() {
|
||||
return location.hubs*.firmwareVersionString.findAll { it }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,253 +1,548 @@
|
||||
/**
|
||||
* Gideon
|
||||
*
|
||||
* Copyright 2016 Nicola Russo
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
definition(
|
||||
name: "Gideon",
|
||||
namespace: "gideon.api",
|
||||
author: "Braindrain Solutions",
|
||||
description: "Gideon AI Smart app allows you to connect and control all of your SmartThings devices through the Gideon AI app, making your SmartThings devices even smarter.",
|
||||
category: "Family",
|
||||
iconUrl: "http://s33.postimg.org/t77u7y7v3/logo.png",
|
||||
iconX2Url: "http://s33.postimg.org/t77u7y7v3/logo.png",
|
||||
iconX3Url: "http://s33.postimg.org/t77u7y7v3/logo.png",
|
||||
oauth: [displayName: "Gideon AI API", displayLink: "gideon.ai"])
|
||||
|
||||
|
||||
preferences {
|
||||
section("Control these switches...") {
|
||||
input "switches", "capability.switch", multiple:true
|
||||
}
|
||||
section("Control these motion sensors...") {
|
||||
input "motions", "capability.motionSensor", multiple:true
|
||||
}
|
||||
section("Control these presence sensors...") {
|
||||
input "presence_sensors", "capability.presenceSensor", multiple:true
|
||||
}
|
||||
section("Control these outlets...") {
|
||||
input "outlets", "capability.switch", multiple:true
|
||||
}
|
||||
section("Control these locks...") {
|
||||
input "locks", "capability.lock", multiple:true
|
||||
}
|
||||
section("Control these locks...") {
|
||||
input "temperature_sensors", "capability.temperatureMeasurement"
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
log.debug "Installed with settings: ${settings}"
|
||||
|
||||
initialize()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "Updated with settings: ${settings}"
|
||||
|
||||
unsubscribe()
|
||||
initialize()
|
||||
}
|
||||
|
||||
def initialize() {
|
||||
// TODO: subscribe to attributes, devices, locations, etc.
|
||||
subscribe(outlet, "energy", outletHandler)
|
||||
subscribe(outlet, "switch", outletHandler)
|
||||
}
|
||||
|
||||
// TODO: implement event handlers
|
||||
def outletHandler(evt) {
|
||||
log.debug "$outlet.currentEnergy"
|
||||
//TODO call G API
|
||||
}
|
||||
|
||||
|
||||
private device(it, type) {
|
||||
it ? [id: it.id, label: it.label, type: type] : null
|
||||
}
|
||||
|
||||
//API Mapping
|
||||
mappings {
|
||||
path("/getalldevices") {
|
||||
action: [
|
||||
GET: "getAllDevices"
|
||||
]
|
||||
}
|
||||
path("/doorlocks/:id/:command") {
|
||||
action: [
|
||||
GET: "updateDoorLock"
|
||||
]
|
||||
}
|
||||
path("/doorlocks/:id") {
|
||||
action: [
|
||||
GET: "getDoorLockStatus"
|
||||
]
|
||||
}
|
||||
path("/tempsensors/:id") {
|
||||
action: [
|
||||
GET: "getTempSensorsStatus"
|
||||
]
|
||||
}
|
||||
path("/presences/:id") {
|
||||
action: [
|
||||
GET: "getPresenceStatus"
|
||||
]
|
||||
}
|
||||
path("/motions/:id") {
|
||||
action: [
|
||||
GET: "getMotionStatus"
|
||||
]
|
||||
}
|
||||
path("/outlets/:id") {
|
||||
action: [
|
||||
GET: "getOutletStatus"
|
||||
]
|
||||
}
|
||||
path("/outlets/:id/:command") {
|
||||
action: [
|
||||
GET: "updateOutlet"
|
||||
]
|
||||
}
|
||||
path("/switches/:command") {
|
||||
action: [
|
||||
PUT: "updateSwitch"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
//API Methods
|
||||
def getAllDevices() {
|
||||
def locks_list = locks.collect{device(it,"Lock")}
|
||||
def presences_list = presence_sensors.collect{device(it,"Presence")}
|
||||
def motions_list = motions.collect{device(it,"Motion")}
|
||||
def outlets_list = outlets.collect{device(it,"Outlet")}
|
||||
def switches_list = switches.collect{device(it,"Switch")}
|
||||
def temp_list = temperature_sensors.collect{device(it,"Temperature")}
|
||||
return [Locks: locks_list, Presences: presences_list, Motions: motions_list, Outlets: outlets_list, Switches: switches_list, Temperatures: temp_list]
|
||||
}
|
||||
|
||||
//LOCKS
|
||||
def getDoorLockStatus() {
|
||||
def device = locks.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
return [Device_state: device.currentValue('lock')]
|
||||
}
|
||||
}
|
||||
|
||||
def updateDoorLock() {
|
||||
def command = params.command
|
||||
def device = locks.find { it.id == params.id }
|
||||
if (command){
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
if(command == "toggle")
|
||||
{
|
||||
if(device.currentValue('lock') == "locked")
|
||||
device.unlock();
|
||||
else
|
||||
device.lock();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//PRESENCE
|
||||
def getPresenceStatus() {
|
||||
|
||||
def device = presence_sensors.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
return [Device_state: device.currentValue('presence')]
|
||||
}
|
||||
}
|
||||
|
||||
//MOTION
|
||||
def getMotionStatus() {
|
||||
|
||||
def device = motions.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
return [Device_state: device.currentValue('motion')]
|
||||
}
|
||||
}
|
||||
|
||||
//OUTLET
|
||||
def getOutletStatus() {
|
||||
|
||||
def device = outlets.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
return [Device_state: device.currentSwitch, Current_watt: device.currentValue("energy")]
|
||||
}
|
||||
}
|
||||
|
||||
def updateOutlet() {
|
||||
|
||||
def command = params.command
|
||||
def device = outlets.find { it.id == params.id }
|
||||
if (command){
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
if(command == "toggle")
|
||||
{
|
||||
if(device.currentSwitch == "on")
|
||||
device.off();
|
||||
else
|
||||
device.on();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//SWITCH
|
||||
def updateSwitch() {
|
||||
def command = params.command
|
||||
def device = switches.find { it.id == params.id }
|
||||
if (command){
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
if(command == "toggle")
|
||||
{
|
||||
if(device.currentSwitch == "on")
|
||||
device.off();
|
||||
else
|
||||
device.on();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TEMPERATURE
|
||||
def getTempSensorsStatus() {
|
||||
|
||||
def device = temperature_sensors.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
return [Device_state: device.currentValue('temperature')]
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gideon
|
||||
*
|
||||
* Copyright 2016 Nicola Russo
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
definition(
|
||||
name: "Gideon",
|
||||
namespace: "gideon.api",
|
||||
author: "Braindrain Solutions ltd",
|
||||
description: "Gideon Smart Home SmartApp allows you to connect and control all of your SmartThings devices through the Gideon app, making your SmartThings devices even smarter.",
|
||||
category: "Family",
|
||||
iconUrl: "http://s33.postimg.org/t77u7y7v3/logo.png",
|
||||
iconX2Url: "http://s33.postimg.org/t77u7y7v3/logo.png",
|
||||
iconX3Url: "http://s33.postimg.org/t77u7y7v3/logo.png",
|
||||
oauth: [displayName: "Gideon Smart Home API app", displayLink: "gideon.ai"])
|
||||
|
||||
|
||||
preferences {
|
||||
section("Control these contact sensors...") {
|
||||
input "contact", "capability.contactSensor", multiple:true, required:false
|
||||
}
|
||||
section("Control these switches...") {
|
||||
input "switches", "capability.switch", multiple:true, required:false
|
||||
}
|
||||
section("Control these smoke alarms...") {
|
||||
input "smoke_alarms", "capability.smokeDetector", multiple:true, required:false
|
||||
}
|
||||
section("Control these window shades...") {
|
||||
input "shades", "capability.windowShade", multiple:true, required:false
|
||||
}
|
||||
section("Control these garage doors...") {
|
||||
input "garage", "capability.garageDoorControl", multiple:true, required:false
|
||||
}
|
||||
section("Control these water sensors...") {
|
||||
input "water_sensors", "capability.waterSensor", multiple:true, required:false
|
||||
}
|
||||
section("Control these motion sensors...") {
|
||||
input "motions", "capability.motionSensor", multiple:true, required:false
|
||||
}
|
||||
section("Control these presence sensors...") {
|
||||
input "presence_sensors", "capability.presenceSensor", multiple:true, required:false
|
||||
}
|
||||
/** section("Control these outlets...") {
|
||||
input "outlets", "capability.switch", multiple:true, required:false
|
||||
}
|
||||
*/
|
||||
section("Control these power meters...") {
|
||||
input "meters", "capability.powerMeter", multiple:true, required:false
|
||||
}
|
||||
section("Control these locks...") {
|
||||
input "locks", "capability.lock", multiple:true, required:false
|
||||
}
|
||||
section("Control these temperature sensors...") {
|
||||
input "temperature_sensors", "capability.temperatureMeasurement", multiple:true, required:false
|
||||
}
|
||||
section("Control these batteries...") {
|
||||
input "batteries", "capability.battery", multiple:true, required:false
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
log.debug "Installed with settings: ${settings}"
|
||||
|
||||
initialize()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "Updated with settings: ${settings}"
|
||||
|
||||
unsubscribe()
|
||||
initialize()
|
||||
}
|
||||
|
||||
def initialize() {
|
||||
}
|
||||
|
||||
private device(it, type) {
|
||||
it ? [id: it.id, label: it.label, type: type] : null
|
||||
}
|
||||
|
||||
//API Mapping
|
||||
mappings {
|
||||
path("/getalldevices") {
|
||||
action: [
|
||||
GET: "getAllDevices"
|
||||
]
|
||||
}
|
||||
path("/doorlocks/lock/:id") {
|
||||
action: [
|
||||
GET: "lockDoorLock"
|
||||
]
|
||||
}
|
||||
path("/doorlocks/unlock/:id") {
|
||||
action: [
|
||||
GET: "unlockDoorLock"
|
||||
]
|
||||
}
|
||||
path("/doorlocks/:id") {
|
||||
action: [
|
||||
GET: "getDoorLockStatus"
|
||||
]
|
||||
}
|
||||
path("/contacts/:id") {
|
||||
action: [
|
||||
GET: "getContactStatus"
|
||||
]
|
||||
}
|
||||
path("/smoke/:id") {
|
||||
action: [
|
||||
GET: "getSmokeStatus"
|
||||
]
|
||||
}
|
||||
path("/shades/open/:id") {
|
||||
action: [
|
||||
GET: "openShade"
|
||||
]
|
||||
}
|
||||
path("/shades/preset/:id") {
|
||||
action: [
|
||||
GET: "presetShade"
|
||||
]
|
||||
}
|
||||
path("/shades/close/:id") {
|
||||
action: [
|
||||
GET: "closeShade"
|
||||
]
|
||||
}
|
||||
path("/shades/:id") {
|
||||
action: [
|
||||
GET: "getShadeStatus"
|
||||
]
|
||||
}
|
||||
path("/garage/open/:id") {
|
||||
action: [
|
||||
GET: "openGarage"
|
||||
]
|
||||
}
|
||||
path("/garage/close/:id") {
|
||||
action: [
|
||||
GET: "closeGarage"
|
||||
]
|
||||
}
|
||||
path("/garage/:id") {
|
||||
action: [
|
||||
GET: "getGarageStatus"
|
||||
]
|
||||
}
|
||||
path("/watersensors/:id") {
|
||||
action: [
|
||||
GET: "getWaterSensorStatus"
|
||||
]
|
||||
}
|
||||
path("/tempsensors/:id") {
|
||||
action: [
|
||||
GET: "getTempSensorsStatus"
|
||||
]
|
||||
}
|
||||
path("/meters/:id") {
|
||||
action: [
|
||||
GET: "getMeterStatus"
|
||||
]
|
||||
}
|
||||
path("/batteries/:id") {
|
||||
action: [
|
||||
GET: "getBatteryStatus"
|
||||
]
|
||||
}
|
||||
path("/presences/:id") {
|
||||
action: [
|
||||
GET: "getPresenceStatus"
|
||||
]
|
||||
}
|
||||
path("/motions/:id") {
|
||||
action: [
|
||||
GET: "getMotionStatus"
|
||||
]
|
||||
}
|
||||
/** path("/outlets/:id") {
|
||||
action: [
|
||||
GET: "getOutletStatus"
|
||||
]
|
||||
}
|
||||
path("/outlets/turnon/:id") {
|
||||
action: [
|
||||
GET: "turnOnOutlet"
|
||||
]
|
||||
}
|
||||
path("/outlets/turnoff/:id") {
|
||||
action: [
|
||||
GET: "turnOffOutlet"
|
||||
]
|
||||
}
|
||||
*/
|
||||
path("/switches/turnon/:id") {
|
||||
action: [
|
||||
GET: "turnOnSwitch"
|
||||
]
|
||||
}
|
||||
path("/switches/turnoff/:id") {
|
||||
action: [
|
||||
GET: "turnOffSwitch"
|
||||
]
|
||||
}
|
||||
path("/switches/:id") {
|
||||
action: [
|
||||
GET: "getSwitchStatus"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
//API Methods
|
||||
def getAllDevices() {
|
||||
def locks_list = locks.collect{device(it,"Lock")}
|
||||
def contact_list = contact.collect{device(it,"Contact Sensor")}
|
||||
def smokes_list = smoke_alarms.collect{device(it,"Smoke Alarm")}
|
||||
def shades_list = shades.collect{device(it,"Window Shade")}
|
||||
def garage_list = garage.collect{device(it,"Garage Door")}
|
||||
def water_sensors_list = water_sensors.collect{device(it,"Water Sensor")}
|
||||
def presences_list = presence_sensors.collect{device(it,"Presence")}
|
||||
def motions_list = motions.collect{device(it,"Motion")}
|
||||
/** def outlets_list = outlets.collect{device(it,"Outlet")} */
|
||||
def switches_list = switches.collect{device(it,"Switch")}
|
||||
def temp_list = temperature_sensors.collect{device(it,"Temperature")}
|
||||
def meters_list = meters.collect{device(it,"Power Meters")}
|
||||
def battery_list = batteries.collect{device(it,"Batteries")}
|
||||
return smokes_list + contact_list + water_sensors_list + shades_list + garage_list + locks_list + presences_list + motions_list + switches_list + temp_list + meters_list + battery_list
|
||||
}
|
||||
|
||||
//contact sensors
|
||||
def getContactStatus() {
|
||||
def device = contact.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
def args = getTempSensorsStatus(device.id)
|
||||
return [Device_state: device.currentValue('contact')] + args
|
||||
}
|
||||
}
|
||||
|
||||
//smoke detectors
|
||||
def getSmokeStatus() {
|
||||
def device = smoke_alarms.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
def bat = getBatteryStatus(device.id)
|
||||
return [Device_state: device.currentValue('smoke')] + bat
|
||||
}
|
||||
}
|
||||
|
||||
//garage
|
||||
def getGarageStatus() {
|
||||
def device = garage.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
return [Device_state: device.currentValue('door')]
|
||||
}
|
||||
}
|
||||
|
||||
def openGarage() {
|
||||
def device = garage.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
|
||||
device.open();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
|
||||
def closeGarage() {
|
||||
def device = garage.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
|
||||
device.close();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
//shades
|
||||
def getShadeStatus() {
|
||||
def device = shades.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
return [Device_state: device.currentValue('windowShade')]
|
||||
}
|
||||
}
|
||||
|
||||
def openShade() {
|
||||
def device = shades.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
|
||||
device.open();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
|
||||
def presetShade() {
|
||||
def device = shades.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
|
||||
device.presetPosition();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
|
||||
def closeShade() {
|
||||
def device = shades.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
|
||||
device.close();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
|
||||
//water sensor
|
||||
def getWaterSensorStatus() {
|
||||
def device = water_sensors.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
def bat = getBatteryStatus(device.id)
|
||||
return [Device_state: device.currentValue('water')] + bat
|
||||
}
|
||||
}
|
||||
//batteries
|
||||
def getBatteryStatus() {
|
||||
def device = batteries.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
return [Device_state: device.latestValue("battery")]
|
||||
}
|
||||
}
|
||||
|
||||
def getBatteryStatus(id) {
|
||||
def device = batteries.find { it.id == id }
|
||||
if (!device) {
|
||||
return []
|
||||
} else {
|
||||
return [battery_state: device.latestValue("battery")]
|
||||
}
|
||||
}
|
||||
|
||||
//LOCKS
|
||||
def getDoorLockStatus() {
|
||||
def device = locks.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
def bat = getBatteryStatus(device.id)
|
||||
return [Device_state: device.currentValue('lock')] + bat
|
||||
}
|
||||
}
|
||||
|
||||
def lockDoorLock() {
|
||||
def device = locks.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
|
||||
device.lock();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
|
||||
def unlockDoorLock() {
|
||||
def device = locks.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
|
||||
device.unlock();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
//PRESENCE
|
||||
def getPresenceStatus() {
|
||||
|
||||
def device = presence_sensors.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
def bat = getBatteryStatus(device.id)
|
||||
return [Device_state: device.currentValue('presence')] + bat
|
||||
}
|
||||
}
|
||||
|
||||
//MOTION
|
||||
def getMotionStatus() {
|
||||
|
||||
def device = motions.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
def args = getTempSensorsStatus(device.id)
|
||||
return [Device_state: device.currentValue('motion')] + args
|
||||
}
|
||||
}
|
||||
|
||||
//OUTLET
|
||||
/**
|
||||
def getOutletStatus() {
|
||||
|
||||
def device = outlets.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
def watt = getMeterStatus(device.id)
|
||||
return [Device_state: device.currentSwitch] + watt
|
||||
}
|
||||
}
|
||||
*/
|
||||
def getMeterStatus() {
|
||||
|
||||
def device = meters.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
return [Device_id: device.id, Device_type: device.type, Current_watt: device.currentValue("power")]
|
||||
}
|
||||
}
|
||||
|
||||
def getMeterStatus(id) {
|
||||
|
||||
def device = meters.find { it.id == id }
|
||||
if (!device) {
|
||||
return []
|
||||
} else {
|
||||
return [Current_watt: device.currentValue("power")]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
def turnOnOutlet() {
|
||||
def device = outlets.find { it.id == params.id }
|
||||
if (command){
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
|
||||
device.on();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def turnOffOutlet() {
|
||||
def device = outlets.find { it.id == params.id }
|
||||
if (command){
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
|
||||
device.off();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
//SWITCH
|
||||
def getSwitchStatus() {
|
||||
def device = switches.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
return [Device_state: device.currentValue('switch')]
|
||||
}
|
||||
}
|
||||
|
||||
def turnOnSwitch() {
|
||||
def device = switches.find { it.id == params.id }
|
||||
if (command){
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
|
||||
device.on();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def turnOffSwitch() {
|
||||
def device = switches.find { it.id == params.id }
|
||||
if (command){
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
|
||||
device.on();
|
||||
|
||||
return [Device_id: params.id, result_action: "200"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//TEMPERATURE
|
||||
def getTempSensorsStatus() {
|
||||
|
||||
def device = temperature_sensors.find { it.id == params.id }
|
||||
if (!device) {
|
||||
httpError(404, "Device not found")
|
||||
} else {
|
||||
def bat = getBatteryStatus(device.id)
|
||||
return [Device_state: device.currentValue('temperature')] + bat
|
||||
}
|
||||
}
|
||||
|
||||
def getTempSensorsStatus(id) {
|
||||
def device = temperature_sensors.find { it.id == id }
|
||||
if (!device) {
|
||||
return []
|
||||
} else {
|
||||
def bat = getBatteryStatus(device.id)
|
||||
return [temperature: device.currentValue('temperature')] + bat
|
||||
}
|
||||
}
|
||||
@@ -1,465 +0,0 @@
|
||||
/**
|
||||
* OpenT2T SmartApp Test
|
||||
*
|
||||
* Copyright 2016 OpenT2T
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
definition(
|
||||
name: "OpenT2T SmartApp Test",
|
||||
namespace: "opent2t",
|
||||
author: "OpenT2T",
|
||||
description: "Test app to test end to end SmartThings scenarios via OpenT2T",
|
||||
category: "SmartThings Labs",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
|
||||
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")
|
||||
|
||||
/** --------------------+---------------+-----------------------+------------------------------------
|
||||
* Device Type | Attribute Name| Commands | Attribute Values
|
||||
* --------------------+---------------+-----------------------+------------------------------------
|
||||
* switches | switch | on, off | on, off
|
||||
* motionSensors | motion | | active, inactive
|
||||
* contactSensors | contact | | open, closed
|
||||
* presenceSensors | presence | | present, 'not present'
|
||||
* temperatureSensors | temperature | | <numeric, F or C according to unit>
|
||||
* accelerationSensors | acceleration | | active, inactive
|
||||
* waterSensors | water | | wet, dry
|
||||
* lightSensors | illuminance | | <numeric, lux>
|
||||
* humiditySensors | humidity | | <numeric, percent>
|
||||
* locks | lock | lock, unlock | locked, unlocked
|
||||
* garageDoors | door | open, close | unknown, closed, open, closing, opening
|
||||
* cameras | image | take | <String>
|
||||
* thermostats | thermostat | setHeatingSetpoint, | temperature, heatingSetpoint, coolingSetpoint,
|
||||
* | | setCoolingSetpoint, | thermostatSetpoint, thermostatMode,
|
||||
* | | off, heat, cool, auto,| thermostatFanMode, thermostatOperatingState
|
||||
* | | emergencyHeat, |
|
||||
* | | setThermostatMode, |
|
||||
* | | fanOn, fanAuto, |
|
||||
* | | fanCirculate, |
|
||||
* | | setThermostatFanMode |
|
||||
* --------------------+---------------+-----------------------+------------------------------------
|
||||
*/
|
||||
|
||||
//Device Inputs
|
||||
preferences {
|
||||
section("Allow OpenT2T to control these things...") {
|
||||
input "contactSensors", "capability.contactSensor", title: "Which Contact Sensors", multiple: true, required: false
|
||||
input "garageDoors", "capability.garageDoorControl", title: "Which Garage Doors?", multiple: true, required: false
|
||||
input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false
|
||||
input "cameras", "capability.videoCapture", title: "Which Cameras?", multiple: true, required: false
|
||||
input "motionSensors", "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false
|
||||
input "presenceSensors", "capability.presenceSensor", title: "Which Presence Sensors", multiple: true, required: false
|
||||
input "switches", "capability.switch", title: "Which Switches and Lights?", multiple: true, required: false
|
||||
input "thermostats", "capability.thermostat", title: "Which Thermostat?", multiple: true, required: false
|
||||
input "waterSensors", "capability.waterSensor", title: "Which Water Leak Sensors?", multiple: true, required: false
|
||||
}
|
||||
}
|
||||
|
||||
def getInputs() {
|
||||
def inputList = []
|
||||
inputList += contactSensors ?: []
|
||||
inputList += garageDoors ?: []
|
||||
inputList += locks ?: []
|
||||
inputList += cameras ?: []
|
||||
inputList += motionSensors ?: []
|
||||
inputList += presenceSensors ?: []
|
||||
inputList += switches ?: []
|
||||
inputList += thermostats ?: []
|
||||
inputList += waterSensors ?: []
|
||||
return inputList
|
||||
}
|
||||
|
||||
//API external Endpoints
|
||||
mappings {
|
||||
path("/subscriptionURL/:url") {
|
||||
action:
|
||||
[
|
||||
PUT: "updateEndpointURL"
|
||||
]
|
||||
}
|
||||
path("/connectionId/:connId") {
|
||||
action:
|
||||
[
|
||||
PUT: "updateConnectionId"
|
||||
]
|
||||
}
|
||||
path("/devices") {
|
||||
action:
|
||||
[
|
||||
GET: "getDevices"
|
||||
]
|
||||
}
|
||||
path("/devices/:id") {
|
||||
action:
|
||||
[
|
||||
GET: "getDevice"
|
||||
]
|
||||
}
|
||||
path("/update/:id") {
|
||||
action:
|
||||
[
|
||||
PUT: "updateDevice"
|
||||
]
|
||||
}
|
||||
path("/subscription/:id") {
|
||||
action:
|
||||
[
|
||||
POST : "registerDeviceChange",
|
||||
DELETE: "unregisterDeviceChange"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
log.debug "Installed with settings: ${settings}"
|
||||
initialize()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "Updated with settings: ${settings}"
|
||||
unsubscribe()
|
||||
registerSubscriptions()
|
||||
}
|
||||
|
||||
def initialize() {
|
||||
state.connectionId = ""
|
||||
state.endpointURL = "https://ifs.windows-int.com/v1/cb/81C7E77B-EABC-488A-B2BF-FEC42F0DABD2/notify"
|
||||
registerSubscriptions()
|
||||
}
|
||||
|
||||
//Subscribe events for all devices
|
||||
def registerSubscriptions() {
|
||||
registerChangeHandler(inputs)
|
||||
}
|
||||
|
||||
//Subscribe to events from a list of devices
|
||||
def registerChangeHandler(myList) {
|
||||
myList.each { myDevice ->
|
||||
def theAtts = myDevice.supportedAttributes
|
||||
theAtts.each { att ->
|
||||
subscribe(myDevice, att.name, eventHandler)
|
||||
log.info "Registering ${myDevice.displayName}.${att.name}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Endpoints function: Subscribe to events from a specific device
|
||||
def registerDeviceChange() {
|
||||
def myDevice = findDevice(params.id)
|
||||
def theAtts = myDevice.supportedAttributes
|
||||
try {
|
||||
theAtts.each { att ->
|
||||
subscribe(myDevice, att.name, eventHandler)
|
||||
log.info "Registering ${myDevice.displayName}.${att.name}"
|
||||
}
|
||||
return ["succeed"]
|
||||
} catch (e) {
|
||||
httpError(500, "something went wrong: $e")
|
||||
}
|
||||
}
|
||||
|
||||
//Endpoints function: Unsubscribe to events from a specific device
|
||||
def unregisterDeviceChange() {
|
||||
def myDevice = findDevice(params.id)
|
||||
try {
|
||||
unsubscribe(myDevice)
|
||||
log.info "Unregistering ${myDevice.displayName}"
|
||||
return ["succeed"]
|
||||
} catch (e) {
|
||||
httpError(500, "something went wrong: $e")
|
||||
}
|
||||
}
|
||||
|
||||
//When events are triggered, send HTTP post to web socket servers
|
||||
def eventHandler(evt) {
|
||||
def evt_device_id = evt.deviceId
|
||||
def evt_device_value = evt.value
|
||||
def evt_name = evt.name
|
||||
def evt_device = evt.device
|
||||
def evt_deviceType = getDeviceType(evt_device);
|
||||
def params = [
|
||||
uri : "${state.endpointURL}/${state.connectionId}",
|
||||
body: [
|
||||
name : evt_device.displayName,
|
||||
id : evt_device.id,
|
||||
deviceType : evt_deviceType,
|
||||
manufacturer: evt_device.getManufacturerName(),
|
||||
model : evt_device.getModelName(),
|
||||
attributes : deviceAttributeList(evt_device)
|
||||
]
|
||||
]
|
||||
try {
|
||||
log.trace "POST URI: ${params.uri}"
|
||||
log.trace "Payload: ${params.body}"
|
||||
httpPostJson(params) { resp ->
|
||||
resp.headers.each {
|
||||
log.debug "${it.name} : ${it.value}"
|
||||
}
|
||||
log.trace "response status code: ${resp.status}"
|
||||
log.trace "response data: ${resp.data}"
|
||||
}
|
||||
} catch (e) {
|
||||
log.debug "something went wrong: $e"
|
||||
}
|
||||
}
|
||||
|
||||
//Endpoints function: update subcription endpoint url [state.endpoint]
|
||||
void updateEndpointURL() {
|
||||
state.endpointURL = params.url
|
||||
log.info "Updated EndpointURL to ${state.endpointURL}"
|
||||
}
|
||||
|
||||
//Endpoints function: update global variable [state.connectionId]
|
||||
void updateConnectionId() {
|
||||
def connId = params.connId
|
||||
state.connectionId = connId
|
||||
log.info "Updated ConnectionID to ${state.connectionId}"
|
||||
}
|
||||
|
||||
//Endpoints function: return all device data in json format
|
||||
def getDevices() {
|
||||
def deviceData = []
|
||||
inputs?.each {
|
||||
def deviceType = getDeviceType(it)
|
||||
if (deviceType == "thermostat") {
|
||||
deviceData << [name: it.displayName, id: it.id, deviceType: deviceType, manufacturer: it.getManufacturerName(), model: it.getModelName(), attributes: deviceAttributeList(it), locationMode: getLocationModeInfo()]
|
||||
} else {
|
||||
deviceData << [name: it.displayName, id: it.id, deviceType: deviceType, manufacturer: it.getManufacturerName(), model: it.getModelName(), attributes: deviceAttributeList(it)]
|
||||
}
|
||||
}
|
||||
|
||||
log.debug "getDevices, return: ${deviceData}"
|
||||
return deviceData
|
||||
}
|
||||
|
||||
//Endpoints function: get device data
|
||||
def getDevice() {
|
||||
def it = findDevice(params.id)
|
||||
def deviceType = getDeviceType(it)
|
||||
def device
|
||||
if (deviceType == "thermostat") {
|
||||
device = [name: it.displayName, id: it.id, deviceType: deviceType, manufacturer: it.getManufacturerName(), model: it.getModelName(), attributes: deviceAttributeList(it), locationMode: getLocationModeInfo()]
|
||||
} else {
|
||||
device = [name: it.displayName, id: it.id, deviceType: deviceType, manufacturer: it.getManufacturerName(), model: it.getModelName(), attributes: deviceAttributeList(it)]
|
||||
}
|
||||
log.debug "getDevice, return: ${device}"
|
||||
return device
|
||||
}
|
||||
|
||||
//Endpoints function: update device data
|
||||
void updateDevice() {
|
||||
def device = findDevice(params.id)
|
||||
request.JSON.each {
|
||||
def command = it.key
|
||||
def value = it.value
|
||||
if (command) {
|
||||
def commandList = mapDeviceCommands(command, value)
|
||||
command = commandList[0]
|
||||
value = commandList[1]
|
||||
|
||||
if (command == "setAwayMode") {
|
||||
log.info "Setting away mode to ${value}"
|
||||
if (location.modes?.find { it.name == value }) {
|
||||
location.setMode(value)
|
||||
}
|
||||
} else if (command == "thermostatSetpoint") {
|
||||
switch (device.currentThermostatMode) {
|
||||
case "cool":
|
||||
log.info "Update: ${device.displayName}, [${command}, ${value}]"
|
||||
device.setCoolingSetpoint(value)
|
||||
break
|
||||
case "heat":
|
||||
case "emergency heat":
|
||||
log.info "Update: ${device.displayName}, [${command}, ${value}]"
|
||||
device.setHeatingSetpoint(value)
|
||||
break
|
||||
default:
|
||||
httpError(501, "this mode: ${device.currentThermostatMode} does not allow changing thermostat setpoint.")
|
||||
break
|
||||
}
|
||||
} else if (!device) {
|
||||
log.error "updateDevice, Device not found"
|
||||
httpError(404, "Device not found")
|
||||
} else if (!device.hasCommand(command)) {
|
||||
log.error "updateDevice, Device does not have the command"
|
||||
httpError(404, "Device does not have such command")
|
||||
} else {
|
||||
if (command == "setColor") {
|
||||
log.info "Update: ${device.displayName}, [${command}, ${value}]"
|
||||
device."$command"(hex: value)
|
||||
} else if (value.isNumber()) {
|
||||
def intValue = value as Integer
|
||||
log.info "Update: ${device.displayName}, [${command}, ${intValue}(int)]"
|
||||
device."$command"(intValue)
|
||||
} else if (value) {
|
||||
log.info "Update: ${device.displayName}, [${command}, ${value}]"
|
||||
device."$command"(value)
|
||||
} else {
|
||||
log.info "Update: ${device.displayName}, [${command}]"
|
||||
device."$command"()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*** Private Functions ***/
|
||||
|
||||
//Return current location mode info
|
||||
private getLocationModeInfo() {
|
||||
return [mode: location.mode, supported: location.modes.name]
|
||||
}
|
||||
|
||||
//Map each device to a type given it's capabilities
|
||||
private getDeviceType(device) {
|
||||
def deviceType
|
||||
def caps = device.capabilities
|
||||
log.debug "capabilities: [${device}, ${caps}]"
|
||||
log.debug "supported commands: [${device}, ${device.supportedCommands}]"
|
||||
caps.each {
|
||||
switch (it.name.toLowerCase()) {
|
||||
case "switch":
|
||||
deviceType = "switch"
|
||||
if (caps.any { it.name.toLowerCase() == "power meter" }) {
|
||||
return deviceType
|
||||
}
|
||||
if (caps.any { it.name.toLowerCase() == "switch level" }) {
|
||||
deviceType = "light"
|
||||
return deviceType
|
||||
}
|
||||
break
|
||||
case "contact sensor":
|
||||
deviceType = "contactSensor"
|
||||
return deviceType
|
||||
case "garageDoorControl":
|
||||
deviceType = "garageDoor"
|
||||
return deviceType
|
||||
case "lock":
|
||||
deviceType = "lock"
|
||||
return deviceType
|
||||
case "video camera":
|
||||
deviceType = "camera"
|
||||
return deviceType
|
||||
case "motion sensor":
|
||||
deviceType = "motionSensor"
|
||||
return deviceType
|
||||
case "presence sensor":
|
||||
deviceType = "presenceSensor"
|
||||
return deviceType
|
||||
case "thermostat":
|
||||
deviceType = "thermostat"
|
||||
return deviceType
|
||||
case "water sensor":
|
||||
deviceType = "waterSensor"
|
||||
return deviceType
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
return deviceType
|
||||
}
|
||||
|
||||
//Return a specific device give the device ID.
|
||||
private findDevice(deviceId) {
|
||||
return inputs?.find { it.id == deviceId }
|
||||
}
|
||||
|
||||
//Return a list of device attributes
|
||||
private deviceAttributeList(device) {
|
||||
device.supportedAttributes.collectEntries { attribute ->
|
||||
try {
|
||||
[(attribute.name): device.currentValue(attribute.name)]
|
||||
} catch (e) {
|
||||
[(attribute.name): null]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Map device command and value.
|
||||
//input command and value are from UWP,
|
||||
//returns resultCommand and resultValue that corresponds with function and value in SmartApps
|
||||
private mapDeviceCommands(command, value) {
|
||||
log.debug "mapDeviceCommands: [${command}, ${value}]"
|
||||
def resultCommand = command
|
||||
def resultValue = value
|
||||
switch (command) {
|
||||
case "switch":
|
||||
if (value == 1 || value == "1" || value == "on") {
|
||||
resultCommand = "on"
|
||||
resultValue = ""
|
||||
} else if (value == 0 || value == "0" || value == "off") {
|
||||
resultCommand = "off"
|
||||
resultValue = ""
|
||||
}
|
||||
break
|
||||
// light attributes
|
||||
case "level":
|
||||
resultCommand = "setLevel"
|
||||
resultValue = value
|
||||
break
|
||||
case "hue":
|
||||
resultCommand = "setHue"
|
||||
resultValue = value
|
||||
break
|
||||
case "saturation":
|
||||
resultCommand = "setSaturation"
|
||||
resultValue = value
|
||||
break
|
||||
case "ct":
|
||||
resultCommand = "setColorTemperature"
|
||||
resultValue = value
|
||||
break
|
||||
case "color":
|
||||
resultCommand = "setColor"
|
||||
resultValue = value
|
||||
// thermostat attributes
|
||||
case "hvacMode":
|
||||
resultCommand = "setThermostatMode"
|
||||
resultValue = value
|
||||
break
|
||||
case "fanMode":
|
||||
resultCommand = "setThermostatFanMode"
|
||||
resultValue = value
|
||||
break
|
||||
case "awayMode":
|
||||
resultCommand = "setAwayMode"
|
||||
resultValue = value
|
||||
break
|
||||
case "coolingSetpoint":
|
||||
resultCommand = "setCoolingSetpoint"
|
||||
resultValue = value
|
||||
break
|
||||
case "heatingSetpoint":
|
||||
resultCommand = "setHeatingSetpoint"
|
||||
resultValue = value
|
||||
break
|
||||
case "thermostatSetpoint":
|
||||
resultCommand = "thermostatSetpoint"
|
||||
resultValue = value
|
||||
break
|
||||
// lock attributes
|
||||
case "locked":
|
||||
if (value == 1 || value == "1" || value == "lock") {
|
||||
resultCommand = "lock"
|
||||
resultValue = ""
|
||||
} else if (value == 0 || value == "0" || value == "unlock") {
|
||||
resultCommand = "unlock"
|
||||
resultValue = ""
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return [resultCommand, resultValue]
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ def authPage(){
|
||||
atomicState.accessToken = state.accessToken
|
||||
}
|
||||
|
||||
def redirectUrl = oauthInitUrl()
|
||||
def redirectUrl = oauthInitUrl()
|
||||
def uninstallAllowed = false
|
||||
def oauthTokenProvided = false
|
||||
if(atomicState.authToken){
|
||||
@@ -78,9 +78,9 @@ def authPage(){
|
||||
}
|
||||
}else{
|
||||
return dynamicPage(name: "auth", title: "Step 1 of 2 - Completed", nextPage:"deviceList", uninstall:uninstallAllowed) {
|
||||
section(){
|
||||
section(){
|
||||
paragraph "You are logged in to myplantlink.com, tap next to continue", image: iconUrl
|
||||
href(url:redirectUrl, title:"Or", description:"tap to switch accounts")
|
||||
href(url:redirectUrl, title:"Or", description:"tap to switch accounts")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,44 +137,36 @@ def dock_sensor(device_serial, expected_plant_name) {
|
||||
contentType: "application/json",
|
||||
]
|
||||
log.debug "Creating new plant on myplantlink.com - ${expected_plant_name}"
|
||||
try {
|
||||
httpPost(docking_params) { docking_response ->
|
||||
if (parse_api_response(docking_response, "Docking a link")) {
|
||||
if (docking_response.data.plants.size() == 0) {
|
||||
log.debug "creating plant for - ${expected_plant_name}"
|
||||
plant_post_body_map["name"] = expected_plant_name
|
||||
plant_post_body_map['links_key'] = [docking_response.data.key]
|
||||
def plant_post_body_json_builder = new JsonBuilder(plant_post_body_map)
|
||||
plant_post_params["body"] = plant_post_body_json_builder.toString()
|
||||
try {
|
||||
httpPost(plant_post_params) { plant_post_response ->
|
||||
if(parse_api_response(plant_post_response, 'creating plant')){
|
||||
def attached_map = atomicState.attached_sensors
|
||||
attached_map[device_serial] = plant_post_response.data
|
||||
atomicState.attached_sensors = attached_map
|
||||
}
|
||||
}
|
||||
} catch (Exception f) {
|
||||
log.debug "call failed $f"
|
||||
httpPost(docking_params) { docking_response ->
|
||||
if (parse_api_response(docking_response, "Docking a link")) {
|
||||
if (docking_response.data.plants.size() == 0) {
|
||||
log.debug "creating plant for - ${expected_plant_name}"
|
||||
plant_post_body_map["name"] = expected_plant_name
|
||||
plant_post_body_map['links_key'] = [docking_response.data.key]
|
||||
def plant_post_body_json_builder = new JsonBuilder(plant_post_body_map)
|
||||
plant_post_params["body"] = plant_post_body_json_builder.toString()
|
||||
httpPost(plant_post_params) { plant_post_response ->
|
||||
if(parse_api_response(plant_post_response, 'creating plant')){
|
||||
def attached_map = atomicState.attached_sensors
|
||||
attached_map[device_serial] = plant_post_response.data
|
||||
atomicState.attached_sensors = attached_map
|
||||
}
|
||||
} else {
|
||||
def plant = docking_response.data.plants[0]
|
||||
def attached_map = atomicState.attached_sensors
|
||||
attached_map[device_serial] = plant
|
||||
atomicState.attached_sensors = attached_map
|
||||
checkAndUpdatePlantIfNeeded(plant, expected_plant_name)
|
||||
}
|
||||
} else {
|
||||
def plant = docking_response.data.plants[0]
|
||||
def attached_map = atomicState.attached_sensors
|
||||
attached_map[device_serial] = plant
|
||||
atomicState.attached_sensors = attached_map
|
||||
checkAndUpdatePlantIfNeeded(plant, expected_plant_name)
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug "call failed $e"
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
def checkAndUpdatePlantIfNeeded(plant, expected_plant_name){
|
||||
def plant_put_params = [
|
||||
uri : appSettings.https_plantLinkServer,
|
||||
uri : appSettings.https_plantLinkServer,
|
||||
headers : ["Content-Type": "application/json", "Authorization": "Bearer ${atomicState.authToken}"],
|
||||
contentType : "application/json"
|
||||
]
|
||||
@@ -182,16 +174,12 @@ def checkAndUpdatePlantIfNeeded(plant, expected_plant_name){
|
||||
log.debug "updating plant for - ${expected_plant_name}"
|
||||
plant_put_params["path"] = "/api/v1/plants/${plant.key}"
|
||||
def plant_put_body_map = [
|
||||
name: expected_plant_name
|
||||
name: expected_plant_name
|
||||
]
|
||||
def plant_put_body_json_builder = new JsonBuilder(plant_put_body_map)
|
||||
plant_put_params["body"] = plant_put_body_json_builder.toString()
|
||||
try {
|
||||
httpPut(plant_put_params) { plant_put_response ->
|
||||
parse_api_response(plant_put_response, 'updating plant name')
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug "call failed $e"
|
||||
httpPut(plant_put_params) { plant_put_response ->
|
||||
parse_api_response(plant_put_response, 'updating plant name')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,29 +198,25 @@ def moistureHandler(event){
|
||||
contentType: "application/json",
|
||||
body: event.value
|
||||
]
|
||||
try {
|
||||
httpPost(measurement_post_params) { measurement_post_response ->
|
||||
if (parse_api_response(measurement_post_response, 'creating moisture measurement') &&
|
||||
measurement_post_response.data.size() >0){
|
||||
def measurement = measurement_post_response.data[0]
|
||||
def plant = measurement.plant
|
||||
log.debug plant
|
||||
checkAndUpdatePlantIfNeeded(plant, expected_plant_name)
|
||||
plantlinksensors.each{ sensor_device ->
|
||||
if (sensor_device.id == event.deviceId){
|
||||
sensor_device.setStatusIcon(plant.status)
|
||||
if (plant.last_measurements && plant.last_measurements[0].moisture){
|
||||
sensor_device.setPlantFuelLevel(plant.last_measurements[0].moisture * 100 as int)
|
||||
}
|
||||
if (plant.last_measurements && plant.last_measurements[0].battery){
|
||||
sensor_device.setBatteryLevel(plant.last_measurements[0].battery * 100 as int)
|
||||
}
|
||||
httpPost(measurement_post_params) { measurement_post_response ->
|
||||
if (parse_api_response(measurement_post_response, 'creating moisture measurement') &&
|
||||
measurement_post_response.data.size() >0){
|
||||
def measurement = measurement_post_response.data[0]
|
||||
def plant = measurement.plant
|
||||
log.debug plant
|
||||
checkAndUpdatePlantIfNeeded(plant, expected_plant_name)
|
||||
plantlinksensors.each{ sensor_device ->
|
||||
if (sensor_device.id == event.deviceId){
|
||||
sensor_device.setStatusIcon(plant.status)
|
||||
if (plant.last_measurements && plant.last_measurements[0].moisture){
|
||||
sensor_device.setPlantFuelLevel(plant.last_measurements[0].moisture * 100 as int)
|
||||
}
|
||||
if (plant.last_measurements && plant.last_measurements[0].battery){
|
||||
sensor_device.setBatteryLevel(plant.last_measurements[0].battery * 100 as int)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug "call failed $e"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,12 +235,8 @@ def batteryHandler(event){
|
||||
contentType: "application/json",
|
||||
body: event.value
|
||||
]
|
||||
try {
|
||||
httpPost(measurement_post_params) { measurement_post_response ->
|
||||
parse_api_response(measurement_post_response, 'creating battery measurement')
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug "call failed $e"
|
||||
httpPost(measurement_post_params) { measurement_post_response ->
|
||||
parse_api_response(measurement_post_response, 'creating battery measurement')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,7 +248,7 @@ def getDeviceSerialFromEvent(event){
|
||||
}
|
||||
|
||||
def oauthInitUrl(){
|
||||
atomicState.oauthInitState = UUID.randomUUID().toString()
|
||||
atomicState.oauthInitState = UUID.randomUUID().toString()
|
||||
def oauthParams = [
|
||||
response_type: "code",
|
||||
client_id: appSettings.client_id,
|
||||
@@ -295,12 +275,8 @@ def swapToken(){
|
||||
]
|
||||
|
||||
def jsonMap
|
||||
try {
|
||||
httpPost(postParams) { resp ->
|
||||
jsonMap = resp.data
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug "call failed $e"
|
||||
httpPost(postParams) { resp ->
|
||||
jsonMap = resp.data
|
||||
}
|
||||
|
||||
atomicState.refreshToken = jsonMap.refresh_token
|
||||
@@ -311,33 +287,33 @@ def swapToken(){
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
.container {
|
||||
padding:25px;
|
||||
}
|
||||
.flex1 {
|
||||
width:33%;
|
||||
float:left;
|
||||
text-align: center;
|
||||
}
|
||||
p {
|
||||
font-size: 2em;
|
||||
font-family: Verdana, Geneva, sans-serif;
|
||||
text-align: center;
|
||||
color: #777;
|
||||
}
|
||||
.container {
|
||||
padding:25px;
|
||||
}
|
||||
.flex1 {
|
||||
width:33%;
|
||||
float:left;
|
||||
text-align: center;
|
||||
}
|
||||
p {
|
||||
font-size: 2em;
|
||||
font-family: Verdana, Geneva, sans-serif;
|
||||
text-align: center;
|
||||
color: #777;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="flex1"><img src="https://dashboard.myplantlink.com/images/PLlogo.png" alt="PlantLink" height="75"/></div>
|
||||
<div class="flex1"><img src="https://s3.amazonaws.com/smartapp-icons/Partner/support/connected-device-icn%402x.png" alt="connected to" height="25" style="padding-top:25px;" /></div>
|
||||
<div class="flex1"><img src="https://s3.amazonaws.com/smartapp-icons/Partner/support/st-logo%402x.png" alt="SmartThings" height="75"/></div>
|
||||
<br clear="all">
|
||||
<div class="container">
|
||||
<div class="flex1"><img src="https://dashboard.myplantlink.com/images/PLlogo.png" alt="PlantLink" height="75"/></div>
|
||||
<div class="flex1"><img src="https://s3.amazonaws.com/smartapp-icons/Partner/support/connected-device-icn%402x.png" alt="connected to" height="25" style="padding-top:25px;" /></div>
|
||||
<div class="flex1"><img src="https://s3.amazonaws.com/smartapp-icons/Partner/support/st-logo%402x.png" alt="SmartThings" height="75"/></div>
|
||||
<br clear="all">
|
||||
</div>
|
||||
<div class="container">
|
||||
<p>Your PlantLink Account is now connected to SmartThings!</p>
|
||||
<p style="color:green;">Click <strong>Done</strong> at the top right to finish setup.</p>
|
||||
</div>
|
||||
<p>Your PlantLink Account is now connected to SmartThings!</p>
|
||||
<p style="color:green;">Click <strong>Done</strong> at the top right to finish setup.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
* JLH - 02-15-2014 - Fuller use of ecobee API
|
||||
* 10-28-2015 DVCSMP-604 - accessory sensor, DVCSMP-1174, DVCSMP-1111 - not respond to routines
|
||||
*/
|
||||
|
||||
include 'localization'
|
||||
|
||||
definition(
|
||||
name: "Ecobee (Connect)",
|
||||
namespace: "smartthings",
|
||||
@@ -81,7 +78,7 @@ def authPage() {
|
||||
return dynamicPage(name: "auth", title: "Select Your Thermostats", uninstall: true) {
|
||||
section("") {
|
||||
paragraph "Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings."
|
||||
input(name: "thermostats", title:"Select Your Thermostats", type: "enum", required:true, multiple:true, description: "Tap to choose", metadata:[values:stats])
|
||||
input(name: "thermostats", title:"", type: "enum", required:true, multiple:true, description: "Tap to choose", metadata:[values:stats])
|
||||
}
|
||||
|
||||
def options = sensorsDiscovered() ?: []
|
||||
@@ -89,7 +86,7 @@ def authPage() {
|
||||
if (numFound > 0) {
|
||||
section("") {
|
||||
paragraph "Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings."
|
||||
input(name: "ecobeesensors", title: "Select Ecobee Sensors ({{numFound}} found)", messageArgs: [numFound: numFound], type: "enum", required:false, description: "Tap to choose", multiple:true, options:options)
|
||||
input(name: "ecobeesensors", title:"Select Ecobee Sensors (${numFound} found)", type: "enum", required:false, description: "Tap to choose", multiple:true, options:options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=قم بتوصيل ثرموستات Ecobee بـ SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=أنت متصل.
|
||||
'''Click to enter Ecobee Credentials'''=النقر لإدخال بيانات اعتماد Ecobee
|
||||
'''Login'''=تسجيل الدخول
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=انقر أدناه لتسجيل الدخول إلى خدمة ecobee والمصادقة على الوصول إلى SmartThings. تأكد من التمرير للأسفل على الصفحة ٢ والضغط على زر ”السماح“.
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=تحديد أجهزة الثرموستات
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=انقر أدناه لرؤية قائمة أجهزة ثرموستات ecobee المتوفرة في حساب ecobee، وحدد الأجهزة التي ترغب في توصيلها بـ SmartThings.
|
||||
'''Tap to choose'''=النقر لاختيار <device name>
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=انقر أدناه لرؤية قائمة مستشعرات ecobee المتوفرة في حساب ecobee، وحدد الأجهزة التي ترغب في توصيلها بـ SmartThings.
|
||||
'''Tap to choose'''=النقر لاختيار <device name>
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=تحديد مستشعرات Ecobee ({{numFound}} found)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=حساب ecobee متصل الآن بـ SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=انقر فوق ”تم“ لإنهاء الإعداد.
|
||||
'''The connection could not be established!'''=يتعذر إنشاء الاتصال!
|
||||
'''Click 'Done' to return to the menu.'''=انقر فوق ”تم“ للعودة إلى القائمة.
|
||||
'''is connected to SmartThings'''={{deviceName}} متصل بـ SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=تم قطع اتصال {{deviceName}} بـ SmartThings، لأن بيانات اعتماد الوصول قد تغيرت أو فُقدت. يُرجى الانتقال إلى التطبيق الذكي Ecobee (Connect) وإعادة إدخال بيانات اعتماد تسجيل الدخول إلى حسابك.
|
||||
'''Your Ecobee thermostat '''=ثرموستات Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Свържете термостата Ecobee към SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Свързани сте.
|
||||
'''Click to enter Ecobee Credentials'''=Щракнете, за да въведете идентификационни данни за Ecobee
|
||||
'''Login'''=Вход
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Докоснете по-долу, за да влезете в услугата ecobee и да упълномощите достъпа на SmartThings. Превъртете надолу в страница 2 и натиснете бутона Allow (Позволяване).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Избор на термостати
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Докоснете по-долу, за да видите списък с термостатите ecobee във вашия ecobee акаунт, и изберете онези, които искате да свържете към SmartThings.
|
||||
'''Tap to choose'''=Докосване за избор
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Докоснете по-долу, за да видите списък със сензорите ecobee във вашия ecobee акаунт, и изберете онези, които искате да свържете към SmartThings.
|
||||
'''Tap to choose'''=Докосване за избор
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Избор на сензори Ecobee ({{numFound}} с намерени)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Вашият ecobee акаунт вече е свързан към SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Щракнете върху Done (Готово), за да завършите настройката.
|
||||
'''The connection could not be established!'''=Връзката не може да се осъществи!
|
||||
'''Click 'Done' to return to the menu.'''=Щракнете върху Done (Готово), за да се върнете към менюто.
|
||||
'''is connected to SmartThings'''=е свързан към SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=е прекъснат от SmartThings, тъй като идентификационните данни за достъп са променени или изгубени. Отидете в Ecobee (Connect) SmartApp и въведете отново идентификационните си данни за влизане в акаунта.
|
||||
'''Your Ecobee thermostat '''=Вашият термостат Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Připojte termostat Ecobee k systému SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Jste připojeni.
|
||||
'''Click to enter Ecobee Credentials'''=Klepněte a zadejte přihlašovací údaje Ecobee
|
||||
'''Login'''=Přihlásit
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Klepnutím na následující tlačítko se přihlásíte ke službě ecobee a autorizujete přístup pro systém SmartThings. Posuňte se dolů na stránku 2 a stiskněte tlačítko „Allow“ (Povolit).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Vyberte termostaty
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Klepnutím na následující tlačítko zobrazte seznam termostatů ecobee dostupných na vašem účtu ecobee a vyberte ty, které chcete připojit k systému SmartThings.
|
||||
'''Tap to choose'''=Klepnutím zvolte
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Klepnutím na následující tlačítko zobrazte seznam senzorů ecobee dostupných na vašem účtu ecobee a vyberte ty, které chcete připojit k systému SmartThings.
|
||||
'''Tap to choose'''=Klepnutím zvolte
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Vyberte senzory Ecobee (nalezeno {{numFound}})
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Účet ecobee je nyní připojen k systému SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Dokončete nastavení klepnutím na tlačítko „Done“ (Hotovo).
|
||||
'''The connection could not be established!'''=Připojení nelze navázat!
|
||||
'''Click 'Done' to return to the menu.'''=Klepnutím na tlačítko „Done“ (Hotovo) se vrátíte do menu.
|
||||
'''is connected to SmartThings'''=je připojen ke SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=byl odpojen od systému SmartThings, protože přístupové přihlašovací údaje byly změněny nebo ztraceny. Přejděte do Ecobee (Connect) SmartApp a znovu zadejte své přihlašovací údaje k účtu.
|
||||
'''Your Ecobee thermostat '''=Termostat Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Forbind din Ecobee-termostat med SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Du er nu forbundet.
|
||||
'''Click to enter Ecobee Credentials'''=Klik for at indtaste Ecobee-legitimationsoplysninger
|
||||
'''Login'''=Log ind
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Tryk nedenfor for at logge ind på din ecobee-tjeneste og godkende SmartThings-adgang. Sørg for at rulle ned på side 2 og trykke på knappen “Allow” (Tillad).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Vælg dine termostater
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tryk herunder for at se listen over ecobee-termostater, der er tilgængelige på din ecobee-konto, og vælg dem, du vil forbinde med SmartThings.
|
||||
'''Tap to choose'''=Tryk for at vælge
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tryk herunder for at se listen over ecobee-sensorer, der er tilgængelige på din ecobee-konto, og vælg dem, du vil forbinde med SmartThings.
|
||||
'''Tap to choose'''=Tryk for at vælge
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Vælg Ecobee-sensorer ({{numFound}} fundet)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Din ecobee-konto er nu forbundet med SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Klik på “Done” (Udført) for at afslutte konfigurationen.
|
||||
'''The connection could not be established!'''=Der kunne ikke oprettes forbindelse!
|
||||
'''Click 'Done' to return to the menu.'''=Klik på “Done” (Udført) for at vende tilbage til menuen.
|
||||
'''is connected to SmartThings'''=er forbundet med SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=er koblet fra SmartThings, fordi adgangslegitimationsoplysningerne er ændret eller gået tabt. Gå til Ecobee (Connect (Forbind)) SmartApp, og indtast dine kontologinoplysninger igen.
|
||||
'''Your Ecobee thermostat '''=Din Ecobee-termostat
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Verbinden Sie Ihr Ecobee-Thermostat mit SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Sie sind verbunden.
|
||||
'''Click to enter Ecobee Credentials'''=Hier klicken, um die ecobee-Zugangsdaten einzugeben.
|
||||
'''Login'''=Anmeldung
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Tippen Sie unten, um sich am ecobee-Dienst anzumelden und den SmartThings-Zugriff zu autorisieren. Stellen Sie sicher, dass Sie bis auf Seite 2 herunterscrollen und auf die Schaltfläche „Allow“ (Zulassen) tippen.
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Ihre Thermostate auswählen
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tippen Sie unten, um eine Liste der ecobee-Thermostate anzuzeigen, die in Ihrem ecobee-Konto verfügbar sind, und wählen Sie diejenigen aus, mit denen Sie eine Verbindung zu SmartThings herstellen möchten.
|
||||
'''Tap to choose'''=Zur Auswahl tippen
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tippen Sie unten, um eine Liste der ecobee-Sensoren anzuzeigen, die in Ihrem ecobee-Konto verfügbar sind, und wählen Sie diejenigen aus, mit denen Sie eine Verbindung zu SmartThings herstellen möchten.
|
||||
'''Tap to choose'''=Zur Auswahl tippen
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=ecobee-Sensoren auswählen ({{numFound}} gefunden)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Ihr ecobee-Konto ist jetzt mit SmartThings verbunden!
|
||||
'''Click 'Done' to finish setup.'''=Klicken Sie auf „Done“ (OK), um die Einrichtung abzuschließen.
|
||||
'''The connection could not be established!'''=Es konnte keine Verbindung hergestellt werden!
|
||||
'''Click 'Done' to return to the menu.'''=Klicken Sie auf „Done“ (OK), um zum Menü zurückzukehren.
|
||||
'''is connected to SmartThings'''=ist mit SmartThings verbunden
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=ist von SmartThings getrennt, da die Zugangsdaten für den Zugriff geändert wurden oder verloren gingen. Wechseln Sie zur ecobee (Connect)-SmartApp und geben Sie Ihre Kontozugangsdaten erneut ein.
|
||||
'''Your Ecobee thermostat '''=Ihr ecobee-Thermostat
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Συνδέστε το θερμοστάτη Ecobee στο SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Έχετε συνδεθεί.
|
||||
'''Click to enter Ecobee Credentials'''=Κάντε κλικ για να καταχωρήσετε διαπιστευτήρια Ecobee
|
||||
'''Login'''=Σύνδεση
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Πατήστε παρακάτω για να συνδεθείτε στην υπηρεσία ecobee και να δώσετε εξουσιοδότηση πρόσβασης για το SmartThings. Κάνετε κύλιση προς τα κάτω στη σελίδα 2 και πατήστε το κουμπί "Επιτρ.".
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Επιλέξτε τους θερμοστάτες σας
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Πατήστε παρακάτω για να δείτε τη λίστα με τους θερμοστάτες ecobee που είναι διαθέσιμοι στο λογαριασμό ecobee και να επιλέξετε αυτούς που θέλετε να συνδέσετε στο SmartThings.
|
||||
'''Tap to choose'''=Πατήστε για να επιλέξετε
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Πατήστε παρακάτω για να δείτε τη λίστα με τους αισθητήρες ecobee που είναι διαθέσιμοι στο λογαριασμό ecobee και να επιλέξετε αυτούς που θέλετε να συνδέσετε στο SmartThings.
|
||||
'''Tap to choose'''=Πατήστε για να επιλέξετε
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Επιλογή αισθητήρων Ecobee (βρέθηκαν {{numFound}})
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Ο λογαριασμός σας στο ecobee έχει τώρα συνδεθεί στο SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Πατήστε "Done" (Τέλος) για να ολοκληρωθεί η ρύθμιση.
|
||||
'''The connection could not be established!'''=Δεν ήταν δυνατή η δημιουργία σύνδεσης!
|
||||
'''Click 'Done' to return to the menu.'''=Κάντε κλικ στο "Done" (Τέλος) για να επιστρέψετε στο μενού.
|
||||
'''is connected to SmartThings'''=συνδέθηκε στο SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=αποσυνδέθηκε από το SmartThings, επειδή τα διαπιστευτήρια πρόσβασης άλλαξαν ή έχουν χαθεί. Μεταβείτε στην εφαρμογή Ecobee (Connect) SmartApp και καταχωρήστε ξανά τα διαπιστευτήρια σύνδεσης για το λογαριασμό σας.
|
||||
'''Your Ecobee thermostat '''=Θερμοστάτης Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Connect your Ecobee thermostat to SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=You are connected.
|
||||
'''Click to enter Ecobee Credentials'''=Click to enter Ecobee Credentials
|
||||
'''Login'''=Login
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Tap below to log in to the ecobee service and authorise SmartThings access. Be sure to scroll down on page 2 and press the ’Allow’ button.
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Select Your Thermostats
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.
|
||||
'''Tap to choose'''=Tap to choose
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.
|
||||
'''Tap to choose'''=Tap to choose
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Select Ecobee Sensors ({{numFound}} found)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Your ecobee Account is now connected to SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Click ’Done’ to finish setup.
|
||||
'''The connection could not be established!'''=The connection could not be established!
|
||||
'''Click 'Done' to return to the menu.'''=Click ’Done’ to return to the menu.
|
||||
'''is connected to SmartThings'''=is connected to SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.
|
||||
'''Your Ecobee thermostat '''=Your Ecobee thermostat
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Conecte su termostato Ecobee a SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Está conectado.
|
||||
'''Click to enter Ecobee Credentials'''=Haga clic para introducir las credenciales de Ecobee
|
||||
'''Login'''=Inicio de sesión
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Pulse a continuación para iniciar sesión en el servicio de ecobee y autorizar el acceso a SmartThings. Asegúrese de desplazarse hacia abajo a la página 2 y pulsar el botón “Allow” (Permitir).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Seleccionar los termostatos
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de termostatos ecobee disponibles en su cuenta de ecobee y seleccione los que quiera conectar a SmartThings.
|
||||
'''Tap to choose'''=Pulsar para seleccionar
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de sensores ecobee disponibles en su cuenta de ecobee y seleccione los que quiera conectar a SmartThings.
|
||||
'''Tap to choose'''=Pulsar para seleccionar
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Seleccionar sensores de Ecobee ({{numFound}} encontrados)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=¡Su cuenta de ecobee ya está conectada a SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Haga clic en “Done” (Hecho) para finalizar la configuración.
|
||||
'''The connection could not be established!'''=¡No se ha podido establecer la conexión!
|
||||
'''Click 'Done' to return to the menu.'''=Haga clic en “Done” (Hecho) para volver al menú.
|
||||
'''is connected to SmartThings'''=está conectado a SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=está desconectado de SmartThings porque se han cambiado o perdido las credenciales de acceso. Vaya a la aplicación inteligente de Ecobee (Conectar) y vuelva a introducir las credenciales de inicio de sesión de su cuenta.
|
||||
'''Your Ecobee thermostat '''=Su termostato Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Conecte el termostato Ecobee a SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Está conectado.
|
||||
'''Click to enter Ecobee Credentials'''=Haga clic para introducir las credenciales de Ecobee
|
||||
'''Login'''=Inicio de sesión
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Pulse a continuación para iniciar sesión en el servicio de ecobee y otorgar acceso a SmartThings. Asegúrese de desplazarse hacia abajo en la página 2 y de presionar el botón 'Allow' ('Permitir').
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Seleccionar Your Thermostats (Sus termostatos)
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de termostatos ecobee disponibles en su cuenta de ecobee y seleccione los que desea conectar a SmartThings.
|
||||
'''Tap to choose'''=Pulsar para elegir
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pulse a continuación para ver la lista de sensores ecobee disponibles en su cuenta de ecobee y seleccione los que desea conectar a SmartThings.
|
||||
'''Tap to choose'''=Pulsar para elegir
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Seleccionar sensores Ecobee (hay {{numFound}})
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=¡Su cuenta de ecobee ahora está conectada a SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Haga clic en 'Done' ('Listo') para finalizar la configuración.
|
||||
'''The connection could not be established!'''=¡No fue posible establecer la conexión!
|
||||
'''Click 'Done' to return to the menu.'''=Haga clic en 'Done' ('Listo') para volver al menú.
|
||||
'''is connected to SmartThings'''=está conectado a SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=no está conectado a SmartThings debido a que la credencial de acceso se cambió o se perdió. Vaya a la SmartApp de Ecobee (Connect) y vuelva a introducir las credenciales de inicio de sesión de su cuenta.
|
||||
'''Your Ecobee thermostat '''=Su termostato Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Ühendage oma termostaat Ecobee teenusega SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Ühendus on loodud.
|
||||
'''Click to enter Ecobee Credentials'''=Klõpsake, et sisestada teenuse Ecobee volitused
|
||||
'''Login'''=Sisselogimine
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Toksake all, et logida sisse teenusesse ecobee ja autoriseerida teenuse SmartThings juurdepääs. Kerige kindlasti alla lehele 2 ja vajutage nuppu Luba.
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Valige oma termostaadid
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toksake all, et näha oma ecobee kontole registreeritud ecobee termostaate ja valige need, mida soovite ühendada teenusega SmartThings.
|
||||
'''Tap to choose'''=Toksake, et valida
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toksake all, et näha oma ecobee kontole registreeritud ecobee andureid ja valige need, mida soovite ühendada teenusega SmartThings.
|
||||
'''Tap to choose'''=Toksake, et valida
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Valige Ecobee andurid (leiti {{numFound}})
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Teie ecobee konto on nüüd ühendatud teenusega SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Klõpsake valikut Valmis, et seadistamine lõpule viia.
|
||||
'''The connection could not be established!'''=Ühenduse loomine nurjus!
|
||||
'''Click 'Done' to return to the menu.'''=Klõpsake valikut Valmis, et naasta menüüsse.
|
||||
'''is connected to SmartThings'''=on ühendatud teenusega SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=on teenusest SmartThings lahti ühendatud, kuna juurdepääsu volitus muutus või kadus. Avage rakendus Ecobee (Connect) SmartApp ja sisestage uuesti oma konto sisselogimisandmed.
|
||||
'''Your Ecobee thermostat '''=Teie Ecobee termostaat
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Yhdistä Ecobee-termostaattisi SmartThingsiin.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Yhteys muodostettu.
|
||||
'''Click to enter Ecobee Credentials'''=Napsauta ja anna Ecobee-tunnistetiedot
|
||||
'''Login'''=Kirjautuminen
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Kirjaudu ecobee-palveluun ja myönnä SmartThingsille käyttöoikeudet napauttamalla alla. Vieritä alas sivulle 2 ja paina Allow (Salli) -painiketta.
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Valitse termostaatit
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Napauttamalla alla voit tuoda ecobee-tililläsi käytettävissä olevien ecobee-termostaattien luettelon näyttöön ja valita SmartThingsiin yhdistettävät laitteet.
|
||||
'''Tap to choose'''=Valitse napauttamalla
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Napauttamalla alla voit tuoda ecobee-tililläsi käytettävissä olevien ecobee-tunnistimien luettelon näyttöön ja valita SmartThingsiin yhdistettävät laitteet.
|
||||
'''Tap to choose'''=Valitse napauttamalla
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Valitse Ecobee-tunnistimet ({{numFound}} löydetty)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=ecobee-tilisi on nyt yhdistetty SmartThingsiin!
|
||||
'''Click 'Done' to finish setup.'''=Viimeistele asennus napsauttamalla Done (Valmis).
|
||||
'''The connection could not be established!'''=Yhteyden muodostaminen epäonnistui!
|
||||
'''Click 'Done' to return to the menu.'''=Palaa valikkoon napsauttamalla Done (Valmis).
|
||||
'''is connected to SmartThings'''=on yhdistetty SmartThingsiin
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=ei enää ole yhteydessä SmartThingsiin, sillä käyttötunnukset ovat muuttuneet tai kadonneet. Siirry Ecobee (Connect) SmartAppiin ja anna tilisi kirjautumistiedot uudelleen.
|
||||
'''Your Ecobee thermostat '''=Ecobee-termostaattisi
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Connectez votre thermostat Ecobee à SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Vous êtes connecté.
|
||||
'''Click to enter Ecobee Credentials'''=Cliquez pour saisir les informations d'identification Ecobee
|
||||
'''Login'''=Connexion
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Appuyez ci-dessous pour vous connecter au service ecobee et autoriser l'accès pour SmartThings. Faites défiler l'écran jusqu'en bas de la page 2 et appuyez sur le bouton Allow (Autoriser).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Sélection de vos thermostats
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Appuyez ci-dessous pour afficher la liste des thermostats ecobee disponibles dans votre compte ecobee et sélectionner ceux que vous souhaitez connecter à SmartThings.
|
||||
'''Tap to choose'''=Appuyez pour sélectionner
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Appuyez ci-dessous pour afficher la liste des capteurs ecobee disponibles dans votre compte ecobee et sélectionner ceux que vous souhaitez connecter à SmartThings.
|
||||
'''Tap to choose'''=Appuyez pour sélectionner
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Sélection des capteurs Ecobee ({{numFound}} trouvé(s))
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Votre compte ecobee est maintenant connecté à SmartThings !
|
||||
'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration.
|
||||
'''The connection could not be established!'''=La connexion n'a pas pu être établie !
|
||||
'''Click 'Done' to return to the menu.'''=Cliquez sur Done (Terminé) pour revenir au menu.
|
||||
'''is connected to SmartThings'''=est connecté à SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=est déconnecté de SmartThings, car les identifiants d'accès ont été modifiés ou perdus. Accédez à la SmartApp Ecobee (Connect) et saisissez à nouveau les informations de connexion à votre compte.
|
||||
'''Your Ecobee thermostat '''=Votre thermostat Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Connectez votre thermostat Ecobee à SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Vous êtes connecté.
|
||||
'''Click to enter Ecobee Credentials'''=Cliquez pour saisir les informations d'identification Ecobee
|
||||
'''Login'''=Connexion
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Appuyez ci-dessous pour vous connecter au service ecobee et autoriser l'accès pour SmartThings. Faites défiler l'écran jusqu'en bas de la page 2 et appuyez sur le bouton Allow (Autoriser).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Sélection de vos thermostats
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Appuyez ci-dessous pour afficher la liste des thermostats ecobee disponibles dans votre compte ecobee et sélectionner ceux que vous souhaitez connecter à SmartThings.
|
||||
'''Tap to choose'''=Appuyez pour sélectionner
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Appuyez ci-dessous pour afficher la liste des capteurs ecobee disponibles dans votre compte ecobee et sélectionner ceux que vous souhaitez connecter à SmartThings.
|
||||
'''Tap to choose'''=Appuyez pour sélectionner
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Sélection des capteurs Ecobee ({{numFound}} trouvé(s))
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Votre compte ecobee est maintenant connecté à SmartThings !
|
||||
'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration.
|
||||
'''The connection could not be established!'''=La connexion n'a pas pu être établie !
|
||||
'''Click 'Done' to return to the menu.'''=Cliquez sur Done (Terminé) pour revenir au menu.
|
||||
'''is connected to SmartThings'''=est connecté à SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=est déconnecté de SmartThings, car les identifiants d'accès ont été modifiés ou perdus. Accédez à la SmartApp Ecobee (Connect) et saisissez à nouveau les informations de connexion à votre compte.
|
||||
'''Your Ecobee thermostat '''=Votre thermostat Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Povežite termostat Ecobee s uslugom SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Povezani ste.
|
||||
'''Click to enter Ecobee Credentials'''=Kliknite za unos podataka za prijavu za Ecobee
|
||||
'''Login'''=Prijava
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Dodirnite u nastavku da biste se prijavili u uslugu ecobee i odobrili pristup za SmartThings. Na 2. se stranici pomaknite prema dolje i pritisnite gumb „Allow” (Dopusti).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Odaberite termostate
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Dodirnite u nastavku da biste vidjeli popis termostata ecobee dostupnih na vašem računu za ecobee i odaberite one koje želite povezati s uslugom SmartThings.
|
||||
'''Tap to choose'''=Dodirnite za odabir
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Dodirnite u nastavku da biste vidjeli popis senzora ecobee dostupnih na vašem računu za ecobee i odaberite one koje želite povezati s uslugom SmartThings.
|
||||
'''Tap to choose'''=Dodirnite za odabir
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Odaberite senzore Ecobee (pronađeno: {{numFound}})
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Račun za ecobee sada je povezan s uslugom SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Kliknite „Done” (Gotovo) da biste dovršili postavljanje.
|
||||
'''The connection could not be established!'''=Veza se nije uspostavila!
|
||||
'''Click 'Done' to return to the menu.'''=Kliknite „Done” (Gotovo) za vraćanje na izbornik.
|
||||
'''is connected to SmartThings'''=povezan je s uslugom SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=nije povezan s uslugom SmartThings jer su se pristupni podaci promijenili ili izgubili. Idite na Ecobee (Connect) SmartApp i ponovno unesite podatke za prijavu na račun.
|
||||
'''Your Ecobee thermostat '''=Termostat Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Ecobee termosztátot csatlakoztathat a SmartThings rendszerhez.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Kapcsolódott.
|
||||
'''Click to enter Ecobee Credentials'''=Kattintson az Ecobee-hitelesítőadatok megadásához
|
||||
'''Login'''=Bejelentkezés
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Az alábbi hivatkozás megérintésével bejelentkezhet az ecobee szolgáltatásba, és engedélyezheti a SmartThings-hozzáférést. Görgessen le a 2. oldalon, és nyomja meg az „Allow” (Engedélyezés) gombot.
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=A termosztátok kiválasztása
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Az alábbi hivatkozás megérintésével megjelenítheti az ecobee-fiókjában rendelkezésre álló ecobee termosztátok listáját, és kiválaszthatja azokat, amelyeket csatlakoztatni szeretne a SmartThings rendszerhez.
|
||||
'''Tap to choose'''=Érintse meg a kiválasztáshoz
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Az alábbi hivatkozás megérintésével megjelenítheti az ecobee-fiókjában rendelkezésre álló ecobee érzékelők listáját, és kiválaszthatja azokat, amelyeket csatlakoztatni szeretne a SmartThings rendszerhez.
|
||||
'''Tap to choose'''=Érintse meg a kiválasztáshoz
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Ecobee érzékelők kiválasztása ({{numFound}} találat)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Csatlakoztatta ecobee-fiókját a SmartThings rendszerhez!
|
||||
'''Click 'Done' to finish setup.'''=A telepítés befejezéséhez kattintson a „Done” (Kész) gombra.
|
||||
'''The connection could not be established!'''=Nem sikerült kapcsolatot létesíteni!
|
||||
'''Click 'Done' to return to the menu.'''=A menühöz való visszatéréshez kattintson a „Done” (Kész) gombra.
|
||||
'''is connected to SmartThings'''=kapcsolódott a SmartThings rendszerhez
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=le lett választva a SmartThings rendszerről, mert megváltoztak vagy elvesztek a hozzáférési hitelesítő adatok. Adja meg újra a fiókja bejelentkezési hitelesítő adatait a Ecobee (Connect) SmartApp segítségével.
|
||||
'''Your Ecobee thermostat '''=Az Ön Ecobee termosztátja
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Connettete il termostato Ecobee a SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Connessione effettuata.
|
||||
'''Click to enter Ecobee Credentials'''=Fate clic per inserire le credenziali Ecobee
|
||||
'''Login'''=Accesso
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Toccate di seguito per accedere al servizio ecobee e autorizzare l'accesso a SmartThings. Scorrete fino in fondo alla pagina 2 e premete il pulsante “Allow” (Consenti).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Selezionate i termostati
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toccate di seguito per visualizzare l'elenco dei termostati ecobee disponibili nell'account ecobee e selezionate quelli che volete connettere a SmartThings.
|
||||
'''Tap to choose'''=Toccate per scegliere
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toccate di seguito per visualizzare l'elenco dei sensori ecobee disponibili nell'account ecobee e selezionate quelli che volete connettere a SmartThings.
|
||||
'''Tap to choose'''=Toccate per scegliere
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Selezionate i sensori Ecobee ({{numFound}} trovati)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=L'account ecobee è ora connesso a SmartThings.
|
||||
'''Click 'Done' to finish setup.'''=Fate clic su “Done” (Fatto) per terminare la configurazione.
|
||||
'''The connection could not be established!'''=Non è stato possibile stabilire la connessione.
|
||||
'''Click 'Done' to return to the menu.'''=Fate clic su “Done” (Fatto) per tornare al menu.
|
||||
'''is connected to SmartThings'''=connesso a SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=disconnesso da SmartThings. Le credenziali di accesso sono state modificate o sono andate perse. Andate alla SmartApp di Ecobee (Connect) e inserite nuovamente le credenziali di accesso all'account.
|
||||
'''Your Ecobee thermostat '''=Il termostato Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Ecobee 온도조절기를 SmartThings에 연결하세요.
|
||||
'''ecobee'''=Ecobee
|
||||
'''You are connected.'''=연결되었습니다.
|
||||
'''Click to enter Ecobee Credentials'''=Ecobee 로그인 정보를 입력하려면 클릭하세요
|
||||
'''Login'''=로그인
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Ecobee 서비스에 로그인하여 SmartThings를 사용할 수 있도록 인증하려면 아래를 누르세요. 2페이지에서 아래로 스크롤한 후 [허용]을 누르세요.
|
||||
'''ecobee'''=Ecobee
|
||||
'''Select Your Thermostats'''=온도조절기 선택
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ecobee 계정에 등록된 Ecobee 온도조절기 목록을 확인하고 SmartThings에 연결할 기기를 선택하려면 아래를 누르세요.
|
||||
'''Tap to choose'''=눌러서 선택
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ecobee 계정에 등록된 Ecobee 센서 목록을 확인하고 SmartThings에 연결할 기기를 선택하려면 아래를 누르세요.
|
||||
'''Tap to choose'''=눌러서 선택
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Ecobee 센서 선택 ({{numFound}}개 찾음)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Ecobee 계정이 SmartThings에 연결되었습니다!
|
||||
'''Click 'Done' to finish setup.'''=설정을 완료하려면 [완료]를 클릭하세요.
|
||||
'''The connection could not be established!'''=연결을 실행할 수 없습니다!
|
||||
'''Click 'Done' to return to the menu.'''=메뉴로 돌아가려면 [완료]를 클릭하세요.
|
||||
'''is connected to SmartThings'''=이(가) SmartThings에 연결되었습니다
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=이(가) SmartThings에서 연결 해제되었습니다. 로그인 정보가 변경되었거나 유실되었습니다. Ecobee (연결) 스마트앱에서 계정의 로그인 정보를 다시 입력하세요.
|
||||
'''Your Ecobee thermostat '''=Ecobee 온도조절기
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Verbind uw Ecobee-thermostaat met SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=U bent verbonden.
|
||||
'''Click to enter Ecobee Credentials'''=Klik om Ecobee-inloggegevens in te voeren
|
||||
'''Login'''=Inloggen
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Tik hieronder om in te loggen bij uw ecobee-service en toegang door SmartThings toe te staan. Scrol naar beneden op pagina 2 en druk op de knop Allow (Toestaan).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Selecteer uw thermostaten
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tik hieronder om de lijst met ecobee-thermostaten in uw ecobee-account weer te geven en de apparaten te selecteren die u wilt verbinden met SmartThings.
|
||||
'''Tap to choose'''=Tik om te kiezen
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tik hieronder om de lijst met ecobee-sensoren in uw ecobee-account weer te geven en de apparaten te selecteren die u wilt verbinden met SmartThings.
|
||||
'''Tap to choose'''=Tik om te kiezen
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Selecteer Ecobee-sensoren ({{numFound}} gevonden)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Uw ecobee-account is nu verbonden met SmartThings.
|
||||
'''Click 'Done' to finish setup.'''=Klik op Done (Gereed) om het instellen te voltooien.
|
||||
'''The connection could not be established!'''=Er kan geen verbinding worden gemaakt.
|
||||
'''Click 'Done' to return to the menu.'''=Klik op Done (Gereed) om terug te gaan naar het menu.
|
||||
'''is connected to SmartThings'''=is verbonden met SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=-verbinding met SmartThings is verbroken, omdat de inloggegevens zijn gewijzigd of verloren zijn gegaan. Ga naar de Ecobee (Connect) SmartApp en voer de inloggegevens voor uw account opnieuw in.
|
||||
'''Your Ecobee thermostat '''=Uw Ecobee-thermostaat
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Koble Ecobee-termostaten til SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Du er tilkoblet.
|
||||
'''Click to enter Ecobee Credentials'''=Klikk for å angi Ecobee-informasjon
|
||||
'''Login'''=Logg på
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Trykk nedenfor for å logge på ecobee-tjenesten og godkjenne SmartThings-tilgang. Pass på å bla ned på side 2 og trykke på Allow (Tillat)-knappen.
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Velg termostatene dine
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Trykk nedenfor for å se listen over ecobee-termostatene som er tilgjengelige i ecobee-kontoen din, og velg de du vil koble til SmartThings.
|
||||
'''Tap to choose'''=Trykk for å velge
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Trykk nedenfor for å se listen over ecobee-sensorene som er tilgjengelige i ecobee-kontoen din, og velg de du vil koble til SmartThings.
|
||||
'''Tap to choose'''=Trykk for å velge
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Velg Ecobee-sensorer (fant {{numFound}})
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=ecobee-kontoen din er nå koblet til SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Klikk på Done (Ferdig) for å fullføre oppsettet.
|
||||
'''The connection could not be established!'''=Kunne ikke opprette tilkoblingen!
|
||||
'''Click 'Done' to return to the menu.'''=Klikk på Done (Ferdig) for å gå tilbake til menyen.
|
||||
'''is connected to SmartThings'''=er koblet til SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=er koblet fra SmartThings fordi tilgangsinformasjonen ble endret eller mistet. Gå til Ecobee (Connect) SmartApp, og angi påloggingsinformasjonen for kontoen på nytt.
|
||||
'''Your Ecobee thermostat '''=Ecobee-termostaten
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Połącz termostat Ecobee ze SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Połączono.
|
||||
'''Click to enter Ecobee Credentials'''=Kliknij, aby wprowadzić poświadczenia Ecobee
|
||||
'''Login'''=Logowanie
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Dotknij poniżej, aby zalogować się do usługi ecobee i autoryzować dostęp SmartThings. Przewiń w dół na stronie 2 i naciśnij przycisk „Allow” (Zezwól).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Wybierz termostaty
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Dotknij poniżej, aby wyświetlić listę termostatów ecobee dostępnych na koncie ecobee, i wybierz te, które chcesz połączyć ze SmartThings.
|
||||
'''Tap to choose'''=Dotknij, aby wybrać
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Dotknij poniżej, aby wyświetlić listę czujników ecobee dostępnych na koncie ecobee, i wybierz te, które chcesz połączyć ze SmartThings.
|
||||
'''Tap to choose'''=Dotknij, aby wybrać
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Wybierz czujniki Ecobee (znaleziono {{numFound}})
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Konto ecobee jest teraz połączone ze SmartThings.
|
||||
'''Click 'Done' to finish setup.'''=Kliknij opcję „Done” (Gotowe), aby ukończyć instalację.
|
||||
'''The connection could not be established!'''=Nie można ustanowić połączenia.
|
||||
'''Click 'Done' to return to the menu.'''=Kliknij opcję „Done” (Gotowe), aby powrócić do menu.
|
||||
'''is connected to SmartThings'''=jest połączony ze SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=jest odłączony od SmartThings, ponieważ poświadczenie dostępu zostało zmienione lub utracone. Przejdź do aplikacji Ecobee (Connect) SmartApp i wprowadź ponownie poświadczenia logowania konta.
|
||||
'''Your Ecobee thermostat '''=Termostat Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Conecte seu termostato Ecobee ao SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Você está conectado.
|
||||
'''Click to enter Ecobee Credentials'''=Clique para inserir as credenciais do Ecobee
|
||||
'''Login'''=Conectar
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Toque abaixo para entrar no serviço ecobee e autorizar o acesso ao SmartThings. Certifique-se de rolar para baixo na página 2 e pressionar o botão 'Allow' (Permitir).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Selecionar seus termostatos
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toque abaixo para ver a lista de termostatos ecobee disponíveis na sua conta ecobee e selecione os que deseja conectar ao SmartThings.
|
||||
'''Tap to choose'''=Tocar para escolher
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toque abaixo para ver a lista de sensores ecobee disponíveis na sua conta ecobee e selecione os que deseja conectar ao SmartThings.
|
||||
'''Tap to choose'''=Tocar para escolher
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Selecionar sensores Ecobee ({{numFound}} encontrado(s))
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Agora sua conta ecobee está conectada ao SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Clique em 'Done' (Concluído) para concluir a configuração.
|
||||
'''The connection could not be established!'''=Não foi possível estabelecer a conexão!
|
||||
'''Click 'Done' to return to the menu.'''=Clique em 'Done' (Concluído) para retornar ao menu.
|
||||
'''is connected to SmartThings'''=está conectado ao SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=foi desconectado do SmartThings, pois a credencial de acesso foi alterada ou perdida. Vá para Ecobee (Connect) SmartApp e insira novamente suas credenciais de acesso à conta.
|
||||
'''Your Ecobee thermostat '''=Seu termostato Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Ligue o seu termóstato Ecobee ao SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Está ligado.
|
||||
'''Click to enter Ecobee Credentials'''=Clique para introduzir as Credenciais da Ecobee
|
||||
'''Login'''=Iniciar Sessão
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Toque abaixo para iniciar sessão no serviço ecobee e autorizar o acesso ao SmartThings. Certifique-se de que se desloca para baixo na página 2 e prime o botão "Allow" (Permitir).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Seleccionar os seus Termóstatos
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toque abaixo para ver a lista de termóstatos da ecobee disponíveis na sua conta ecobee e seleccione aqueles que pretende ligar ao SmartThings.
|
||||
'''Tap to choose'''=Toque para escolher
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Toque abaixo para ver a lista de sensores da ecobee disponíveis na sua conta ecobee e seleccione aqueles que pretende ligar ao SmartThings.
|
||||
'''Tap to choose'''=Toque para escolher
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Seleccionar sensores da Ecobee ({{numFound}} encontrado)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Agora, a sua Conta ecobee está ligada ao SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Clique em "Done" (Concluir) para terminar a configuração.
|
||||
'''The connection could not be established!'''=Não foi possível estabelecer a ligação!
|
||||
'''Click 'Done' to return to the menu.'''=Clique em "Done" (Concluir) para regressar ao menu.
|
||||
'''is connected to SmartThings'''=está ligado ao SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=foi desligado do SmartThings, porque a credencial de acesso foi alterada ou perdida. Vá para Ecobee (Connect) SmartApp e introduza novamente as suas credenciais de início de sessão na conta.
|
||||
'''Your Ecobee thermostat '''=O seu termóstato Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Conectați termostatul Ecobee la SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Sunteți conectat.
|
||||
'''Click to enter Ecobee Credentials'''=Faceți clic pentru a introduce acreditările Ecobee
|
||||
'''Login'''=Conectare
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Atingeți mai jos pentru a vă conecta la serviciul ecobee și a autoriza accesul la SmartThings. Asigurați-vă că ați derulat în jos până la pagina 2 și apăsați butonul „Allow” (Permitere).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Selectați termostatele
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Atingeți mai jos pentru a vizualiza o listă de termostate ecobee disponibile în contul dvs. ecobee și selectați-le pe cele pe care doriți să le conectați la SmartThings.
|
||||
'''Tap to choose'''=Atingeți pentru a selecta
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Atingeți mai jos pentru a vizualiza o listă de senzori ecobee disponibili în contul dvs. ecobee și selectați-i pe cei pe care doriți să îi conectați la SmartThings.
|
||||
'''Tap to choose'''=Atingeți pentru a selecta
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Selectare senzori Ecobee ({{numFound}} găsiți)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Contul dvs. ecobee este acum conectat la SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Faceți clic pe „Done” (Efectuat) pentru a finaliza configurarea.
|
||||
'''The connection could not be established!'''=Nu a putut fi stabilită conexiunea!
|
||||
'''Click 'Done' to return to the menu.'''=Faceți clic pe „Done” (Efectuat) pentru a reveni la meniu.
|
||||
'''is connected to SmartThings'''=este conectat la SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=este deconectat de la SmartThings, deoarece acreditările de acces au fost schimbate sau pierdute. Accesați aplicația Ecobee (Connect) SmartApp și reintroduceți acreditările de conectare la cont.
|
||||
'''Your Ecobee thermostat '''=Termostatul dvs. Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Подключите свой термостат Ecobee к SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Подключено.
|
||||
'''Click to enter Ecobee Credentials'''=Нажмите для ввода учетных данных Ecobee
|
||||
'''Login'''=Вход
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Коснитесь ниже, чтобы войти в службу ecobee и предоставить доступ SmartThings. Обязательно прокрутите страницу 2 до самого низа и нажмите кнопку «Разрешить».
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Выберите свои термостаты
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Коснитесь ниже, чтобы отобразить список доступных термостатов ecobee в вашей учетной записи ecobee, и выберите те, которые нужно подключить к SmartThings.
|
||||
'''Tap to choose'''=Коснитесь, чтобы выбрать
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Коснитесь ниже, чтобы отобразить список доступных датчиков ecobee в вашей учетной записи ecobee, и выберите те, которые нужно подключить к SmartThings.
|
||||
'''Tap to choose'''=Коснитесь, чтобы выбрать
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Выбрать датчики Ecobee (найдено {{numFound}})
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Теперь ваша учетная запись ecobee подключена к SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Для завершения настройки нажмите «Готово».
|
||||
'''The connection could not be established!'''=Не удалось установить соединение!
|
||||
'''Click 'Done' to return to the menu.'''=Чтобы вернуться в меню, нажмите «Готово».
|
||||
'''is connected to SmartThings'''=подключено к SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=отключено от SmartThings, поскольку данные для доступа были изменены или потеряны. Перейдите в Ecobee (Подключить) SmartApp и повторно введите регистрационные данные своей учетной записи.
|
||||
'''Your Ecobee thermostat '''=Ваш термостат Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Pripojte termostat Ecobee k systému SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Ste pripojení.
|
||||
'''Click to enter Ecobee Credentials'''=Kliknite a zadajte poverenia pre Ecobee
|
||||
'''Login'''=Prihlásiť sa
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Ťuknutím nižšie sa prihláste k službe ecobee a autorizujte prístup do systému SmartThings. Prejdite nadol na stránku 2 a stlačte tlačidlo Allow (Povoliť).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Vyberte termostaty
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ťuknutím nižšie môžete zobraziť zoznam termostatov ecobee dostupných vo vašom konte ecobee a vybrať tie, ktoré chcete pripojiť k systému SmartThings.
|
||||
'''Tap to choose'''=Ťuknutím vyberte
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ťuknutím nižšie môžete zobraziť zoznam senzorov ecobee dostupných vo vašom konte ecobee a vybrať tie, ktoré chcete pripojiť k systému SmartThings.
|
||||
'''Tap to choose'''=Ťuknutím vyberte
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Vyberte senzory Ecobee (nájdené: {{numFound}})
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Vaše konto ecobee je teraz prepojené so systémom SmartThings.
|
||||
'''Click 'Done' to finish setup.'''=Kliknutím na tlačidlo Done (Hotovo) dokončite inštaláciu.
|
||||
'''The connection could not be established!'''=Nepodarilo sa nadviazať spojenie.
|
||||
'''Click 'Done' to return to the menu.'''=Kliknutím na tlačidlo Done (Hotovo) sa vráťte do menu.
|
||||
'''is connected to SmartThings'''=je pripojený k systému SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=je odpojený od systému SmartThings, pretože prístupové poverenia boli zmenené alebo stratené. Prejdite do aplikácie Ecobee (Connect) SmartApp a znova zadajte prihlasovacie poverenia pre konto.
|
||||
'''Your Ecobee thermostat '''=Váš termostat Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Povežite termostat Ecobee s storitvijo SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Povezani ste.
|
||||
'''Click to enter Ecobee Credentials'''=Kliknite za vnos poverilnic Ecobee
|
||||
'''Login'''=Prijava
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Pritisnite spodaj, da se prijavite v storitev ecobee in odobrite dostop do storitve SmartThings. Pomaknite se na 2. stran in pritisnite gumb »Allow« (Dovoli).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Izberite svoje termostate
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pritisnite spodaj za prikaz seznama termostatov ecobee, ki so na voljo v vašem računu ecobee, in izberite tiste, ki jih želite povezati s storitvijo SmartThings.
|
||||
'''Tap to choose'''=Pritisnite za izbiranje
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Pritisnite spodaj za prikaz seznama senzorjev ecobee, ki so na voljo v vašem računu ecobee, in izberite tiste, ki jih želite povezati s storitvijo SmartThings.
|
||||
'''Tap to choose'''=Pritisnite za izbiranje
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Izberite senzorje Ecobee (št. najdenih: {{numFound}})
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Vaš račun ecobee je zdaj povezan s storitvijo SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Kliknite »Done« (Končano), da zaključite nastavitev.
|
||||
'''The connection could not be established!'''=Povezave ni bilo mogoče vzpostaviti!
|
||||
'''Click 'Done' to return to the menu.'''=Kliknite »Done« (Končano), da se vrnete v meni.
|
||||
'''is connected to SmartThings'''=je povezan s storitvijo SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=ni povezan s storitvijo SmartThings, ker so bile poverilnice za dostop spremenjene ali izgubljene. Pojdite v aplikacijo Ecobee (Connect) SmartApp in znova vnesite poverilnice za prijavo v račun.
|
||||
'''Your Ecobee thermostat '''=Vaš termostat Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Lidh termostatin Ecobee me SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Je lidhur.
|
||||
'''Click to enter Ecobee Credentials'''=Kliko për të futur kredencialet Ecobee
|
||||
'''Login'''=Login
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Trokit më poshtë për t’u loguar në shërbimin ecobee dhe autorizuar aksesin në SmartThings. Sigurohu që të lundrosh poshtë në faqen 2 dhe të shtypësh butonin ‘Allow’ (Lejo).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Përzgjidh termostatet e tua
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Trokit më poshtë për të parë listën e termostateve ecobee që janë në dispozicion në llogarinë tënde ecobee dhe përzgjidh ato që dëshiron të lidhen me SmartThings.
|
||||
'''Tap to choose'''=Trokit për të zgjedhur
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Trokit më poshtë për të parë listën e sensorëve ecobee që janë në dispozicion në llogarinë tënde ecobee dhe përzgjidh ato që dëshiron të lidhen me SmartThings.
|
||||
'''Tap to choose'''=Trokit për të zgjedhur
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Përzgjidh sensorët Ecobee (u gjet {{numFound}})
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Llogaria jote ecobee tani është lidhur me SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Kliko mbi ‘Done’ (U krye) për ta mbaruar konfigurimin.
|
||||
'''The connection could not be established!'''=Lidhja nuk u vendos dot!
|
||||
'''Click 'Done' to return to the menu.'''=Kliko mbi ‘Done’ (U krye) për t’u kthyer në meny.
|
||||
'''is connected to SmartThings'''=është lidhur me SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=është shkëputur nga SmartThings, sepse kredenciali i aksesit ka ndryshuar ose ka humbur. Shko te Ecobee (Connect) SmartApp dhe futi sërish kredencialet e logimit në llogari.
|
||||
'''Your Ecobee thermostat '''=Termostati yt Ecobee
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Povežite Ecobee termostat na SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Povezani ste.
|
||||
'''Click to enter Ecobee Credentials'''=Kliknite da biste uneli Ecobee akreditive
|
||||
'''Login'''=Login (Prijava)
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Kucnite ispod da biste se prijavili na uslugu ecobee i odobrili pristup aplikaciji SmartThings. Obavezno listajte nadole do stranice broj 2 i pritisnite dugme „Allow” (Dozvoli).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Izaberite termostate
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Kucnite ispod da biste videli listu dostupnih ecobee termostata na svom ecobee nalogu i izaberite one koje želite da povežete na SmartThings.
|
||||
'''Tap to choose'''=Kucnite da biste odabrali
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Kucnite ispod da biste videli listu dostupnih senzora na svom ecobee nalogu i izaberite one koje želite da povežete na SmartThings.
|
||||
'''Tap to choose'''=Kucnite da biste odabrali
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Izaberite Ecobee senzore ({{numFound}} pronađeno)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Vaš ecobee nalog je sada povezan na SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Kliknite na „Done” (Gotovo) za kraj konfiguracije.
|
||||
'''The connection could not be established!'''=Veza nije uspostavljena!
|
||||
'''Click 'Done' to return to the menu.'''=Kliknite na „Done” (Gotovo) da biste se vratili na meni.
|
||||
'''is connected to SmartThings'''=je povezan na SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=je prekinuo vezu sa aplikacijom SmartThings zato što su akreditivi za pristup promenjeni ili izgubljeni. Idite na aplikaciju Ecobee (Connect) SmartApp i ponovo unesite akreditive za prijavljivanje na nalog.
|
||||
'''Your Ecobee thermostat '''=Vaš Ecobee termostat
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Anslut din Ecobee-termostat till SmartThings.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Du är ansluten.
|
||||
'''Click to enter Ecobee Credentials'''=Klicka för att ange dina Ecobee-inloggningsuppgifter
|
||||
'''Login'''=Logga in
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Tryck nedan för att logga in på ecobee-tjänsten och ge SmartThings åtkomst. Rulla ned till sidan 2 och tryck på knappen Allow (Tillåt).
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Välj dina termostater
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tryck nedan om du vill se listan med ecobee-termostater som är tillgängliga i ditt ecobee-konto och välj dem du vill ansluta till SmartThings.
|
||||
'''Tap to choose'''=Tryck för att välja
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Tryck nedan om du vill se listan med ecobee-givare som är tillgängliga i ditt ecobee-konto och välj dem du vill ansluta till SmartThings.
|
||||
'''Tap to choose'''=Tryck för att välja
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Välj Ecobee-givare ({{numFound}} hittades)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Ditt ecobee-konto är nu anslutet till SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Klicka på Done (Klart) för att slutföra konfigurationen.
|
||||
'''The connection could not be established!'''=Det gick inte att upprätta anslutningen!
|
||||
'''Click 'Done' to return to the menu.'''=Klicka på Done (Klart) för att återgå till menyn.
|
||||
'''is connected to SmartThings'''=är ansluten till SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=är frånkopplad från SmartThings, eftersom inloggningsuppgifterna har ändrats eller gått förlorade. Starta Ecobee (Connect) SmartApp och ange kontots inloggningsuppgifter igen.
|
||||
'''Your Ecobee thermostat '''=Din Ecobee-termostat
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=เชื่อมต่อตัวควบคุมอุณหภูมิ Ecobee ของคุณเข้ากับ SmartThings
|
||||
'''ecobee'''=Ecobee
|
||||
'''You are connected.'''=คุณได้เชื่อมต่อแล้ว
|
||||
'''Click to enter Ecobee Credentials'''=คลิกเพื่อใส่ ข้อมูลยืนยันตัวตน Ecobee
|
||||
'''Login'''=เข้าสู่ระบบ
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=แตะด้านล่างเพื่อเข้าสู่บริการ Ecobee และอนุญาตการเข้าถึงของ SmartThings ดูให้แน่ใจว่าได้เลื่อนลงมาที่หน้า 2 แล้วกดปุ่ม 'อนุญาต'
|
||||
'''ecobee'''=Ecobee
|
||||
'''Select Your Thermostats'''=เลือกตัวควบคุมอุณหภูมิของคุณ
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=แตะที่ด้านล่างเพื่อดูรายการตัวควบคุมอุณหภูมิ Ecobee ที่มีอยู่ในบัญชีผู้ใช้ Ecobee ของคุณ และเลือกตัวควบคุมอุณหภูมิที่คุณต้องการจะเชื่อมต่อกับ SmartThings
|
||||
'''Tap to choose'''=แตะเพื่อเลือก <device name>
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=แตะที่ด้านล่างเพื่อดูรายการเซ็นเซอร์ Ecobee ที่มีอยู่ในบัญชีผู้ใช้ Ecobee ของคุณ และเลือกเซ็นเซอร์ที่คุณต้องการจะเชื่อมต่อกับ SmartThings
|
||||
'''Tap to choose'''=แตะเพื่อเลือก <device name>
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=เลือกเซ็นเซอร์ Ecobee ({{numFound}} found)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=ตอนนี้บัญชีผู้ใช้ Ecobee ของคุณเชื่อมต่อกับ SmartThings แล้ว
|
||||
'''Click 'Done' to finish setup.'''=คลิก 'เสร็จสิ้น' เพื่อทำการตั้งค่าให้เสร็จสิ้น
|
||||
'''The connection could not be established!'''=ไม่สามารถสร้างการเชื่อมต่อได้!
|
||||
'''Click 'Done' to return to the menu.'''=คลิก 'เสร็จสิ้น' เพื่อกลับไปยังเมนู
|
||||
'''is connected to SmartThings'''={{deviceName}} เชื่อมต่อกับ SmartThings แล้ว
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''={{deviceName}} ถูกตัดการเชื่อมต่อจาก SmartThings เนื่องจากข้อมูลการเข้าถึงถูกเปลี่ยนแปลงหรือหายไป กรุณาไปที่ Ecobee (การเชื่อมต่อ) SmartApp และใส่ข้อมูลยืนยันตัวตนการเข้าสู่บัญชีผู้ใช้ของคุณอีกครั้ง
|
||||
'''Your Ecobee thermostat '''=ตัวควบคุมอุณหภูมิ Ecobee ของคุณ
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=Ecobee termostatınızı SmartThings'e bağlayın.
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=Bağlantı kurdunuz.
|
||||
'''Click to enter Ecobee Credentials'''=Ecobee Kimlik Bilgilerinizi girmek için tıklayın
|
||||
'''Login'''=Oturum aç
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=Ecobee servisinde oturum açmak ve SmartThings erişimine izin vermek için aşağıya dokunun. Ekranı 2. sayfaya kaydırdığınızdan emin olun ve 'İzin Ver' tuşuna basın.
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=Termostatlarınızı Seçin
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ecobee hesabınızda mevcut olan ecobee termostatlarının listesini görüntülemek için aşağıya dokunun ve SmartThings'e bağlamak istediklerinizi seçin.
|
||||
'''Tap to choose'''=<cihaz ismi> seçmek için dokunun
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=Ecobee hesabınızda mevcut olan ecobee sensörlerinin listesini görüntülemek için aşağıya dokunun ve SmartThings'e bağlamak istediklerinizi seçin.
|
||||
'''Tap to choose'''=<cihaz ismi> seçmek için dokunun
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=Ecobee Sensörlerini seçin ({{numFound}} bulundu)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=Ecobee Hesabınız artık SmartThings'e bağlandı!
|
||||
'''Click 'Done' to finish setup.'''=Kurulumu bitirmek için 'Bitti' öğesine tıklayın.
|
||||
'''The connection could not be established!'''=Bağlantı kurulamadı!
|
||||
'''Click 'Done' to return to the menu.'''=Menüye dönmek için 'Bitti' öğesine tıklayın.
|
||||
'''is connected to SmartThings'''={{cihazİsmi}} SmartThings'e bağlandı
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=Erişim kimlik doğruları değiştirildiğinden veya kaybolduğundan {{cihazİsmi}} ile SmartThings arasındaki bağlantı kesildi. Lütfen Ecobee (Connect) SmartApp'e gidin ve hesabınızın oturum açma kimlik bilgilerini tekrar girin.
|
||||
'''Your Ecobee thermostat '''=Ecobee termostatınız
|
||||
@@ -1,20 +0,0 @@
|
||||
'''Connect your Ecobee thermostat to SmartThings.'''=将 Ecobee 恒温器连接至 SmartThings。
|
||||
'''ecobee'''=ecobee
|
||||
'''You are connected.'''=已连接。
|
||||
'''Click to enter Ecobee Credentials'''=点击以输入 Ecobee 凭据
|
||||
'''Login'''=登录
|
||||
'''Tap below to log in to the ecobee service and authorize SmartThings access. Be sure to scroll down on page 2 and press the 'Allow' button.'''=点击下方以登录 ecobee 服务并授予 SmartThings 访问权限。务必在第 2 页上向下滚动,然后按下“允许”按钮。
|
||||
'''ecobee'''=ecobee
|
||||
'''Select Your Thermostats'''=选择恒温器
|
||||
'''Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings.'''=点击下方以查看 ecobee 帐户中可用 ecobee 恒温器的列表,然后选择要连接至 SmartThings 的恒温器。
|
||||
'''Tap to choose'''=点击以选择
|
||||
'''Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings.'''=点击下方以查看 ecobee 帐户中可用 ecobee 传感器的列表,然后选择要连接至 SmartThings 的传感器。
|
||||
'''Tap to choose'''=点击以选择
|
||||
'''Select Ecobee Sensors ({{numFound}} found)'''=选择 Ecobee 传感器 (发现 {{numFound}} 个)
|
||||
'''Your ecobee Account is now connected to SmartThings!'''=ecobee 帐户现在已连接至 SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=单击“完成”以完成设置。
|
||||
'''The connection could not be established!'''=无法建立连接!
|
||||
'''Click 'Done' to return to the menu.'''=单击“完成”返回菜单。
|
||||
'''is connected to SmartThings'''=已连接至 SmartThings
|
||||
'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=已从 SmartThings 断开,因为访问凭据已更改或丢失。请转到 Ecobee (连接) SmartApp,然后重新输入您的帐户登录凭据。
|
||||
'''Your Ecobee thermostat '''=您的 Ecobee 恒温器
|
||||
@@ -17,14 +17,14 @@
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "Hue (Connect)",
|
||||
namespace: "smartthings",
|
||||
author: "SmartThings",
|
||||
description: "Allows you to connect your Philips Hue lights with SmartThings and control them from your Things area or Dashboard in the SmartThings Mobile app. Adjust colors by going to the Thing detail screen for your Hue lights (tap the gear on Hue tiles).\n\nPlease update your Hue Bridge first, outside of the SmartThings app, using the Philips Hue app.",
|
||||
category: "SmartThings Labs",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png",
|
||||
singleInstance: true
|
||||
name: "Hue (Connect)",
|
||||
namespace: "smartthings",
|
||||
author: "SmartThings",
|
||||
description: "Allows you to connect your Philips Hue lights with SmartThings and control them from your Things area or Dashboard in the SmartThings Mobile app. Adjust colors by going to the Thing detail screen for your Hue lights (tap the gear on Hue tiles).\n\nPlease update your Hue Bridge first, outside of the SmartThings app, using the Philips Hue app.",
|
||||
category: "SmartThings Labs",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png",
|
||||
singleInstance: true
|
||||
)
|
||||
|
||||
preferences {
|
||||
@@ -85,8 +85,7 @@ def bridgeDiscovery(params=[:])
|
||||
}
|
||||
|
||||
return dynamicPage(name:"bridgeDiscovery", title:"Discovery Started!", nextPage:"bridgeBtnPush", refreshInterval:refreshInterval, uninstall: true) {
|
||||
section("Please wait while we discover your Hue Bridge. Kindly note that you must first configure your Hue Bridge and Lights using the Philips Hue application. " +
|
||||
"Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
||||
section("Please wait while we discover your Hue Bridge. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
||||
input "selectedHue", "enum", required:false, title:"Select Hue Bridge (${numFound} found)", multiple:false, options:options, submitOnChange: true
|
||||
}
|
||||
}
|
||||
@@ -173,34 +172,18 @@ def bulbDiscovery() {
|
||||
if (existingLightsDescription.isEmpty()) {
|
||||
existingLightsDescription += it.value
|
||||
} else {
|
||||
existingLightsDescription += ", ${it.value}"
|
||||
existingLightsDescription += ", ${it.value}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bulbRefreshCount > 200 && numFound == 0) {
|
||||
// Time out after 10 minutes
|
||||
state.inBulbDiscovery = false
|
||||
bulbRefreshCount = 0
|
||||
return dynamicPage(name:"bulbDiscovery", title:"Light Discovery Failed!", nextPage:"", refreshInterval:0, install:true, uninstall: true) {
|
||||
section("Failed to discover any lights, please try again later. Click Done to exit.") {
|
||||
//input "selectedBulbs", "enum", required:false, title:"Select Hue Lights to add (${numFound} found)", multiple:true, submitOnChange: true, options:newLights
|
||||
paragraph title: "Previously added Hue Lights (${existingLights.size()} added)", existingLightsDescription
|
||||
}
|
||||
section {
|
||||
href "bridgeDiscovery", title: title, description: "", state: selectedHue ? "complete" : "incomplete", params: [override: true]
|
||||
}
|
||||
return dynamicPage(name:"bulbDiscovery", title:"Light Discovery Started!", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) {
|
||||
section("Please wait while we discover your Hue Lights. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
||||
input "selectedBulbs", "enum", required:false, title:"Select Hue Lights to add (${numFound} found)", multiple:true, submitOnChange: true, options:newLights
|
||||
paragraph title: "Previously added Hue Lights (${existingLights.size()} added)", existingLightsDescription
|
||||
}
|
||||
|
||||
} else {
|
||||
return dynamicPage(name:"bulbDiscovery", title:"Light Discovery Started!", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) {
|
||||
section("Please wait while we discover your Hue Lights. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
||||
input "selectedBulbs", "enum", required:false, title:"Select Hue Lights to add (${numFound} found)", multiple:true, submitOnChange: true, options:newLights
|
||||
paragraph title: "Previously added Hue Lights (${existingLights.size()} added)", existingLightsDescription
|
||||
}
|
||||
section {
|
||||
href "bridgeDiscovery", title: title, description: "", state: selectedHue ? "complete" : "incomplete", params: [override: true]
|
||||
}
|
||||
section {
|
||||
href "bridgeDiscovery", title: title, description: "", state: selectedHue ? "complete" : "incomplete", params: [override: true]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,32 +200,32 @@ private sendDeveloperReq() {
|
||||
def token = app.id
|
||||
def host = getBridgeIP()
|
||||
sendHubCommand(new physicalgraph.device.HubAction([
|
||||
method: "POST",
|
||||
path: "/api",
|
||||
headers: [
|
||||
HOST: host
|
||||
],
|
||||
body: [devicetype: "$token-0"]], "${selectedHue}", [callback: "usernameHandler"]))
|
||||
method: "POST",
|
||||
path: "/api",
|
||||
headers: [
|
||||
HOST: host
|
||||
],
|
||||
body: [devicetype: "$token-0"]], "${selectedHue}", [callback: "usernameHandler"]))
|
||||
}
|
||||
|
||||
private discoverHueBulbs() {
|
||||
def host = getBridgeIP()
|
||||
sendHubCommand(new physicalgraph.device.HubAction([
|
||||
method: "GET",
|
||||
path: "/api/${state.username}/lights",
|
||||
headers: [
|
||||
HOST: host
|
||||
]], "${selectedHue}", [callback: "lightsHandler"]))
|
||||
method: "GET",
|
||||
path: "/api/${state.username}/lights",
|
||||
headers: [
|
||||
HOST: host
|
||||
]], "${selectedHue}", [callback: "lightsHandler"]))
|
||||
}
|
||||
|
||||
private verifyHueBridge(String deviceNetworkId, String host) {
|
||||
log.trace "Verify Hue Bridge $deviceNetworkId"
|
||||
sendHubCommand(new physicalgraph.device.HubAction([
|
||||
method: "GET",
|
||||
path: "/description.xml",
|
||||
headers: [
|
||||
HOST: host
|
||||
]], deviceNetworkId, [callback: "bridgeDescriptionHandler"]))
|
||||
method: "GET",
|
||||
path: "/description.xml",
|
||||
headers: [
|
||||
HOST: host
|
||||
]], deviceNetworkId, [callback: "bridgeDescriptionHandler"]))
|
||||
}
|
||||
|
||||
private verifyHueBridges() {
|
||||
@@ -400,7 +383,7 @@ def addBulbs() {
|
||||
log.debug "$dni in not longer paired to the Hue Bridge or ID changed"
|
||||
}
|
||||
} else {
|
||||
//backwards compatable
|
||||
//backwards compatable
|
||||
newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni }
|
||||
d = addChildBulb(dni, "Extended Color Light", newHueBulb?.value?.name, newHueBulb?.value?.hub)
|
||||
d?.completedSetup = true
|
||||
@@ -424,7 +407,7 @@ def addBridge() {
|
||||
if(vbridge) {
|
||||
def d = getChildDevice(selectedHue)
|
||||
if(!d) {
|
||||
// compatibility with old devices
|
||||
// compatibility with old devices
|
||||
def newbridge = true
|
||||
childDevices.each {
|
||||
if (it.getDeviceDataByName("mac")) {
|
||||
@@ -610,7 +593,7 @@ def locationHandler(evt) {
|
||||
log.trace "Location: $description"
|
||||
|
||||
def hub = evt?.hubId
|
||||
def parsedEvent = parseLanMessage(description)
|
||||
def parsedEvent = parseLanMessage(description)
|
||||
parsedEvent << ["hub":hub]
|
||||
|
||||
if (parsedEvent?.ssdpTerm?.contains("urn:schemas-upnp-org:device:basic:1")) {
|
||||
@@ -836,7 +819,8 @@ def parse(childDevice, description) {
|
||||
try {
|
||||
body = new groovy.json.JsonSlurper().parseText(bodyString)
|
||||
} catch (all) {
|
||||
log.warn "Parsing Body failed"
|
||||
log.warn "Parsing Body failed - trying again..."
|
||||
poll()
|
||||
}
|
||||
if (body instanceof java.util.Map) {
|
||||
// get (poll) reponse
|
||||
@@ -860,7 +844,7 @@ private sendColorEvents(device, xy, hue, sat, ct, colormode = null) {
|
||||
|
||||
def events = [:]
|
||||
// For now, only care about changing color temperature if requested by user
|
||||
if (ct != null && ct != 0 && (colormode == "ct" || (xy == null && hue == null && sat == null))) {
|
||||
if (ct != null && (colormode == "ct" || (xy == null && hue == null && sat == null))) {
|
||||
// for some reason setting Hue to their specified minimum off 153 yields 154, dealt with below
|
||||
// 153 (6500K) to 500 (2000K)
|
||||
def temp = (ct == 154) ? 6500 : Math.round(1000000 / ct)
|
||||
@@ -1152,7 +1136,7 @@ def setColorTemperature(childDevice, huesettings) {
|
||||
def ct = hueSettings == 6500 ? 153 : Math.round(1000000/huesettings)
|
||||
createSwitchEvent(childDevice, "on")
|
||||
put("lights/$id/state", [ct: ct, on: true])
|
||||
return "Setting color temperature to $ct"
|
||||
return "Setting color temperature to $percent"
|
||||
}
|
||||
|
||||
def setColor(childDevice, huesettings) {
|
||||
@@ -1227,7 +1211,7 @@ private poll() {
|
||||
def uri = "/api/${state.username}/lights/"
|
||||
log.debug "GET: $host$uri"
|
||||
sendHubCommand(new physicalgraph.device.HubAction("GET ${uri} HTTP/1.1\r\n" +
|
||||
"HOST: ${host}\r\n\r\n", physicalgraph.device.Protocol.LAN, selectedHue))
|
||||
"HOST: ${host}\r\n\r\n", physicalgraph.device.Protocol.LAN, selectedHue))
|
||||
}
|
||||
|
||||
private isOnline(id) {
|
||||
@@ -1244,10 +1228,10 @@ private put(path, body) {
|
||||
log.debug "BODY: ${bodyJSON}"
|
||||
|
||||
sendHubCommand(new physicalgraph.device.HubAction("PUT $uri HTTP/1.1\r\n" +
|
||||
"HOST: ${host}\r\n" +
|
||||
"Content-Length: ${length}\r\n" +
|
||||
"\r\n" +
|
||||
"${bodyJSON}", physicalgraph.device.Protocol.LAN, "${selectedHue}"))
|
||||
"HOST: ${host}\r\n" +
|
||||
"Content-Length: ${length}\r\n" +
|
||||
"\r\n" +
|
||||
"${bodyJSON}", physicalgraph.device.Protocol.LAN, "${selectedHue}"))
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1268,7 +1252,7 @@ private getBridgeIP() {
|
||||
if (d) {
|
||||
if (d.getDeviceDataByName("networkAddress"))
|
||||
host = d.getDeviceDataByName("networkAddress")
|
||||
else
|
||||
else
|
||||
host = d.latestState('networkAddress').stringValue
|
||||
}
|
||||
if (host == null || host == "") {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=يتيح لك استخدام مصابيح LIFX الذكية من خلال SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=النقر لإدخال بيانات اعتماد LIFX
|
||||
'''Connect to LIFX'''=الاتصال بـ LIFX
|
||||
'''Tap here to connect your LIFX account'''=النقر هنا لتوصيل حساب LIFX
|
||||
'''Connect to LIFX'''=الاتصال بـ LIFX
|
||||
'''Select your location'''=تحديد موقعك
|
||||
'''Select location ({{count}} found)'''=تحديد الموقع ({{count}} found)
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=حساب LIFX متصل الآن بـ SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=انقر فوق ”تم“ لإنهاء الإعداد.
|
||||
'''The connection could not be established!'''=يتعذر إنشاء الاتصال!
|
||||
'''Click 'Done' to return to the menu.'''=انقر فوق ”تم“ للعودة إلى القائمة.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=حساب LIFX متصل بالفعل بـ SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=انقر فوق ”تم“ لإنهاء الإعداد.
|
||||
'''SmartThings Connection'''=اتصال SmartThings
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Позволява да използвате интелигентни ел. крушки LIFX със SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Докоснете за въвеждане на идентификационни данни за LIFX
|
||||
'''Connect to LIFX'''=Свързване към LIFX
|
||||
'''Tap here to connect your LIFX account'''=Докоснете тук за свързване на вашия LIFX акаунт
|
||||
'''Connect to LIFX'''=Свързване към LIFX
|
||||
'''Select your location'''=Избор на местоположение
|
||||
'''Select location ({{count}} found)'''=Избор на местоположение ({{count}} са намерени)
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=Вашият LIFX акаунт вече е свързан към SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Щракнете върху Done (Готово), за да завършите настройката.
|
||||
'''The connection could not be established!'''=Връзката не може да се осъществи!
|
||||
'''Click 'Done' to return to the menu.'''=Щракнете върху Done (Готово), за да се върнете към менюто.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=Вашият LIFX акаунт вече е свързан към SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Щракнете върху Done (Готово), за да завършите настройката.
|
||||
'''SmartThings Connection'''=Свързване на SmartThings
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Umožní vám použít inteligentní žárovky LIFX se systémem SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Klepněte a zadejte přihlašovací údaje LIFX
|
||||
'''Connect to LIFX'''=Připojit k LIFX
|
||||
'''Tap here to connect your LIFX account'''=Klepnutím sem se připojíte k účtu LIFX
|
||||
'''Connect to LIFX'''=Připojit k LIFX
|
||||
'''Select your location'''=Vyberte vaši polohu
|
||||
'''Select location ({{count}} found)'''=Vyberte polohu (nalezeno {{count}})
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=Účet LIFX Account je nyní připojen k systému SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Dokončete nastavení klepnutím na tlačítko „Done“ (Hotovo).
|
||||
'''The connection could not be established!'''=Připojení nelze navázat!
|
||||
'''Click 'Done' to return to the menu.'''=Klepnutím na tlačítko „Done“ (Hotovo) se vrátíte do menu.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=Účet LIFX Account je již připojen k systému SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Dokončete nastavení klepnutím na tlačítko „Done“ (Hotovo).
|
||||
'''SmartThings Connection'''=Připojení SmartThings
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Giver dig mulighed for at bruge LIFX-smartpærer sammen med SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Tryk for at indtaste LIFX-legitimationsoplysninger
|
||||
'''Connect to LIFX'''=Forbind med LIFX
|
||||
'''Tap here to connect your LIFX account'''=Tryk her for at forbinde din LIFX-konto
|
||||
'''Connect to LIFX'''=Forbind med LIFX
|
||||
'''Select your location'''=Vælg din placering
|
||||
'''Select location ({{count}} found)'''=Vælg placering ({{count}} fundet)
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=Din LIFX-konto er nu forbundet med SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Klik på “Done” (Udført) for at afslutte konfigurationen.
|
||||
'''The connection could not be established!'''=Der kunne ikke oprettes forbindelse!
|
||||
'''Click 'Done' to return to the menu.'''=Klik på “Done” (Udført) for at vende tilbage til menuen.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=Din LIFX-konto er allerede forbundet med SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Klik på “Done” (Udført) for at afslutte konfigurationen.
|
||||
'''SmartThings Connection'''=SmartThings-forbindelse
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Ermöglicht die Verwendung intelligenter Glühbirnen von LIFX mit SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Tippen, um LIFX-Zugangsdaten einzugeben
|
||||
'''Connect to LIFX'''=Mit LIFX verbinden
|
||||
'''Tap here to connect your LIFX account'''=Hier tippen, um Ihr LIFX-Konto zu verbinden.
|
||||
'''Connect to LIFX'''=Mit LIFX verbinden
|
||||
'''Select your location'''=Ihren Standort auswählen
|
||||
'''Select location ({{count}} found)'''=Standortauswahl ({{count}} gefunden)
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=Ihr LIFX-Konto ist jetzt mit SmartThings verbunden!
|
||||
'''Click 'Done' to finish setup.'''=Klicken Sie auf „Done“ (OK), um die Einrichtung abzuschließen.
|
||||
'''The connection could not be established!'''=Es konnte keine Verbindung hergestellt werden!
|
||||
'''Click 'Done' to return to the menu.'''=Klicken Sie auf „Done“ (OK), um zum Menü zurückzukehren.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=Ihr LIFX-Konto ist bereits mit SmartThings verbunden!
|
||||
'''Click 'Done' to finish setup.'''=Klicken Sie auf „Done“ (OK), um die Einrichtung abzuschließen.
|
||||
'''SmartThings Connection'''=SmartThings-Verbindung
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Σας επιτρέπει να χρησιμοποιείτε έξυπνους λαμπτήρες LIFX με το SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Πατήστε για να καταχωρήσετε διαπιστευτήρια LIFX
|
||||
'''Connect to LIFX'''=Σύνδεση στο LIFX
|
||||
'''Tap here to connect your LIFX account'''=Πατήστε εδώ για να συνδέσετε το λογαριασμό σας LIFX
|
||||
'''Connect to LIFX'''=Σύνδεση στο LIFX
|
||||
'''Select your location'''=Επιλέξτε την τοποθεσία σας
|
||||
'''Select location ({{count}} found)'''=Επιλογή τοποθεσίας (βρέθηκαν {{count}})
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=Ο λογαριασμός σας στο LIFX έχει τώρα συνδεθεί στο SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Πατήστε "Done" (Τέλος) για να ολοκληρωθεί η ρύθμιση.
|
||||
'''The connection could not be established!'''=Δεν ήταν δυνατή η δημιουργία σύνδεσης!
|
||||
'''Click 'Done' to return to the menu.'''=Κάντε κλικ στο "Done" (Τέλος) για να επιστρέψετε στο μενού.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=Ο λογαριασμός σας στο LIFX έχει ήδη συνδεθεί στο SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Πατήστε "Done" (Τέλος) για να ολοκληρωθεί η ρύθμιση.
|
||||
'''SmartThings Connection'''=Σύνδεση SmartThings
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Allows you to use LIFX smart light bulbs with SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Tap to enter LIFX credentials
|
||||
'''Connect to LIFX'''=Connect to LIFX
|
||||
'''Tap here to connect your LIFX account'''=Tap here to connect your LIFX account
|
||||
'''Connect to LIFX'''=Connect to LIFX
|
||||
'''Select your location'''=Select your location
|
||||
'''Select location ({{count}} found)'''=Select location ({{count}} found)
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=Your LIFX Account is now connected to SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Click ’Done’ to exit setup.
|
||||
'''The connection could not be established!'''=The connection could not be established!
|
||||
'''Click 'Done' to return to the menu.'''=Click ’Done’ to return to the menu.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=Your LIFX Account is already connected to SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Click ’Done’ to finish setup.
|
||||
'''SmartThings Connection'''=SmartThings Connection
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Le permite utilizar bombillas de luz inteligente LIFX con SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Pulsar para introducir credenciales de LIFX
|
||||
'''Connect to LIFX'''=Conectar a LIFX
|
||||
'''Tap here to connect your LIFX account'''=Pulsar aquí para conectar la cuenta LIFX
|
||||
'''Connect to LIFX'''=Conectar a LIFX
|
||||
'''Select your location'''=Seleccionar ubicación
|
||||
'''Select location ({{count}} found)'''=Seleccionar ubicación ({{count}} encontrado)
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=¡Su cuenta de LIFX ya está conectada a SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Haga clic en “Done” (Hecho) para finalizar la configuración.
|
||||
'''The connection could not be established!'''=¡No se ha podido establecer la conexión!
|
||||
'''Click 'Done' to return to the menu.'''=Haga clic en “Done” (Hecho) para volver al menú.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=¡Su cuenta de LIFX ya está conectada a SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Haga clic en “Done” (Hecho) para finalizar la configuración.
|
||||
'''SmartThings Connection'''=Conexión de SmartThings
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Le permite usar las bombillas inteligentes LIFX con SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Pulse para introducir las credenciales de LIFX
|
||||
'''Connect to LIFX'''=Conectar a LIFX
|
||||
'''Tap here to connect your LIFX account'''=Pulse aquí para conectar su cuenta de LIFX
|
||||
'''Connect to LIFX'''=Conectar a LIFX
|
||||
'''Select your location'''=Seleccione su ubicación
|
||||
'''Select location ({{count}} found)'''=Seleccionar ubicación (hay {{count}})
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=¡Su cuenta de LIFX ahora está conectada a SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Haga clic en 'Done' ('Listo') para finalizar la configuración.
|
||||
'''The connection could not be established!'''=¡No fue posible establecer la conexión!
|
||||
'''Click 'Done' to return to the menu.'''=Haga clic en 'Done' ('Listo') para volver al menú.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=¡Su cuenta de LIFX ya está conectada a SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Haga clic en 'Done' ('Listo') para finalizar la configuración.
|
||||
'''SmartThings Connection'''=Conexión de SmartThings
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Võimaldab kasutada LIFXi nutikaid lambipirne teenusega SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Toksake, et sisestada teenuse LIFX volitused
|
||||
'''Connect to LIFX'''=Loo ühendus teenusega LIFX
|
||||
'''Tap here to connect your LIFX account'''=Toksake siia, et luua ühendus oma LIFXi kontoga
|
||||
'''Connect to LIFX'''=Loo ühendus teenusega LIFX
|
||||
'''Select your location'''=Valige oma asukoht
|
||||
'''Select location ({{count}} found)'''=Valige asukoht ({{count}} found)
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=Teie LIFXi konto on nüüd ühendatud teenusega SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Klõpsake valikut Valmis, et seadistamine lõpule viia.
|
||||
'''The connection could not be established!'''=Ühenduse loomine nurjus!
|
||||
'''Click 'Done' to return to the menu.'''=Klõpsake valikut Valmis, et naasta menüüsse.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=Teie LIFXi konto on juba ühendatud teenusega SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Klõpsake valikut Valmis, et seadistamine lõpule viia.
|
||||
'''SmartThings Connection'''=Teenuse SmartThings ühendus
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Mahdollistaa LIFX-älylamppujen käytön SmartThingsin kanssa.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Anna LIFX-tunnistetiedot
|
||||
'''Connect to LIFX'''=Muodosta LIFX-yhteys
|
||||
'''Tap here to connect your LIFX account'''=Napauta tätä, jos haluat muodostaa yhteyden LIFX-tiliisi
|
||||
'''Connect to LIFX'''=Muodosta LIFX-yhteys
|
||||
'''Select your location'''=Valitse sijaintisi
|
||||
'''Select location ({{count}} found)'''=Valitse sijainti ({{count}} löydetty)
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=LIFX-tilisi on nyt yhdistetty SmartThingsiin!
|
||||
'''Click 'Done' to finish setup.'''=Viimeistele asennus napsauttamalla Done (Valmis).
|
||||
'''The connection could not be established!'''=Yhteyden muodostaminen epäonnistui!
|
||||
'''Click 'Done' to return to the menu.'''=Palaa valikkoon napsauttamalla Done (Valmis).
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=LIFX-tilisi on jo yhdistetty SmartThingsiin!
|
||||
'''Click 'Done' to finish setup.'''=Viimeistele asennus napsauttamalla Done (Valmis).
|
||||
'''SmartThings Connection'''=SmartThings-yhteys
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Vous permet d'utiliser des ampoules intelligentes LIFX avec SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Appuyez pour saisir les informations d'identification LIFX
|
||||
'''Connect to LIFX'''=Connexion à LIFX
|
||||
'''Tap here to connect your LIFX account'''=Appuyez ici pour connecter votre compte LIFX
|
||||
'''Connect to LIFX'''=Connexion à LIFX
|
||||
'''Select your location'''=Sélection de votre zone géographique
|
||||
'''Select location ({{count}} found)'''=Sélection d'une zone géographique ({{count}} trouvée(s))
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=Votre compte LIFX est maintenant connecté à SmartThings !
|
||||
'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration.
|
||||
'''The connection could not be established!'''=La connexion n'a pas pu être établie !
|
||||
'''Click 'Done' to return to the menu.'''=Cliquez sur Done (Terminé) pour revenir au menu.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=Votre compte LIFX est déjà connecté à SmartThings !
|
||||
'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration.
|
||||
'''SmartThings Connection'''=Connexion SmartThings
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Vous permet d'utiliser des ampoules intelligentes LIFX avec SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Appuyez pour saisir les informations d'identification LIFX
|
||||
'''Connect to LIFX'''=Connexion à LIFX
|
||||
'''Tap here to connect your LIFX account'''=Appuyez ici pour connecter votre compte LIFX
|
||||
'''Connect to LIFX'''=Connexion à LIFX
|
||||
'''Select your location'''=Sélection de votre zone géographique
|
||||
'''Select location ({{count}} found)'''=Sélection d'une zone géographique ({{count}} trouvée(s))
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=Votre compte LIFX est maintenant connecté à SmartThings !
|
||||
'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration.
|
||||
'''The connection could not be established!'''=La connexion n'a pas pu être établie !
|
||||
'''Click 'Done' to return to the menu.'''=Cliquez sur Done (Terminé) pour revenir au menu.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=Votre compte LIFX est déjà connecté à SmartThings !
|
||||
'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration.
|
||||
'''SmartThings Connection'''=Connexion SmartThings
|
||||
@@ -1,15 +0,0 @@
|
||||
'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Dopušta vam da upotrebljavate pametne žarulje LIFX s uslugom SmartThings.
|
||||
'''LIFX'''=LIFX
|
||||
'''Tap to enter LIFX credentials'''=Dodirnite za unos podataka za prijavu za LIFX
|
||||
'''Connect to LIFX'''=Povezivanje na LIFX
|
||||
'''Tap here to connect your LIFX account'''=Dodirnite ovdje da biste povezali svoj račun za LIFX
|
||||
'''Connect to LIFX'''=Povezivanje na LIFX
|
||||
'''Select your location'''=Odaberite lokaciju
|
||||
'''Select location ({{count}} found)'''=Odaberite lokaciju (pronađeno: {{count}})
|
||||
'''Your LIFX Account is now connected to SmartThings!'''=Račun za LIFX sada je povezan s uslugom SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Kliknite „Done” (Gotovo) da biste dovršili postavljanje.
|
||||
'''The connection could not be established!'''=Veza se nije uspostavila!
|
||||
'''Click 'Done' to return to the menu.'''=Kliknite „Done” (Gotovo) za vraćanje na izbornik.
|
||||
'''Your LIFX Account is already connected to SmartThings!'''=Račun za LIFX već je povezan s uslugom SmartThings!
|
||||
'''Click 'Done' to finish setup.'''=Kliknite „Done” (Gotovo) da biste dovršili postavljanje.
|
||||
'''SmartThings Connection'''=Veza za SmartThings
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user