Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

MTRBaseDevice InvokeCommand method

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?

Answered by DTS Engineer in 829548022

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

First off, sorry for a bit of a delay getting back to you on this, it's been a busy week.

Let me start here:

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).

Basically, no, NSNumber isn't really the issue, as it basically just doesn't work this way. The input value type doesn't really matter and, frankly, it's probably weaker at enforcing value configuration than it should be. I would use "numberWithBool" as the initializer but that's primarily an ascetic choice.

However...

I am sending the following as the commandField parameter: ["type": "UnsignedInteger", "value": 1]

Did you try using "Boolean"?

Looking at the spec side of this:

The device receiving the command is using Matter 1.3 and is expecting a Boolean State Configuration new to that version of the spec.

I think this was basically just renaming an existing cluster, not actually defining a new type. I'm not sure how the framework handles new "stuff", but my expectation is that it wouldn't allow you to retrieve/create objects that it wouldn't also let you send commands too.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

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.

My firmware guys told me about the 1.3 Boolean State Configuration, I’ll try learning more about that and if it is a simple rename perhaps I can use something from 1.2 instead. I’ll also see if the firmware guys can tweak something to make it work.

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

MTRBaseDevice InvokeCommand method
 
 
Q