Hello,
I have a Climax PSM-29ZBSR Power Outlet that I have the basics working (on/off switch), but I havent been able to read the Energy Usage . I have programmed in other languages, but its my first ST device.
The Developer Documentation for the device can be found here (Clusters, attributes, etc):
https://fccid.io/pdf.php?id=2553357
Based on this documentation and my code posted below, I have a few questions.
- Do I have the ClusterOut set correctly in the fingerprint based on the developer documentation. It also mentions 0x0A? I
- Is the cluster out defined in fingerprint just used to identify the device, or is it also used to read from it later in the code.
- How can I read the different attributes from the 0x0702 cluster. There are
three diferent sets mentioned in the documentation (Reading information attribute set, format attribute set, historical attribute set) that have an identifier that is 0x00. I dont know how to get data from the different sets. How can I read them?
I have tried:
"st rattr 0x${device.deviceNetworkId} 1 0x0702 0"
That returns:
read attr - raw: 01E00107021400000025000000000000, dni: 01E0, endpoint: 01, cluster: 0702, size: 14, attrId: 0000, result: success, encoding: 25, value: 000000000000
This doesnt seem to provide the value of power consumtion.
I also have subscribed to cluster notifications with:
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0702 {${device.zigbeeId}} {}", "delay 500",
That returns information from attribute 0400 every 10 minutes as follows:
read attr - raw: 01E00107021E00042A880200000025000000000000, dni: 01E0, endpoint: 01, cluster: 0702, size: 1E, attrId: 0400, encoding: 2A, value: 000000000000250000000288
I am not sure if the information is in that value, or how to transform it.
Here is my complete code:
metadata {
definition (name: "Ozom Outlet", namespace: "bortuzar", author: "bortuzar") {
capability "Actuator"
capability "Configuration"
capability "Refresh"
capability "Sensor"
capability "Switch"
//capability "Switch Level"
capability "Energy Meter"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0702", outClusters: "0009"
}
// 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"
}
// UI tile definitions
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
/* controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 3, inactiveLabel: false) {
state "level", action:"switch level.setLevel"
} */
valueTile("power", "device.power", inactiveLabel: false, decoration: "flat") {
state "power", label: 'Power ${currentValue} W'
}
main(["switch"])
details(["switch", "power", "refresh"])
}
}
// Parse incoming device messages to generate events
/*
def parse(String description) {
log.trace description
if (description?.startsWith("catchall:")) {
def msg = zigbee.parse(description)
log.trace msg
log.trace "data: $msg.data"
if(description?.endsWith("0100"))
{
def result = createEvent(name: "switch", value: "on")
log.debug "Parse returned ${result?.descriptionText}"
return result
}
if(description?.endsWith("0000"))
{
def result = createEvent(name: "switch", value: "off")
log.debug "Parse returned ${result?.descriptionText}"
return result
}
}
if (description?.startsWith("read attr")) {
log.debug "READ ATTR "
def descMap = parseDescriptionAsMap(description)
log.debug "Read attr: $description"
log.debug description[-2..-1]
//so it only parses numeric values.Needs to be improved
if(description[-2..-1] != "tr")
{
//def i = Math.round(convertHexToInt(description[-2..-1]) / 256 * 100 )
def i = Math.round(convertHexToInt(description[-2..-1]) * 100 )
sendEvent( name: "level", value: i )
}
}
}
*/
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "PARSE METHOD Start"
log.trace description
/*
if (description?.startsWith("catchall:")) {
def msg = zigbee.parse(description)
log.trace "data: $msg.data"
} else if (description?.startsWith("read attr -")) {
def descMap = parseDescriptionAsMap(description)
log.debug descMap
log.debug "Read attr: $description"
} else if (descMap.cluster == "0006" && descMap.attrId == "0000") {
name = "switch"
value = descMap.value.endsWith("01") ? "on" : "off"
def result = createEvent(name: name, value: value)
log.debug "Parse returned ${result?.descriptionText}"
return result
} else if(descMap.cluster =="0702" && descMap.attrId == "0x00") {
def value = convertHexToInt(descMap.value)/10
//Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10
log.debug value
def name = "power"
def result = createEvent(name: name, value: value)
log.debug "Parse returned ${result?.descriptionText}"
return result //https://graph.api.smartthings.com/ide/device/editor/f64c2963-da1e-4ce3-8263-c9922e506c9c#
} else {
def name = description?.startsWith("on/off: ") ? "switch" : null
def value = name == "switch" ? (description?.endsWith(" 1") ? "on" : "off") : null
def result = createEvent(name: name, value: value)
log.debug "Parse returned ${result?.descriptionText}"
return result
}
*/
}
def on() {
log.debug "on()"
sendEvent(name: "switch", value: "on")
"st cmd 0x${device.deviceNetworkId} 1 6 1 {}"
}
def off() {
log.debug "off()"
sendEvent(name: "switch", value: "off")
"st cmd 0x${device.deviceNetworkId} 1 6 0 {}"
}
def refresh() {
log.debug "Refresh Start";
[
//"st rattr 0x${device.deviceNetworkId} 1 6 0", "delay 500",
//"st rattr 0x${device.deviceNetworkId} 1 0x0702 0x00", "delay 500"
]
log.debug "Refresh End";
}
/*
def setLevel(value) {
log.trace "setLevel($value)"
def cmds = []
if (value == 0) {
sendEvent(name: "switch", value: "off")
cmds << "st cmd 0x${device.deviceNetworkId} 1 8 0 {0000 0000}"
}
else if (device.latestValue("switch") == "off") {
sendEvent(name: "switch", value: "on")
}
sendEvent(name: "level", value: value)
def level = hexString(Math.round(value * 255/100))
cmds << "st cmd 0x${device.deviceNetworkId} 1 8 4 {${level} 0000}"
//log.debug cmds
cmds
}
*/
def configure() {
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
log.debug "Confuguring Reporting and Bindings."
def configCmds = [
//Switch Reporting
"zcl global send-me-a-report 6 0 0x10 0 3600 {01}", "delay 500",
"send 0x${device.deviceNetworkId} 1 1", "delay 1000",
//Level Control Reporting
"zcl global send-me-a-report 8 0 0x20 5 3600 {0010}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 1000",
"zdo bind 0x${device.deviceNetworkId} 1 1 8 {${device.zigbeeId}} {}", "delay 500",
//"zdo bind 0x${device.deviceNetworkId} 1 1 702 {${device.zigbeeId}} {}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0702 {${device.zigbeeId}} {}", "delay 500",
//"st rattr cmd 0x${device.deviceNetworkId} ${endpointId} 8 0 {}"
"st rattr 0x${device.deviceNetworkId} 1 0x0702 0"
]
return configCmds + refresh() // send refresh cmds as part of config
}
def parseDescriptionAsMap(description) {
(description - "read attr - ").split(",").inject([:]) { map, param ->
def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
}
private hex(value, width=2) {
def s = new BigInteger(Math.round(value).toString()).toString(16)
while (s.size() < width) {
s = "0" + s
}
s
}
private Integer convertHexToInt(hex) {
Integer.parseInt(hex,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
}
Any help woud be appreciated on how to get this working.
Thanks,
Benjamin