I am calling InvokeCommand on a MTRBaseDevice I received from HomeKit. The device receiving the command is using Matter 1.3 and is expecting a Boolean State Configuration new to that version of the spec. That may be the reason why I get the following error:
MTRInteractionErrorDomain Code=133 "The cluster command is malformed, has missing fields, or fields with invalid values.Command not carried out."
I am sending the following as the commandField parameter:
["type": "UnsignedInteger", "value": 1]
When I look into those values more deeply, the value is specified as an NSNumber holding an Int16 value of 1. I created the NSNumber using a Uint8(1). The docs suggest this should result in an NSNumber treated as an unsigned char, but the debugger reports it as a Int16. I tried changing the type in the command field to "SignedInteger" and this had no effect on the error I receive. So I suppose the problem could also be that my parameters always get a signed value when an unsigned value is expected. Is this something I can correct using the current APIs, or do I need to wait for Matter 1.3 support?
The value is 2 Boolean values stored as bits 0 and 1 in a UInt8. I chose the value I was trying to set as one that could be represented as a “Boolean”, but when I tried that as the type I still got the code 133 error.
Within the Matter spec "Boolean" in a independently defined data type, not simply a numeric format. This is part of it's original core behavior (it's actually inherited from Zigbee, see section 2.6.2.5 of the Zigbee Cluster Library Specification r8) not something that was added or implemented later. Note that the definition of a independant true/false type is common (HomeKit/HAP does a similar thing) to many accessory control protocols. A huge number of accessories have some kind of "binary" (On/Off, "Mute", "Active"...) state/format, so it makes sense for those cases to have their own type.
More broadly, it's important to understand that the kind of data conversion you're thinking of does NOT occur in Matter (or most hardware specs). A UInt8 is NOT "8 bits of data". It's a specific numeric data type with specific allowed values (2.6.2.7 see section of the Zigbee Cluster Library Specification). There IS in fact a different type for "8 bits of arbitrary", which is "data8".
The key point here is that you shouldn't expect an accessory to do ANY kind of automatic conversion* between type. Writing a UInt8 value to a Boolean element is just an invalid as writing a data8 or a UInt32 would be.
*I suspect the spec specifically REQUIRES the accessory to reject writes with the wrong type, but I haven't actually looked for the specific section.
However, that also means that this kind of conversion your describing does NOT occur. That is, an accessory should reject an UInt8 to a boolean element for exactly the same reason it should reject a data8 or map8 write. The wrong type is the wrong type, even if size happens to match.
That leads to here:
My firmware guys told me about the 1.3 Boolean State Configuration, I’ll try learning more about that
I had a little extra time and ended up taking a closer look at the matter spec side of this (see "1.8. Boolean State Configuration Cluster" of "Matter Application Cluster Specification") and that explains what's actually going wrong here. Depending on the element you're manipulating, they're defined as either:
-
uint8 with a valid range of 2 -> 10.
-
One of two cluster specific types, both of which derive from "map8" (which I believe you'd write as "map8").
That means a write of "1" would fail in all cases ("out of range" or "wrong data type").
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware