Chapter 07
データモデルの構造 — 機器を「属性の集まり」で表す
この章がなぜ必要なのか——ここが Matter の相互運用性の本体だから.
「A 社の電球が B 社のアプリで動く」を成立させているのは、暗号でもネットワークでもない。 「電球とは何か」を全社が同じ形で表現していることである。
Matter のデータモデルは、Zigbee Cluster Library (ZCL) から受け継いだ設計を 整理・拡張したものである。慣れれば非常に見通しがよい。 ここを曖昧にしたまま実装に入ると、後で作り直しになる。
この章で使う既出の用語(定義は各リンク先). Matter(01 章 3 節)、ネットワーク(01 章 3 節)、相互運用性(01 章 2 節)、ACL(02 章 4 節)、Attribute(02 章 2 節)、Client(02 章 5 節)、Cluster(02 章 2 節)、Command(02 章 2 節)、Endpoint(02 章 2 節)、Event(02 章 2 節)、Node(02 章 2 節)、Report(02 章 6 節)、Server(02 章 5 節)、データモデル(02 章 1 節)、必要(05 章 5 節)、Group(06 章 4 節)
1. 階層をもう一度
Node(1 台の機器)
└── Endpoint(機能単位。0 番は Root Node)
└── Cluster(機能のまとまり。Server / Client の別がある)
├── Attribute(状態)
├── Command(動作の要求)
└── Event(起きたことの記録)各要素の ID はその 1 つ上の文脈の中で意味を持つ。 「Attribute 0x0000」だけでは何も決まらない。 「Endpoint 1 / Cluster 0x0006 / Attribute 0x0000」で初めて「その電球の ON/OFF 状態」になる。
2. Attribute(属性)
性質
| 性質 | 内容 |
|---|---|
| 型 | bool, uint8, int16, string, struct, list, … |
| アクセス | 読み取り専用 / 読み書き |
| 権限 | 読み・書きそれぞれに必要な特権(View / Operate / Manage / Administer) |
| Nullable | null を取りうるか |
| 変更通知 | 変わったら購読者に Report される(10 章) |
| 永続性 | 電源断で保持するか |
グローバル属性
すべてのクラスタが必ず持つ属性がある。これが自己記述性を支えている。
| ID | 名前 | 内容 |
|---|---|---|
0xFFFD | ClusterRevision | クラスタ仕様のリビジョン |
0xFFFC | FeatureMap | 実装している機能のビットマップ |
0xFFFB | AttributeList | このクラスタが持つ属性 ID の一覧 |
0xFFF9 | AcceptedCommandList | 受け付けるコマンド ID の一覧 |
0xFFF8 | GeneratedCommandList | 生成する(応答)コマンド ID の一覧 |
0xFFFA | EventList | イベント ID の一覧(仕様バージョンにより扱いが異なる) |
FeatureMapが「オプション機能」を表現する鍵である.例えば Color Control クラスタには、色相/彩度で色を指定する方式(HS)、 XY 座標方式(XY)、色温度方式(CT)がある。 すべての電球がすべてに対応するわけではない。
FeatureMapのビットを見れば、その機器が何をサポートしているかが分かる。 コントローラはこれを読んで UI を出し分ける。実装側の鉄則: FeatureMap で「対応している」と宣言した機能は、必ず全部動かすこと。 中途半端な宣言は、認証テストで確実に落ちる(22 章)。
属性 ID の空間
| 範囲 | 意味 |
|---|---|
0x0000〜0x4FFF | 標準属性(仕様定義) |
0x5000〜0xFFF7 | 予約 |
0xFFF8〜0xFFFF | グローバル属性 |
| 上位 16 bit にベンダー ID | メーカー独自属性 |
3. Command(コマンド)
動作を起こす要求。属性の書き込みでは表現しにくい操作に使う。
| 例 | クラスタ | 内容 |
|---|---|---|
Toggle | On/Off | 現在の状態を反転(書き込みでは表現できない) |
MoveToLevel | Level Control | 指定時間をかけて明るさを変える |
Identify | Identify | 「どれ?」を知らせるために点滅する |
LockDoor | Door Lock | 施錠(PIN 付きなど、引数がある) |
属性書き込みとコマンドの使い分け
「状態を設定する」なら属性書き込み。「動作をさせる」ならコマンド。
- 電球を点ける →
Onコマンド(OnOff属性は読み取り専用)- 明るさを 3 秒かけて変える →
MoveToLevelコマンド(時間という引数がある)- 機器の表示名を変える →
NodeLabel属性への書き込みクラスタ仕様がどちらにするかを決めているので、実装者が選ぶ余地は基本的にない。 「なぜ OnOff 属性は書けないのか」と思ったら、コマンドを使う設計だからである。
応答
コマンドには応答があるものとないものがある。
| 種類 | 例 |
|---|---|
| ステータスのみ | On, Off, Toggle |
| 応答コマンドあり | AttestationRequest → AttestationResponse |
4. Event(イベント)
過去に起きた出来事の記録。属性が「今の状態」なのに対し、イベントは「履歴」である。
| 性質 | 内容 |
|---|---|
| 単調増加の Event Number | 順序が保証される |
| タイムスタンプ | いつ起きたか |
| Priority | Critical / Info / Debug |
| 保存 | 機器がバッファに保持し、購読者に配信 |
| 例 | 内容 |
|---|---|
StateChange(Switch) | ボタンが押された |
DoorLockAlarm | ジャム、こじ開け検知 |
LockOperation | 誰がいつ施錠/解錠したか |
StartUp / ShutDown | 起動・停止 |
属性では取りこぼす情報がある. ボタンを 2 回素早く押したとき、属性の値を見ているだけでは 1 回に見えるかもしれない。 イベントなら両方が記録され、順序も保たれる。
Critical 優先度のイベントは失われてはならない(施錠履歴、警報など)ので、 機器はバッファを確保し、配信されるまで保持する必要がある。 バッファ設計はメモリ制約と直結する(17 章)。
5. Descriptor クラスタ — 自己記述の要
Descriptor (0x001D) はすべての Endpoint に必須である。
| 属性 | 内容 |
|---|---|
DeviceTypeList | この Endpoint のデバイスタイプとリビジョン |
ServerList | Server として実装しているクラスタ ID の一覧 |
ClientList | Client として実装しているクラスタ ID の一覧 |
PartsList | この Endpoint が含む子 Endpoint の一覧 |
TagList | 意味付けのタグ(1.3 以降、複数の同種 Endpoint の区別に使う) |
これがあるから、コントローラは事前知識なしに機器を理解できる.
- Endpoint 0 の
PartsListを読む → Endpoint 1, 2, 3 があると分かる- 各 Endpoint の
DeviceTypeListを読む → 「Dimmable Light」と分かるServerListを読む → On/Off と Level Control があると分かる- 各クラスタの
FeatureMapとAttributeListを読む → 何ができるか確定この一連の読み出しを「サブスクリプション付きのワイルドカード読み出し」で 一気にやるのがコントローラの定石である(09 章)。
ただし Thread 機器では応答が巨大になり失敗しやすい。分割して読むなどの配慮が要る(03 章)。
TagList が解決する問題
3 口の電源タップで、Endpoint 1・2・3 はどれも同じ On/Off Plug-in Unit である。 どれが「左」でどれが「右」なのかを機械可読な形で示す手段がなかった。
TagList に「Left」「Middle」「Right」といった標準名前空間のタグを付けることで、 コントローラが意味のあるラベルを表示できるようになった。
6. データ型
基本型
| 分類 | 型 |
|---|---|
| 論理 | bool |
| 符号なし整数 | uint8, uint16, uint24, uint32, uint64 |
| 符号付き整数 | int8 … int64 |
| 浮動小数点 | single, double |
| 文字列 | string(UTF-8), octstr(バイト列) |
| 列挙 | enum8, enum16 |
| ビットマップ | map8, map16, map32, map64 |
| 複合 | struct, list[T] |
| null | Nullable 型では特定の値が null を意味する |
派生型
| 型 | 内容 |
|---|---|
percent | 0〜100 |
percent100ths | 0〜10000(0.01% 単位) |
temperature | 0.01 °C 単位の int16 |
epoch-us / epoch-s | 2000-01-01 からの経過時間 |
node-id, fabric-idx, endpoint-no, cluster-id | 各種 ID |
単位に注意. 温度は 0.01 °C 単位である。25.5 °C は
2550と表現される。 明るさ(CurrentLevel)は 0〜254(255 ではない)。 色温度はミレッド(= 1,000,000 / ケルビン)。単位の取り違えは、実装で最も頻繁に起きるバグの 1 つである。 Application Cluster Specification の型欄を必ず確認すること。
Nullable
Nullable な型では、取りうる範囲の端の値が null に予約される。
例えば Nullable な int16 では -32768 が null を意味し、有効範囲は -32767〜32767 になる。
「センサーが値を読めていない」を表現するために null が要る. 温度センサーが故障中に
0を返すと「0 °C」と誤解される。 null を返せば「値が無い」と明確に伝わる。 コントローラ側も null を正しく扱う必要がある(UI に「--」と出すなど)。
7. Fabric スコープと Fabric センシティブ
マルチアドミンの帰結として、「見る Fabric によって値が違う」属性がある。
| 概念 | 内容 |
|---|---|
| Fabric-Scoped | リストの各要素が特定の Fabric に属する。読むと自分の Fabric の分だけ見える |
| Fabric-Sensitive | struct の中の特定のフィールドが、他 Fabric からは見えない |
| 例 | 内容 |
|---|---|
AccessControl.ACL | Fabric-Scoped。自分の Fabric の ACL しか見えない |
Binding | Fabric-Scoped |
GroupKeyManagement の各種 | Fabric-Scoped |
これは「他のエコシステムの設定を覗けない」ようにするための仕組みである. Apple Home が Google Home のアクセス制御設定を読めてしまうと、プライバシー上の問題になる。
実装上の注意: Fabric-Scoped なリストへの書き込みは、 「自分の Fabric の要素だけを置き換える」という特殊な意味を持つ。 単純なリスト書き込みとして実装すると、他 Fabric の設定を消してしまう。 SDK は対応しているが、独自実装では要注意である。
8. Binding — 機器どうしの直接連携
Binding クラスタ (0x001E) は、 「このスイッチはあの電球を制御する」という関係を機器自身に持たせる仕組みである。
[スイッチ] Binding: { Node=0x42, Endpoint=1, Cluster=OnOff }
│
└── ボタンが押されたら、自分で電球に On コマンドを送る| 効果 | 内容 |
|---|---|
| ハブを経由しない | スイッチ → 電球へ直接。レイテンシが最小 |
| ハブが落ちても動く | 物理スイッチとしての信頼性 |
| 設定はコントローラが行う | Binding 属性への書き込み |
これが「壁スイッチ」を Matter で作るときの正解である. ハブ経由だと、ハブの再起動中にスイッチが効かない。 Binding とグループ通信を使えば、スイッチと電球だけで完結する。
実装には Client 側クラスタ(この場合 On/Off Client)が必要である。 「Server だけ実装すればよい」と思い込まないこと(02 章)。
9. 設計の指針
標準クラスタで表現できないか、徹底的に検討すること.
独自クラスタ・独自属性は、他社エコシステムからは完全に無視される。 「Matter 対応」と謳いながら、主要機能が自社アプリでしか使えない、という状態になる。
検討の順序:
- 既存の標準クラスタで表現できないか
- 複数のクラスタの組み合わせで表現できないか
- Endpoint を分けることで表現できないか
- どうしても無理なら → CSA に提案する(仕様は拡張され続けている)
- 当面の措置として独自クラスタ(ただし基本機能は必ず標準クラスタでも提供する)
Endpoint を分ける判断. 「独立に制御できるものは、別の Endpoint にする」が原則である。 3 口タップの各口、複数のセンサーを内蔵した機器の各センサー、 温度と湿度の両方を測るセンサー——これらは別 Endpoint にする。
逆に、1 つの機能の異なる側面(電球の ON/OFF と明るさ)は、 同じ Endpoint の異なるクラスタにする。
10. まとめ
| 要素 | 一言で |
|---|---|
| Endpoint | 独立に制御できる機能単位。0 番は Root Node |
| Cluster | Attribute + Command + Event のまとまり。Server / Client の別あり |
| Attribute | 状態。グローバル属性(FeatureMap 等)で自己記述する |
| Command | 動作の要求。属性書き込みで表せないものに使う |
| Event | 履歴。取りこぼしてはいけない情報に使う |
| Descriptor | 各 Endpoint の目次。これがあるから事前知識なしに理解できる |
| Binding | 機器どうしの直接連携。ハブなしで動く |
- FeatureMap で宣言した機能は必ず全部動かす。認証で落ちる。
- 単位に注意(温度は 0.01 °C、明るさは 0〜254、色温度はミレッド)。
- Fabric-Scoped / Fabric-Sensitive はマルチアドミンのプライバシーの仕組み。
- 独自クラスタは相互運用性を捨てることになる。最後の手段。