"st cmd" in device drivers?

I have a question about the ST CMD command …
I found a driver for the dresden fls-pp written by sticks18 and in it there is a line that says …

st cmd 0x4B98 0x0B 8 4 {00 1400}])

and I can’t find a source for the definition of the available commands and payloads. My immediate need is for the dresden device but any help about finding this info in general would be greatly appreciated

Is it ZigBee or Z-Wave?

For Z-Wave try: http://z-wave.sigmadesigns.com/design-z-wave/z-wave-public-specification/

For ZigBee try: http://www.zigbee.org/zigbee-for-developers/applicationstandards/zigbeehomeautomation/

The Zigbee Home Automation spec that @tgauchat linked to is a good reference but for this particular command you need to refer to the Zigbee Cluster Library. The download link on the Zigbee website seems to be broken right now but if you just search for Zigbee Cluster Library on the internet you should find a PDF.

This particular command string can be interpreted like this:

st cmd - The legacy API for executing an arbitrary Zigbee command. Note that we recommend using zigbee.command for new code. See One simple home system. A world of possibilities. | SmartThings for more info.

0x4B98 - this is the DNI (aka device network ID) of the device.

0x0B - this is the endpoint of the device.

8 - this is the cluster ID. Cluster ID refers to the Level Control cluster and is documented in the Zigbee Cluster Library specification.

4 - this is the command to execute. Command 4 in the Level Control cluster is Move To Level with On/Off. There is an example of using this command in that link posted above. It means set the level of the dimmer device and if the level is 0 also turn it off. If the device is off and the level is > 0 then also turn it on.

00 - the level to set to, in this case it will turn it off.

1400 - the transition time in tenths of a second as a little endian hex string. “1400” → 0x0014 tenths of a second = 2 seconds. This means the device should take 2 seconds to turn off.

1 Like

This one is 2015, but hopefully still relevant: https://www.nxp.com/docs/en/user-guide/JN-UG-3077.pdf

1 Like

Thanks much for the information - can either of you answer a pretty basic question for me - when a “cluster” is refereed to is it a physical thing - like 4 servers in an a HA Oracle cluster where each member of a cluster would get a given command or is it a logical construct or grouping that references that applicable commands for a device?

Having a little trouble wrapping my head around this.

It’s the latter, a grouping of related commands and attributes. There is a little more info about it here: http://docs.smartthings.com/en/latest/device-type-developers-guide/zigbee-primer.html?highlight=zigbee#clusters.

1 Like

thanks for the info - I have reviewed both the cluster library and the zigbee.command doc and I think I’m still missing something.

Using pages 334 trough 336 of the Zigbee Reference doc I don’t know how I could determine which variant of the zigbee.command to use because I can’t find a way to map which parts of the structure need to be filled in, nor do I know what order the zigbee.command fills the structure from the parameters passed to it. Is there a summary document or Rosetta stone that can help with this? Or am I missing the boat completely?

Have you looked at the cluster library doc that @tgauchat already linked to?

Zigbee is a third-party standard. Every zigbee message follows the same format. That format is listed in the cluster library documents. You just have to identify which clusters you’re looking at (from the initial set of numbers) and then you can look up that specific format in the cluster library documents. It should be very straightforward, but you will have to read the docs.

Make sure you read and understand all of part one before jumping into any of the individual cluster definitions.

I also recommend looking at the documentation for the zigbee home automation profile (ZHA) since that is the profile that smartthings uses. Again, read the introductory chapters before jumping in to any of the specific cluster documentation

1 Like

Thanks again guys for your time. I’ve spent a while reading and the fog is slowly lifting.

My original goal was to write a driver for a device with 2 endpoints - specifically an RGBW controller that allows the manipulation of the white channel separately from the RGB channel (yielding true white). This appears to have been implemented by having the RGB control on endpoint 0A and the white channel control on endpoint 0B. The suggestion was made to use zigbee.command rather than the st cmd - question is how do I specify the 0B endpoint to the zigbee.command?

Thanks in advance!

You can do something like:

zigbee.command(zigbee.COLOR_CONTROL_CLUSTER, 0x06, "${scaledHueValue} ${scaledSatValue} 0500", [destEndpoint: 0x0B])

Just change the second and third parameters for the command and payload that you wish to send.

See here for a little more info:

1 Like

Thanks Tom - is there a list of the optional keywords allowed to this and other commands which extends their functionality?

Tom - I’ve been digging away at the docs and hopefully these two questions won’t be too stupid…

From the developers documentation - page 702 …
“The parse() method may return a map defining the Event (page 770) to create and propagate through the Smart-Things platform, or a list of Events if multiple Events should be created…”

How do you know when you HAVE TO return an event and when you MAY?

Secondly - from the same page …

def parse(String description) {
log.debug “Parse description $description"
def name = null
def value = null
if (description?.startsWith(“read attr -”)) {
def descMap = parseDescriptionAsMap(description)
log.debug “Read attr: $description"
if (descMap.cluster == “0006” && descMap.attrId == “0000”) {
name = "switch"
value = descMap.value.endsWith(“01”) ? “on” : “off”
} else {
def reportValue = description.split(”,”).find {it.split(":")[0].trim() == “value”}?.split(":")[name = "power"
// assume 16 bit signed for encoding and power divisor is 10
value = Integer.parseInt(reportValue, 16).intdiv(10)
} else if (description?.startsWith(“on/off:”)) {
log.debug “Switch command"
name = “switch"
value = description?.endsWith(” 1”) ? “on” : “off”
// createEvent returns a Map that defines an Event
def result = createEvent(name: name, value: value)
log.debug “Parse returned ${result?.descriptionText}”
// returning the Event definition map creates an Event
// in the SmartThings platform, and propagates it to
// SmartApps subscribed to the device events.
return result

In reference to the highlighted name= assignments above - how does one know what name to provide? Is it always the associated capability/cluster?

Thanks for your patience

Not stupid at all, I found this stuff confusing the first time I looked at it. Plus I have the advantage of being able to look at all the code to see how it really works :slight_smile:

There are only two options mfgCode and destEndpoint and they are described in the doc link above.

An event is just a Map with specific keys like name and value. If the Zigbee message handled in parse needs to create an event then you must return a Map created by hand or with createEvent (or a list of same) OR you can call sendEvent but then you need to return an empty map ([:]) to prevent a default event from being created.

The name in this context is used to create the event so it should be the attribute name from the appropriate capability.

1 Like

As always - thanks for taking the time to answer.

If you get a chance can you point me to some documentation for the
message. What is its source, where in the handlers/events life cycle is it generated, what causes it to be generated and what the fields are would be helpful.

Lastly (for now :smirk:) the readattribute and writeattribute commands - are they synchronous (i.e. do they return only after the device object is updated or does the response come back at a latter time?)

Sorry - hit send to soon … I am assuming that read/writeattribute commands go out to the device and update the device object with returned results and doesn’t just read what currently in the device object - is that correct?