matter_clusters/lib.rs
1//! Typed Matter cluster definitions — generated from the Matter spec.
2//!
3//! Per-cluster attribute / command / struct **codecs** (encode/decode to Matter
4//! TLV), feature bitflags, enums (with an `Unknown(n)` variant for
5//! forward-compatibility), and bitmaps. The cluster modules live under
6//! [`gen`]; the hand-written foundation is [`Nullable<T>`](types::Nullable)
7//! (distinct from `Option`), [`ClusterError`](error::ClusterError), and
8//! [`datatypes::SemanticTagStruct`].
9//!
10//! # Pipeline
11//!
12//! The `gen/` modules are generated, not hand-written: a pinned `@matter/model`
13//! dump becomes the committed `xtask/model/clusters.json`, which
14//! `cargo xtask codegen` turns into the committed `src/gen/*.rs`. CI gates drift
15//! with `cargo xtask codegen --check`. **Do not edit `src/gen/` by hand** —
16//! change the emitter in `xtask/src/codegen/` and regenerate.
17//!
18//! Correctness: the generated codecs are checked against matter.js 0.16.11
19//! byte-parity vectors (`test-vectors/clusters/`), with `proptest` roundtrips
20//! and a `cargo-fuzz` target. See [Clusters](#clusters) for what is covered
21//! at which level.
22//!
23//! # Clusters
24//!
25//! 47 clusters are generated today. The full list is [`gen`]; by area:
26//!
27//! - **Core / identity:** `BasicInformation`, `Descriptor`, `Identify`,
28//! `Groups`, `Binding`, `FixedLabel`, `UserLabel`, `PowerSource`,
29//! `GeneralDiagnostics`.
30//! - **Lighting and actuators:** `OnOff`, `LevelControl`, `ColorControl`,
31//! `DoorLock` (Aliro features excluded), `WindowCovering`, `Thermostat`,
32//! `ThermostatUserInterfaceConfiguration`, `FanControl`,
33//! `PumpConfigurationAndControl`.
34//! - **Sensing:** `OccupancySensing`, `TemperatureMeasurement`,
35//! `RelativeHumidityMeasurement`, `IlluminanceMeasurement`,
36//! `PressureMeasurement`, `FlowMeasurement`, `BooleanState`, `Switch`,
37//! `AirQuality`, and the ten `ConcentrationMeasurement` clusters
38//! (`CarbonMonoxide`, `CarbonDioxide`, `NitrogenDioxide`, `Ozone`, `Pm25`,
39//! `Formaldehyde`, `Pm1`, `Pm10`, `TotalVolatileOrganicCompounds`,
40//! `Radon`).
41//! - **Energy:** `ElectricalPowerMeasurement`, `ElectricalEnergyMeasurement`.
42//! - **Administration:** `AccessControl`, `GroupKeyManagement`,
43//! `AdministratorCommissioning`, `OperationalCredentials`,
44//! `IcdManagement`, `TimeSynchronization`, `OtaSoftwareUpdateRequestor`,
45//! `OtaSoftwareUpdateProvider`.
46//!
47//! Note that this crate holds **codecs only**. For the administration
48//! clusters in particular, encoding a command is not the same as running the
49//! protocol around it: ACL evaluation, group multicast, commissioning-window
50//! orchestration, and OTA live in `matter-controller` and its siblings.
51//!
52//! Verification varies by cluster. Every cluster has decode-smoke coverage;
53//! matter.js byte-parity vectors cover the core, lighting, and sensing sets
54//! plus one vector for each novel wire shape the later batches introduced
55//! (nested measurement-accuracy structs, list-typed commands,
56//! struct-with-byte-fields, recursive list-of-struct, and floats).
57//!
58//! For any attribute not covered by these typed codecs — a cluster not in
59//! this list, or a manufacturer-specific attribute — the generic `Value`
60//! path in `matter-controller` remains the universal answer.
61//!
62//! # Usage
63//!
64//! Codecs are free functions per attribute/command. Encoders return a standalone
65//! anonymous-tagged TLV element (ready to embed in an Interaction Model
66//! request); decoders take the attribute value bytes from a report.
67//!
68//! ```
69//! use matter_clusters::gen::{basic_information, on_off};
70//!
71//! // Command payload — embed in an InvokeRequest (see the `control_onoff` example).
72//! let _toggle = on_off::encode_toggle();
73//!
74//! // Attribute roundtrips: encode a value, decode it back.
75//! let tlv = on_off::encode_on_time(30);
76//! assert_eq!(on_off::decode_on_time(&tlv)?, 30);
77//!
78//! let tlv = basic_information::encode_node_label(&"living room".to_string());
79//! assert_eq!(basic_information::decode_node_label(&tlv)?, "living room");
80//! # Ok::<(), matter_clusters::error::ClusterError>(())
81//! ```
82//!
83//! See `crates/matter-commissioning/examples/control_onoff.rs` for an
84//! end-to-end read / toggle / write against a real device.
85//!
86//! # Scope — reading attributes beyond these clusters
87//!
88//! Typed codecs exist for these clusters' **mandatory and optional** attributes
89//! (a device may not implement a given optional attribute — it then returns
90//! `UNSUPPORTED_ATTRIBUTE`). To read attributes of clusters NOT in this set, or
91//! manufacturer-specific attributes, use the generic Interaction Model path:
92//! `matter_interaction::parse_report_data` decodes any attribute to a
93//! `(AttributePath, matter_codec::Value)` pair without a typed codec, and
94//! `matter-controller` wraps that in a generic read/write/subscribe API with
95//! wildcard paths.
96
97#![forbid(unsafe_code)]
98
99pub mod datatypes;
100pub mod error;
101pub mod types;
102
103pub use datatypes::SemanticTagStruct;
104
105pub mod gen;
106
107#[cfg(test)]
108mod golden;
109
110/// Compile-checks the Rust examples in this crate's `README.md`.
111///
112/// `#[cfg(doctest)]` means the item exists only while rustdoc is collecting
113/// doctests, so the README is compiled by `cargo test --doc` without being
114/// duplicated into the rendered crate docs.
115#[cfg(doctest)]
116#[doc = include_str!("../README.md")]
117struct ReadmeDoctests;