# matter-clusters
Typed Matter cluster definitions: per-cluster attribute/command/struct codecs,
feature flags, enums (with `Unknown(n)` forward-compat) and bitmaps. The modules
under `gen/` are generated from a pinned `@matter/model` dump by the `xtask`
codegen tool.
Part of [`matter-rust`](https://github.com/phunapps/matter-rust). Milestone 7.
## What this crate does
- Provides encode/decode functions for the attributes, commands, and structs of
47 Matter clusters (mandatory **and** optional attributes), as Matter TLV.
- Models cluster enums with an `Unknown(n)` variant (forward-compatible decode),
feature maps as `bitflags`, and nullable fields as `Nullable<T>` (distinct
from `Option<T>`).
- Generates all of the above from the spec model, gated against drift in CI.
## What this crate does not do
- It is **not** a full cluster set — only the 47 clusters below today. More
arrive in later batches.
- It does **not** provide generic or wildcard attribute access, or
manufacturer-specific typed codecs. Reading arbitrary attributes a device
publishes is the Interaction Model layer / high-level controller (see *Reading
attributes beyond these clusters*).
- It performs no IO and no session/transport work — it only encodes/decodes
bytes.
## Status
0.3.0. The 10 M7 clusters are generated and **byte-parity
tested against matter.js 0.16.11** (`test-vectors/clusters/`): BasicInformation,
Descriptor, Identify, OnOff, LevelControl, ColorControl, OccupancySensing,
TemperatureMeasurement, RelativeHumidityMeasurement, and DoorLock (Aliro
features excluded). The M9-A2.1 pilot batch adds 5 read-only clusters —
IlluminanceMeasurement, PressureMeasurement, FlowMeasurement, BooleanState, and
Switch — decode-smoke tested (they reuse datatype shapes already byte-parity
proven by the M7 set). The M9-A2.2 energy batch adds 4 more read-only clusters —
PowerSource, ElectricalPowerMeasurement, ElectricalEnergyMeasurement, and
AirQuality — decode-smoke tested, with a byte-parity vector for the new nested
`MeasurementAccuracyStruct` (a struct holding a list-of-struct with optional
fields). The M9-A2.3 actuator batch adds 5 read/write clusters — Thermostat,
FanControl, ThermostatUserInterfaceConfiguration, PumpConfigurationAndControl,
and WindowCovering — roundtrip (`decode(encode(x)) == x`) and decode-smoke
tested, with a byte-parity vector for the list-typed `AtomicRequest` command.
The M9-A2.4 utility batch adds 5 more clusters — Groups, Binding,
GeneralDiagnostics, FixedLabel, and UserLabel — decode-smoke tested (incl. the
Groups command encoders and the global `FabricIndex` typedef), with a byte-parity
vector for the new struct-with-byte-fields shape (GeneralDiagnostics
`NetworkInterface`: a `hwadr` bytes field, a keyword `Type` field, and
byte-string-element lists).
The M9-A2.5 management batch adds 4 more clusters — AccessControl,
GroupKeyManagement, AdministratorCommissioning, and OtaSoftwareUpdateRequestor —
**codecs only** (their protocol logic — ACL evaluation, group multicast,
window-open orchestration, OTA — belongs to later milestones). Decode-smoke
tested (incl. ACL entries whose `subject-id` subjects decode as `u64`), with a
byte-parity vector for the recursive list-of-struct command encode
(`AccessControl.ReviewFabricRestrictions`, whose `Arl` is a list of structs each
carrying a nested list-of-struct). Those five batches took the library from 10
clusters to 33.
Four more were added one at a time, each by the milestone that needed it:
OperationalCredentials (M9-D2), OtaSoftwareUpdateProvider (M9-F1 — command-only,
so it generates no attribute codecs), TimeSynchronization (M9-G-a), and
IcdManagement (M9-G-c). That is 37.
The concentration measurement family (Matter 1.2), reported missing by an
external adopter in [#112], adds the 10 read-only clusters that bring the total
to the 47 generated today —
CarbonMonoxide (0x040C), CarbonDioxide (0x040D), NitrogenDioxide (0x0413),
Ozone (0x0415), Pm25 (0x042A), Formaldehyde (0x042B), Pm1 (0x042C),
Pm10 (0x042D), TotalVolatileOrganicCompounds (0x042E), and Radon (0x042F)
ConcentrationMeasurement. They derive from one base cluster and so share a
single shape, which is why they are added as a family rather than piecemeal.
That shape carries this crate's first **float** (`single`/FLOAT32) attributes,
so alongside the per-cluster decode-smoke tests it gets a matter.js byte-parity
vector, an explicit round-trip over the binary32 edges (signed zero, subnormals,
infinities, NaN — compared by bits), and a `proptest` round-trip drawn uniformly
from the whole binary32 bit space. A `single` attribute accepts a FLOAT32
element only, matching chip's strict `TLVReader::Get(float&)`.
[#112]: https://github.com/phunapps/matter-rust/issues/112
For any attribute not covered by these typed codecs — optional,
manufacturer-specific, or a cluster not in this list — the generic `Value` path
in `matter-controller` remains the universal answer. Hand-written support lives
in `types` (`Nullable<T>`), `error` (`ClusterError`), and `datatypes`
(`SemanticTagStruct`).
## Usage
```rust
use matter_clusters::gen::{basic_information, on_off};
// Command payload — embed in an InvokeRequest.
let _toggle = on_off::encode_toggle();
// Attribute roundtrips: encode a value, decode it back.
let tlv = on_off::encode_on_time(30);
assert_eq!(on_off::decode_on_time(&tlv)?, 30);
let tlv = basic_information::encode_node_label(&"living room".to_string());
assert_eq!(basic_information::decode_node_label(&tlv)?, "living room");
# Ok::<(), matter_clusters::error::ClusterError>(())
```
See `crates/matter-commissioning/examples/control_onoff.rs` for an end-to-end
read / toggle / write against a real device (runbook:
`docs/runbooks/m7.5-control-onoff.md`).
## Generated code
`cargo xtask codegen` writes `src/gen/<cluster>.rs` (+ `globals.rs`, `mod.rs`)
from `xtask/model/clusters.json`. Do not edit the generated files by hand —
change the emitter (`xtask/src/codegen/`) and regenerate. `cargo xtask codegen
--check` gates drift in CI.
## Reading attributes beyond these clusters
Typed codecs cover these clusters' mandatory and optional attributes. To read
attributes of other clusters, or manufacturer-specific attributes, use the
generic Interaction Model path: `matter_interaction::parse_report_data` yields
`(AttributePath, matter_codec::Value)` for any attribute without a typed codec.
A high-level generic + wildcard read API (and more typed clusters) arrive in
later milestones.
## Correctness posture
- **Byte-parity** against matter.js 0.16.11 TLV combinators
(`test-vectors/clusters/`): every generated codec round-trips to the captured
oracle.
- **`proptest` roundtrips** over attribute values.
- **A `cargo-fuzz` target** over the generated decoders (weekly CI).
- **`cargo xtask codegen --check`** fails CI if the committed `src/gen/` drifts
from what the emitter + `clusters.json` produce.
## Cryptographic posture
`matter-clusters` performs no cryptography. It is pure data encoding.
## MSRV
Rust 1.88 (workspace MSRV). See the workspace `CHANGELOG.md`.
## License
Apache 2.0. See `LICENSE` at the workspace root.