mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-09 13:21:53 +00:00
Compare commits
4 Commits
MSA-1113-5
...
MSA-65-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96e0995e43 | ||
|
|
bf7a7830cc | ||
|
|
7d90555006 | ||
|
|
04c19990cf |
313
devicetypes/lumivietnam/lumi-dimmer.src/lumi-dimmer.groovy
Normal file
313
devicetypes/lumivietnam/lumi-dimmer.src/lumi-dimmer.groovy
Normal file
@@ -0,0 +1,313 @@
|
||||
/**
|
||||
* Lumi Dimmer
|
||||
*
|
||||
* Copyright 2015 Lumi Vietnam
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
metadata {
|
||||
definition (name: "Lumi Dimmer", namespace: "lumivietnam", author: "Lumi Vietnam") {
|
||||
capability "Switch"
|
||||
capability "Switch Level"
|
||||
//capability "Configuration"
|
||||
capability "Refresh"
|
||||
capability "Actuator"
|
||||
capability "Sensor"
|
||||
|
||||
fingerprint profileId: "0104", endpointId: "9", deviceId: "0101", inClusters: "0000, 0003, 0006, 0008", outClusters: "0000", manufacturer: "Lumi Vietnam", model: "LM-DZ1"
|
||||
}
|
||||
|
||||
// simulator metadata
|
||||
simulator {
|
||||
// status messages
|
||||
status "on": "on/off: 1"
|
||||
status "off": "on/off: 0"
|
||||
|
||||
// reply messages
|
||||
reply "zcl on-off on": "on/off: 1"
|
||||
reply "zcl on-off off": "on/off: 0"
|
||||
}
|
||||
|
||||
tiles {
|
||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||
state "off", label: "Off", action: "switch.on", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "on"
|
||||
state "on", label: "On", action: "switch.off", icon: "st.switches.light.on", backgroundColor: "#79b821", nextState: "off"
|
||||
}
|
||||
standardTile("on", "device.onAll", decoration: "flat") {
|
||||
state "default", label: 'On', action: "on", icon: "st.switches.light.on", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("off", "device.offAll", decoration: "flat") {
|
||||
state "default", label: 'Off', action: "off", icon: "st.switches.light.off", backgroundColor: "#ffffff"
|
||||
}
|
||||
controlTile("levelControl", "device.levelControl", "slider", width: 2, height: 1) {
|
||||
state "default", action:"switch level.setLevel", backgroundColor:"#79b821"
|
||||
}
|
||||
valueTile("level", "device.level", inactiveLabel: false, decoration: "flat") {
|
||||
state "level", label: 'Level ${currentValue}%'
|
||||
}
|
||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
|
||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
main "switch"
|
||||
details(["switch", "on", "off", "levelControl", "level", "refresh"])
|
||||
}
|
||||
}
|
||||
|
||||
// Parse incoming device messages to generate events
|
||||
def parse(String description) {
|
||||
log.debug "description is $description"
|
||||
|
||||
def finalResult = isKnownDescription(description)
|
||||
if (finalResult != "false") {
|
||||
log.info finalResult
|
||||
if (finalResult.type == "update") {
|
||||
log.info "$device updates: ${finalResult.value}"
|
||||
}
|
||||
else {
|
||||
if (finalResult.type == "switch") {
|
||||
sendEvent(name: finalResult.type, value: finalResult.value)
|
||||
}
|
||||
else if (finalResult.type == "level") {
|
||||
sendEvent(name: "level", value: finalResult.value)
|
||||
sendEvent(name: "levelControl", value: finalResult.value)
|
||||
if (finalResult.value == 0)
|
||||
sendEvent(name: "switch", value: "off")
|
||||
else
|
||||
sendEvent(name: "switch", value: "on")
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||
log.debug parseDescriptionAsMap(description)
|
||||
}
|
||||
}
|
||||
|
||||
def off() {
|
||||
log.debug "0x${device.deviceNetworkId} Endpoint ${endpointId}"
|
||||
sendEvent(name: "level", value: "0")
|
||||
sendEvent(name: "levelControl", value: "0")
|
||||
"st cmd 0x${device.deviceNetworkId} ${endpointId} 0x0006 0 {}"
|
||||
}
|
||||
|
||||
def on() {
|
||||
log.debug "0x${device.deviceNetworkId} Endpoint ${endpointId}"
|
||||
sendEvent(name: "level", value: "50")
|
||||
sendEvent(name: "levelControl", value: "50")
|
||||
"st cmd 0x${device.deviceNetworkId} ${endpointId} 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
value = value as Integer
|
||||
sendEvent(name: "level", value: value)
|
||||
sendEvent(name: "levelControl", value: value)
|
||||
if (value == 0) {
|
||||
sendEvent(name: "switch", value: "off")
|
||||
"st cmd 0x${device.deviceNetworkId} ${endpointId} 0x0006 0 {}"
|
||||
}
|
||||
else {
|
||||
sendEvent(name: "switch", value: "on")
|
||||
setLevelWithRate(value, "0000")// + on()
|
||||
}
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
[
|
||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 6 0", "delay 500",
|
||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 8 0", "delay 500",
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
def configure() {
|
||||
onOffConfig() + levelConfig() + refresh()
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
else if(description?.startsWith("on/off:")) {
|
||||
def switchValue = description?.endsWith("1") ? "on" : "off"
|
||||
return [type: "switch", value : switchValue]
|
||||
}
|
||||
else {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
|
||||
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 "false"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//@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 "false"
|
||||
}
|
||||
}
|
||||
|
||||
def onOffConfig() {
|
||||
[
|
||||
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 6 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 6 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
|
||||
]
|
||||
}
|
||||
|
||||
//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} ${endpointId} 1 8 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 8 0 0x20 1 3600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
|
||||
]
|
||||
}
|
||||
|
||||
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}"]
|
||||
}
|
||||
|
||||
String convertToHexString(value, width=2) {
|
||||
def s = new BigInteger(Math.round(value).toString()).toString(16)
|
||||
while (s.size() < width) {
|
||||
s = "0" + s
|
||||
}
|
||||
s
|
||||
}
|
||||
317
devicetypes/lumivietnam/lumi-shade.src/lumi-shade.groovy
Normal file
317
devicetypes/lumivietnam/lumi-shade.src/lumi-shade.groovy
Normal file
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
* Lumi Shade
|
||||
*
|
||||
* Copyright 2015 Lumi Vietnam
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
metadata {
|
||||
definition (name: "Lumi Shade", namespace: "lumivietnam", author: "Lumi Vietnam") {
|
||||
capability "Switch"
|
||||
capability "Switch Level"
|
||||
//capability "Configuration"
|
||||
capability "Refresh"
|
||||
capability "Actuator"
|
||||
capability "Sensor"
|
||||
|
||||
fingerprint profileId: "0104", endpointId: "9", deviceId: "0200", inClusters: "0000, 0003, 0006, 0008", outClusters: "0000", manufacturer: "Lumi Vietnam", model: "LM-BZ1"
|
||||
}
|
||||
|
||||
// simulator metadata
|
||||
simulator {
|
||||
// status messages
|
||||
status "on": "on/off: 1"
|
||||
status "off": "on/off: 0"
|
||||
|
||||
// reply messages
|
||||
reply "zcl on-off on": "on/off: 1"
|
||||
reply "zcl on-off off": "on/off: 0"
|
||||
}
|
||||
|
||||
tiles {
|
||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||
state "off", label: "Closed", action: "switch.on", icon: "st.doors.garage.garage-closed", backgroundColor: "#ffffff", nextState: "turningOn"
|
||||
state "turningOn", label: "Opening", action:" switch.on", icon: "st.doors.garage.garage-opening", backgroundColor: "#79b821"
|
||||
state "on", label: "Opened", action: "switch.off", icon: "st.doors.garage.garage-open", backgroundColor: "#79b821", nextState: "turningOff"
|
||||
state "turningOff", label: "Closing", action:" switch.off", icon: "st.doors.garage.garage-closing", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("on", "device.onAll", decoration: "flat") {
|
||||
state "default", label: 'Open', action: "on", icon: "st.doors.garage.garage-opening", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("off", "device.offAll", decoration: "flat") {
|
||||
state "default", label: 'Close', action: "off", icon: "st.doors.garage.garage-closing", backgroundColor: "#ffffff"
|
||||
}
|
||||
controlTile("levelControl", "device.levelControl", "slider", width: 2, height: 1) {
|
||||
state "default", action:"switch level.setLevel", backgroundColor:"#79b821"
|
||||
}
|
||||
valueTile("level", "device.level", inactiveLabel: false, decoration: "flat") {
|
||||
state "level", label: 'Shade ${currentValue}%'
|
||||
}
|
||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
|
||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
main "switch"
|
||||
details(["switch", "on", "off", "levelControl", "level", "refresh"])
|
||||
}
|
||||
}
|
||||
|
||||
// Parse incoming device messages to generate events
|
||||
def parse(String description) {
|
||||
log.debug "description is $description"
|
||||
|
||||
def finalResult = isKnownDescription(description)
|
||||
if (finalResult != "false") {
|
||||
log.info finalResult
|
||||
if (finalResult.type == "update") {
|
||||
log.info "$device updates: ${finalResult.value}"
|
||||
}
|
||||
else {
|
||||
if (finalResult.type == "switch") {
|
||||
sendEvent(name: finalResult.type, value: finalResult.value)
|
||||
}
|
||||
else if (finalResult.type == "level") {
|
||||
sendEvent(name: "level", value: finalResult.value)
|
||||
sendEvent(name: "levelControl", value: finalResult.value)
|
||||
if (finalResult.value == 0) {
|
||||
sendEvent(name: "switch", value: "off")
|
||||
}
|
||||
else {
|
||||
sendEvent(name: "switch", value: "on")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||
log.debug parseDescriptionAsMap(description)
|
||||
}
|
||||
}
|
||||
|
||||
def off() {
|
||||
log.debug "0x${device.deviceNetworkId} Endpoint ${endpointId}"
|
||||
sendEvent(name: "level", value: "100")
|
||||
sendEvent(name: "levelControl", value: "0")
|
||||
"st cmd 0x${device.deviceNetworkId} ${endpointId} 0x0006 0 {}"
|
||||
}
|
||||
|
||||
def on() {
|
||||
log.debug "0x${device.deviceNetworkId} Endpoint ${endpointId}"
|
||||
sendEvent(name: "level", value: "100")
|
||||
sendEvent(name: "levelControl", value: "0")
|
||||
"st cmd 0x${device.deviceNetworkId} ${endpointId} 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def setLevel(value) {
|
||||
value = value as Integer
|
||||
sendEvent(name: "level", value: value)
|
||||
sendEvent(name: "levelControl", value: value)
|
||||
if (value == 100) {
|
||||
sendEvent(name: "switch", value: "off")
|
||||
"st cmd 0x${device.deviceNetworkId} ${endpointId} 0x0006 0 {}"
|
||||
}
|
||||
else {
|
||||
sendEvent(name: "switch", value: "on")
|
||||
setLevelWithRate(value, "0000")// + on()
|
||||
}
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
[
|
||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 6 0", "delay 500",
|
||||
"st rattr 0x${device.deviceNetworkId} ${endpointId} 8 0", "delay 500",
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
def configure() {
|
||||
onOffConfig() + levelConfig() + refresh()
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
else if(description?.startsWith("on/off:")) {
|
||||
def switchValue = description?.endsWith("1") ? "on" : "off"
|
||||
return [type: "switch", value : switchValue]
|
||||
}
|
||||
else {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
|
||||
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 "false"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//@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 "false"
|
||||
}
|
||||
}
|
||||
|
||||
def onOffConfig() {
|
||||
[
|
||||
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 6 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 6 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
|
||||
]
|
||||
}
|
||||
|
||||
//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} ${endpointId} 1 8 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 8 0 0x20 1 3600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
|
||||
]
|
||||
}
|
||||
|
||||
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}"]
|
||||
}
|
||||
|
||||
String convertToHexString(value, width=2) {
|
||||
def s = new BigInteger(Math.round(value).toString()).toString(16)
|
||||
while (s.size() < width) {
|
||||
s = "0" + s
|
||||
}
|
||||
s
|
||||
}
|
||||
195
devicetypes/lumivietnam/lumi-switch-1.src/lumi-switch-1.groovy
Normal file
195
devicetypes/lumivietnam/lumi-switch-1.src/lumi-switch-1.groovy
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* Lumi Switch 4
|
||||
*
|
||||
* Copyright 2015 Lumi Vietnam
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
metadata {
|
||||
definition (name: "Lumi Switch 1", namespace: "lumivietnam", author: "Lumi Vietnam") {
|
||||
capability "Actuator"
|
||||
//capability "Configuration"
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Switch"
|
||||
|
||||
attribute "switch1", "string"
|
||||
|
||||
command "on1"
|
||||
command "off1"
|
||||
|
||||
fingerprint profileId: "0104", deviceId: "0100", inClusters: "0000, 0003, 0006", outClusters: "0000", manufacturer: "Lumi Vietnam", model: "LM-SZ1"
|
||||
}
|
||||
|
||||
simulator {
|
||||
// status messages
|
||||
status "on": "on/off: 1"
|
||||
status "off": "on/off: 0"
|
||||
|
||||
// reply messages
|
||||
reply "zcl on-off 1": "on/off: 1"
|
||||
reply "zcl on-off 0": "on/off: 0"
|
||||
}
|
||||
|
||||
tiles {
|
||||
standardTile("switch1", "device.switch1", width: 2, height: 2, canChangeIcon: true) {
|
||||
state "on1", label: "SW1", action: "off1", icon: "st.switches.light.on", backgroundColor: "#79b821", nextState: "off1"
|
||||
state "off1", label: "SW1", action: "on1", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "on1"
|
||||
}
|
||||
standardTile("onAll", "device.onAll", decoration: "flat") {
|
||||
state "default", label: 'On', action: "on1", icon: "st.switches.light.on", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("offAll", "device.offAll", decoration: "flat") {
|
||||
state "default", label: 'Off', action: "off1", icon: "st.switches.light.off", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
main "switch1"
|
||||
details(["switch1", "onAll", "offAll", "refresh" ])
|
||||
}
|
||||
}
|
||||
|
||||
// parse events into attributes
|
||||
def parse(String description) {
|
||||
log.debug "Parsing '${description}'"
|
||||
def finalResult = isKnownDescription(description)
|
||||
if (finalResult != "false") {
|
||||
log.info finalResult
|
||||
if (finalResult.type == "update") {
|
||||
log.info "$device updates: ${finalResult.value}"
|
||||
}
|
||||
else if (finalResult.type == "switch") {
|
||||
if (finalResult.srcEP == "01") {
|
||||
state.sw1 = finalResult.value;
|
||||
sendEvent(name: "switch1", value: finalResult.value=="on"?"on1":"off1")
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||
log.debug parseDescriptionAsMap(description)
|
||||
}
|
||||
}
|
||||
|
||||
// handle commands
|
||||
def configure() {
|
||||
log.debug "Executing 'configure'"
|
||||
//Config binding and report for each endpoint
|
||||
[
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 0x0006 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 1"
|
||||
]
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
log.debug "Executing 'refresh'"
|
||||
//Read Attribute On Off Value
|
||||
[
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x0006 0"
|
||||
]
|
||||
}
|
||||
|
||||
def on1() {
|
||||
log.debug "Executing 'on1' 0x${device.deviceNetworkId} endpoint 1"
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def off1() {
|
||||
log.debug "Executing 'off1' 0x${device.deviceNetworkId} endpoint 1"
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 0 {}"
|
||||
}
|
||||
|
||||
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 {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
else if(description?.startsWith("on/off:")) {
|
||||
def switchValue = description?.endsWith("1") ? "on" : "off"
|
||||
return [type: "switch", value : switchValue]
|
||||
}
|
||||
else {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
|
||||
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 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, srcEP : descMap.sourceEndpoint]
|
||||
}
|
||||
else {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
253
devicetypes/lumivietnam/lumi-switch-2.src/lumi-switch-2.groovy
Normal file
253
devicetypes/lumivietnam/lumi-switch-2.src/lumi-switch-2.groovy
Normal file
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* Lumi Switch 2
|
||||
*
|
||||
* Copyright 2015 Lumi Vietnam
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
metadata {
|
||||
definition (name: "Lumi Switch 2", namespace: "lumivietnam", author: "Lumi Vietnam") {
|
||||
capability "Actuator"
|
||||
//capability "Configuration"
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Switch"
|
||||
|
||||
attribute "switch1", "string"
|
||||
attribute "switch2", "string"
|
||||
attribute "switchAll", "string"
|
||||
|
||||
command "on1"
|
||||
command "off1"
|
||||
command "on2"
|
||||
command "off2"
|
||||
command "onAll"
|
||||
command "offAll"
|
||||
|
||||
fingerprint profileId: "0104", deviceId: "0100", inClusters: "0000, 0003, 0006", outClusters: "0000", manufacturer: "Lumi Vietnam", model: "LM-SZ2"
|
||||
}
|
||||
|
||||
simulator {
|
||||
// status messages
|
||||
status "on": "on/off: 1"
|
||||
status "off": "on/off: 0"
|
||||
|
||||
// reply messages
|
||||
reply "zcl on-off 1": "on/off: 1"
|
||||
reply "zcl on-off 0": "on/off: 0"
|
||||
}
|
||||
|
||||
tiles {
|
||||
standardTile("switch1", "device.switch1", canChangeIcon: true) {
|
||||
state "on1", label: "SW1", action: "off1", icon: "st.switches.light.on", backgroundColor: "#79b821", nextState: "off1"
|
||||
state "off1", label: "SW1", action: "on1", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "on1"
|
||||
}
|
||||
standardTile("switch2", "device.switch2", canChangeIcon: true) {
|
||||
state "on2", label: "SW2", action: "off2", icon: "st.switches.light.on", backgroundColor: "#79b821", nextState: "off2"
|
||||
state "off2", label: "SW2", action: "on2", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "on2"
|
||||
}
|
||||
standardTile("switchAll", "device.switchAll", canChangeIcon: false) {
|
||||
state "onAll", label: "All", action: "offAll", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821", nextState: "offAll"
|
||||
state "offAll", label: "All", action: "onAll", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#ffffff", nextState: "onAll"
|
||||
}
|
||||
standardTile("onAll", "device.onAll", decoration: "flat") {
|
||||
state "default", label: 'On All', action: "onAll", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("offAll", "device.offAll", decoration: "flat") {
|
||||
state "default", label: 'Off All', action: "offAll", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
main (["switchAll", "switch1", "switch2"])
|
||||
details(["switch1", "switch2", "switchAll", "onAll", "offAll", "refresh" ])
|
||||
}
|
||||
}
|
||||
|
||||
// parse events into attributes
|
||||
def parse(String description) {
|
||||
log.debug "Parsing '${description}'"
|
||||
def finalResult = isKnownDescription(description)
|
||||
if (finalResult != "false") {
|
||||
log.info finalResult
|
||||
if (finalResult.type == "update") {
|
||||
log.info "$device updates: ${finalResult.value}"
|
||||
}
|
||||
else if (finalResult.type == "switch") {
|
||||
if (finalResult.srcEP == "01") {
|
||||
state.sw1 = finalResult.value;
|
||||
sendEvent(name: "switch1", value: finalResult.value=="on"?"on1":"off1")
|
||||
}
|
||||
else if (finalResult.srcEP == "03") {
|
||||
state.sw2 = finalResult.value;
|
||||
sendEvent(name: "switch2", value: finalResult.value=="on"?"on2":"off2")
|
||||
}
|
||||
//update state for switchAll Tile
|
||||
if (state.sw1 == "off" && state.sw2 == "off") {
|
||||
//log.debug "offalll"
|
||||
sendEvent(name: "switchAll", value: "offAll")
|
||||
}
|
||||
else if (state.sw1 == "on" && state.sw2 == "on") {
|
||||
//log.debug "onall"
|
||||
sendEvent(name: "switchAll", value: "onAll")
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||
log.debug parseDescriptionAsMap(description)
|
||||
}
|
||||
}
|
||||
|
||||
// handle commands
|
||||
def configure() {
|
||||
log.debug "Executing 'configure'"
|
||||
//Config binding and report for each endpoint
|
||||
[
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 0x0006 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||
|
||||
"zdo bind 0x${device.deviceNetworkId} 3 1 0x0006 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 0x0006 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 3"
|
||||
]
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
log.debug "Executing 'refresh'"
|
||||
//Read Attribute On Off Value of each endpoint
|
||||
[
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x0006 0", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 3 0x0006 0"
|
||||
]
|
||||
}
|
||||
|
||||
def on1() {
|
||||
log.debug "Executing 'on1' 0x${device.deviceNetworkId} endpoint 1"
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def off1() {
|
||||
log.debug "Executing 'off1' 0x${device.deviceNetworkId} endpoint 1"
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 0 {}"
|
||||
}
|
||||
|
||||
def on2() {
|
||||
log.debug "Executing 'on2' 0x${device.deviceNetworkId} endpoint 3"
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def off2() {
|
||||
log.debug "Executing 'off2' 0x${device.deviceNetworkId} endpoint 3"
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 0 {}"
|
||||
}
|
||||
|
||||
def onAll() {
|
||||
log.debug "Executing 'onAll' 0x${device.deviceNetworkId} endpoint 1 3"
|
||||
[
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 1 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 1 {}"
|
||||
]
|
||||
}
|
||||
|
||||
def offAll() {
|
||||
log.debug "Executing 'offAll' 0x${device.deviceNetworkId} endpoint 1 3"
|
||||
[
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 0 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 0 {}"
|
||||
]
|
||||
}
|
||||
|
||||
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 {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
else if(description?.startsWith("on/off:")) {
|
||||
def switchValue = description?.endsWith("1") ? "on" : "off"
|
||||
return [type: "switch", value : switchValue]
|
||||
}
|
||||
else {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
|
||||
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 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, srcEP : descMap.sourceEndpoint]
|
||||
}
|
||||
else {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
281
devicetypes/lumivietnam/lumi-switch-3.src/lumi-switch-3.groovy
Normal file
281
devicetypes/lumivietnam/lumi-switch-3.src/lumi-switch-3.groovy
Normal file
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* Lumi Switch 3
|
||||
*
|
||||
* Copyright 2015 Lumi Vietnam
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
metadata {
|
||||
definition (name: "Lumi Switch 3", namespace: "lumivietnam", author: "Lumi Vietnam") {
|
||||
capability "Actuator"
|
||||
//capability "Configuration"
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Switch"
|
||||
|
||||
attribute "switch1", "string"
|
||||
attribute "switch2", "string"
|
||||
attribute "switch3", "string"
|
||||
attribute "switchAll", "string"
|
||||
|
||||
command "on1"
|
||||
command "off1"
|
||||
command "on2"
|
||||
command "off2"
|
||||
command "on3"
|
||||
command "off3"
|
||||
command "onAll"
|
||||
command "offAll"
|
||||
|
||||
fingerprint profileId: "0104", deviceId: "0100", inClusters: "0000, 0003, 0006", outClusters: "0000", manufacturer: "Lumi Vietnam", model: "LM-SZ3"
|
||||
}
|
||||
|
||||
simulator {
|
||||
// status messages
|
||||
status "on": "on/off: 1"
|
||||
status "off": "on/off: 0"
|
||||
|
||||
// reply messages
|
||||
reply "zcl on-off 1": "on/off: 1"
|
||||
reply "zcl on-off 0": "on/off: 0"
|
||||
}
|
||||
|
||||
tiles {
|
||||
standardTile("switch1", "device.switch1", canChangeIcon: true) {
|
||||
state "on1", label: "SW1", action: "off1", icon: "st.switches.light.on", backgroundColor: "#79b821", nextState: "off1"
|
||||
state "off1", label: "SW1", action: "on1", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "on1"
|
||||
}
|
||||
standardTile("switch2", "device.switch2", canChangeIcon: true) {
|
||||
state "on2", label: "SW2", action: "off2", icon: "st.switches.light.on", backgroundColor: "#79b821", nextState: "off2"
|
||||
state "off2", label: "SW2", action: "on2", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "on2"
|
||||
}
|
||||
standardTile("switch3", "device.switch3", canChangeIcon: true) {
|
||||
state "on3", label: "SW3", action: "off3", icon: "st.switches.light.on", backgroundColor: "#79b821", nextState: "off3"
|
||||
state "off3", label: "SW3", action:"on3", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "on3"
|
||||
}
|
||||
standardTile("switchAll", "device.switchAll", canChangeIcon: false) {
|
||||
state "onAll", label: "All", action: "offAll", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821", nextState: "offAll"
|
||||
state "offAll", label: "All", action: "onAll", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#ffffff", nextState: "onAll"
|
||||
}
|
||||
standardTile("onAll", "device.onAll", decoration: "flat") {
|
||||
state "default", label: 'On All', action: "onAll", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("offAll", "device.offAll", decoration: "flat") {
|
||||
state "default", label: 'Off All', action: "offAll", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
main (["switchAll", "switch1", "switch2", "switch3"])
|
||||
details(["switch1", "switch2", "switch3", "onAll", "offAll", "switchAll", "refresh" ])
|
||||
}
|
||||
}
|
||||
|
||||
// parse events into attributes
|
||||
def parse(String description) {
|
||||
log.debug "Parsing '${description}'"
|
||||
def finalResult = isKnownDescription(description)
|
||||
if (finalResult != "false") {
|
||||
log.info finalResult
|
||||
if (finalResult.type == "update") {
|
||||
log.info "$device updates: ${finalResult.value}"
|
||||
}
|
||||
else if (finalResult.type == "switch") {
|
||||
if (finalResult.srcEP == "01") {
|
||||
state.sw1 = finalResult.value;
|
||||
sendEvent(name: "switch1", value: finalResult.value=="on"?"on1":"off1")
|
||||
}
|
||||
else if (finalResult.srcEP == "03") {
|
||||
state.sw2 = finalResult.value;
|
||||
sendEvent(name: "switch2", value: finalResult.value=="on"?"on2":"off2")
|
||||
}
|
||||
else if (finalResult.srcEP == "05") {
|
||||
state.sw3 = finalResult.value;
|
||||
sendEvent(name: "switch3", value: finalResult.value=="on"?"on3":"off3")
|
||||
}
|
||||
//update state for switchAll Tile
|
||||
if (state.sw1 == "off" && state.sw2 == "off" && state.sw3 == "off") {
|
||||
//log.debug "offalll"
|
||||
sendEvent(name: "switchAll", value: "offAll")
|
||||
}
|
||||
else if (state.sw1 == "on" && state.sw2 == "on" && state.sw3 == "on") {
|
||||
//log.debug "onall"
|
||||
sendEvent(name: "switchAll", value: "onAll")
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||
log.debug parseDescriptionAsMap(description)
|
||||
}
|
||||
}
|
||||
|
||||
// handle commands
|
||||
def configure() {
|
||||
log.debug "Executing 'configure'"
|
||||
//Config binding and report for each endpoint
|
||||
[
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 0x0006 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||
|
||||
"zdo bind 0x${device.deviceNetworkId} 3 1 0x0006 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 0x0006 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 3", "delay 500",
|
||||
|
||||
"zdo bind 0x${device.deviceNetworkId} 5 1 0x0006 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 0x0006 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 5"
|
||||
]
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
log.debug "Executing 'refresh'"
|
||||
//Read Attribute On Off Value of each endpoint
|
||||
[
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x0006 0", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 3 0x0006 0", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 5 0x0006 0"
|
||||
]
|
||||
}
|
||||
|
||||
def on1() {
|
||||
log.debug "Executing 'on1' 0x${device.deviceNetworkId} endpoint 1"
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def off1() {
|
||||
log.debug "Executing 'off1' 0x${device.deviceNetworkId} endpoint 1"
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 0 {}"
|
||||
}
|
||||
|
||||
def on2() {
|
||||
log.debug "Executing 'on2' 0x${device.deviceNetworkId} endpoint 3"
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def off2() {
|
||||
log.debug "Executing 'off2' 0x${device.deviceNetworkId} endpoint 3"
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 0 {}"
|
||||
}
|
||||
|
||||
def on3() {
|
||||
log.debug "Executing 'on3' 0x${device.deviceNetworkId} endpoint 5"
|
||||
"st cmd 0x${device.deviceNetworkId} 5 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def off3() {
|
||||
log.debug "Executing 'off3' 0x${device.deviceNetworkId} endpoint 5"
|
||||
"st cmd 0x${device.deviceNetworkId} 5 0x0006 0 {}"
|
||||
}
|
||||
|
||||
def onAll() {
|
||||
log.debug "Executing 'onAll' 0x${device.deviceNetworkId} endpoint 1 3 5"
|
||||
[
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 1 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 1 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 5 0x0006 1 {}"
|
||||
]
|
||||
}
|
||||
|
||||
def offAll() {
|
||||
log.debug "Executing 'offAll' 0x${device.deviceNetworkId} endpoint 1 3 5"
|
||||
[
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 0 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 0 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 5 0x0006 0 {}"
|
||||
]
|
||||
}
|
||||
|
||||
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 {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
else if(description?.startsWith("on/off:")) {
|
||||
def switchValue = description?.endsWith("1") ? "on" : "off"
|
||||
return [type: "switch", value : switchValue]
|
||||
}
|
||||
else {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
|
||||
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 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, srcEP : descMap.sourceEndpoint]
|
||||
}
|
||||
else {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
309
devicetypes/lumivietnam/lumi-switch-4.src/lumi-switch-4.groovy
Normal file
309
devicetypes/lumivietnam/lumi-switch-4.src/lumi-switch-4.groovy
Normal file
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* Lumi Switch 4
|
||||
*
|
||||
* Copyright 2015 Lumi Vietnam
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
metadata {
|
||||
definition (name: "Lumi Switch 4", namespace: "lumivietnam", author: "Lumi Vietnam") {
|
||||
capability "Actuator"
|
||||
//capability "Configuration"
|
||||
capability "Refresh"
|
||||
capability "Sensor"
|
||||
capability "Switch"
|
||||
|
||||
attribute "switch1", "string"
|
||||
attribute "switch2", "string"
|
||||
attribute "switch3", "string"
|
||||
attribute "switch4", "string"
|
||||
attribute "switchAll", "string"
|
||||
|
||||
command "on1"
|
||||
command "off1"
|
||||
command "on2"
|
||||
command "off2"
|
||||
command "on3"
|
||||
command "off3"
|
||||
command "on4"
|
||||
command "off4"
|
||||
command "onAll"
|
||||
command "offAll"
|
||||
|
||||
fingerprint profileId: "0104", deviceId: "0100", inClusters: "0000, 0003, 0006", outClusters: "0000", manufacturer: "Lumi Vietnam", model: "LM-SZ4"
|
||||
}
|
||||
|
||||
simulator {
|
||||
// status messages
|
||||
status "on": "on/off: 1"
|
||||
status "off": "on/off: 0"
|
||||
|
||||
// reply messages
|
||||
reply "zcl on-off 1": "on/off: 1"
|
||||
reply "zcl on-off 0": "on/off: 0"
|
||||
}
|
||||
|
||||
tiles {
|
||||
standardTile("switch1", "device.switch1", canChangeIcon: true) {
|
||||
state "on1", label: "SW1", action: "off1", icon: "st.switches.light.on", backgroundColor: "#79b821", nextState: "off1"
|
||||
state "off1", label: "SW1", action: "on1", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "on1"
|
||||
}
|
||||
standardTile("switch2", "device.switch2", canChangeIcon: true) {
|
||||
state "on2", label: "SW2", action: "off2", icon: "st.switches.light.on", backgroundColor: "#79b821", nextState: "off2"
|
||||
state "off2", label: "SW2", action: "on2", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "on2"
|
||||
}
|
||||
standardTile("switch3", "device.switch3", canChangeIcon: true) {
|
||||
state "on3", label: "SW3", action: "off3", icon: "st.switches.light.on", backgroundColor: "#79b821", nextState: "off3"
|
||||
state "off3", label: "SW3", action:"on3", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "on3"
|
||||
}
|
||||
standardTile("switch4", "device.switch4", canChangeIcon: true) {
|
||||
state "on4", label: "SW4", action: "off4", icon: "st.switches.light.on", backgroundColor: "#79b821", nextState: "off4"
|
||||
state "off4", label: "SW4", action:"on4", icon: "st.switches.light.off", backgroundColor: "#ffffff", nextState: "on4"
|
||||
}
|
||||
standardTile("switchAll", "device.switchAll", canChangeIcon: false) {
|
||||
state "onAll", label: "All", action: "offAll", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#79b821", nextState: "offAll"
|
||||
state "offAll", label: "All", action: "onAll", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#ffffff", nextState: "onAll"
|
||||
}
|
||||
standardTile("onAll", "device.onAll", decoration: "flat") {
|
||||
state "default", label: 'On All', action: "onAll", icon: "st.lights.multi-light-bulb-on", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("offAll", "device.offAll", decoration: "flat") {
|
||||
state "default", label: 'Off All', action: "offAll", icon: "st.lights.multi-light-bulb-off", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
main (["switchAll", "switch1", "switch2", "switch3", "switch4"])
|
||||
details(["switch1", "switch2", "onAll", "switch3", "switch4", "offAll", "switchAll", "refresh" ])
|
||||
}
|
||||
}
|
||||
|
||||
// parse events into attributes
|
||||
def parse(String description) {
|
||||
log.debug "Parsing '${description}'"
|
||||
def finalResult = isKnownDescription(description)
|
||||
if (finalResult != "false") {
|
||||
log.info finalResult
|
||||
if (finalResult.type == "update") {
|
||||
log.info "$device updates: ${finalResult.value}"
|
||||
}
|
||||
else if (finalResult.type == "switch") {
|
||||
if (finalResult.srcEP == "01") {
|
||||
state.sw1 = finalResult.value;
|
||||
sendEvent(name: "switch1", value: finalResult.value=="on"?"on1":"off1")
|
||||
}
|
||||
else if (finalResult.srcEP == "03") {
|
||||
state.sw2 = finalResult.value;
|
||||
sendEvent(name: "switch2", value: finalResult.value=="on"?"on2":"off2")
|
||||
}
|
||||
else if (finalResult.srcEP == "05") {
|
||||
state.sw3 = finalResult.value;
|
||||
sendEvent(name: "switch3", value: finalResult.value=="on"?"on3":"off3")
|
||||
}
|
||||
else if (finalResult.srcEP == "07") {
|
||||
state.sw4 = finalResult.value;
|
||||
sendEvent(name: "switch4", value: finalResult.value=="on"?"on4":"off4")
|
||||
}
|
||||
//update state for switchAll Tile
|
||||
if (state.sw1 == "off" && state.sw2 == "off" && state.sw3 == "off" && state.sw4 == "off") {
|
||||
//log.debug "offalll"
|
||||
sendEvent(name: "switchAll", value: "offAll")
|
||||
}
|
||||
else if (state.sw1 == "on" && state.sw2 == "on" && state.sw3 == "on" && state.sw4 == "on") {
|
||||
//log.debug "onall"
|
||||
sendEvent(name: "switchAll", value: "onAll")
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||
log.debug parseDescriptionAsMap(description)
|
||||
}
|
||||
}
|
||||
|
||||
// handle commands
|
||||
def configure() {
|
||||
log.debug "Executing 'configure'"
|
||||
//Config binding and report for each endpoint
|
||||
[
|
||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 0x0006 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||
|
||||
"zdo bind 0x${device.deviceNetworkId} 3 1 0x0006 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 0x0006 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 3", "delay 500",
|
||||
|
||||
"zdo bind 0x${device.deviceNetworkId} 5 1 0x0006 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 0x0006 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 5", "delay 500",
|
||||
|
||||
"zdo bind 0x${device.deviceNetworkId} 7 1 0x0006 {${device.zigbeeId}} {}", "delay 200",
|
||||
"zcl global send-me-a-report 0x0006 0 0x10 0 600 {01}",
|
||||
"send 0x${device.deviceNetworkId} 1 7"
|
||||
]
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
log.debug "Executing 'refresh'"
|
||||
//Read Attribute On Off Value of each endpoint
|
||||
[
|
||||
"st rattr 0x${device.deviceNetworkId} 1 0x0006 0", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 3 0x0006 0", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 5 0x0006 0", "delay 200",
|
||||
"st rattr 0x${device.deviceNetworkId} 7 0x0006 0"
|
||||
]
|
||||
}
|
||||
|
||||
def on1() {
|
||||
log.debug "Executing 'on1' 0x${device.deviceNetworkId} endpoint 1"
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def off1() {
|
||||
log.debug "Executing 'off1' 0x${device.deviceNetworkId} endpoint 1"
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 0 {}"
|
||||
}
|
||||
|
||||
def on2() {
|
||||
log.debug "Executing 'on2' 0x${device.deviceNetworkId} endpoint 3"
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def off2() {
|
||||
log.debug "Executing 'off2' 0x${device.deviceNetworkId} endpoint 3"
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 0 {}"
|
||||
}
|
||||
|
||||
def on3() {
|
||||
log.debug "Executing 'on3' 0x${device.deviceNetworkId} endpoint 5"
|
||||
"st cmd 0x${device.deviceNetworkId} 5 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def off3() {
|
||||
log.debug "Executing 'off3' 0x${device.deviceNetworkId} endpoint 5"
|
||||
"st cmd 0x${device.deviceNetworkId} 5 0x0006 0 {}"
|
||||
}
|
||||
|
||||
def on4() {
|
||||
log.debug "Executing 'on4' 0x${device.deviceNetworkId} endpoint 7"
|
||||
"st cmd 0x${device.deviceNetworkId} 7 0x0006 1 {}"
|
||||
}
|
||||
|
||||
def off4() {
|
||||
log.debug "Executing 'off4' 0x${device.deviceNetworkId} endpoint 7"
|
||||
"st cmd 0x${device.deviceNetworkId} 7 0x0006 0 {}"
|
||||
}
|
||||
|
||||
def onAll() {
|
||||
log.debug "Executing 'onAll' 0x${device.deviceNetworkId} endpoint 1 3 5 7"
|
||||
[
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 1 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 1 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 5 0x0006 1 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 7 0x0006 1 {}"
|
||||
]
|
||||
}
|
||||
|
||||
def offAll() {
|
||||
log.debug "Executing 'offAll' 0x${device.deviceNetworkId} endpoint 1 3 5 7"
|
||||
[
|
||||
"st cmd 0x${device.deviceNetworkId} 1 0x0006 0 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 3 0x0006 0 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 5 0x0006 0 {}", "delay 200",
|
||||
"st cmd 0x${device.deviceNetworkId} 7 0x0006 0 {}"
|
||||
]
|
||||
}
|
||||
|
||||
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 {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
else if(description?.startsWith("on/off:")) {
|
||||
def switchValue = description?.endsWith("1") ? "on" : "off"
|
||||
return [type: "switch", value : switchValue]
|
||||
}
|
||||
else {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
|
||||
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 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, srcEP : descMap.sourceEndpoint]
|
||||
}
|
||||
else {
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user