Matter 07 · データモデルの構造 — 機器を「属性の集まり」で表す

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)
Nullablenull を取りうるか
変更通知変わったら購読者に Report される(10 章)
永続性電源断で保持するか

グローバル属性

すべてのクラスタが必ず持つ属性がある。これが自己記述性を支えている。

ID名前内容
0xFFFDClusterRevisionクラスタ仕様のリビジョン
0xFFFCFeatureMap実装している機能のビットマップ
0xFFFBAttributeListこのクラスタが持つ属性 ID の一覧
0xFFF9AcceptedCommandList受け付けるコマンド ID の一覧
0xFFF8GeneratedCommandList生成する(応答)コマンド ID の一覧
0xFFFAEventListイベント ID の一覧(仕様バージョンにより扱いが異なる)

FeatureMap が「オプション機能」を表現する鍵である.

例えば Color Control クラスタには、色相/彩度で色を指定する方式(HS)、 XY 座標方式(XY)、色温度方式(CT)がある。 すべての電球がすべてに対応するわけではない。

FeatureMap のビットを見れば、その機器が何をサポートしているかが分かる。 コントローラはこれを読んで UI を出し分ける。

実装側の鉄則: FeatureMap で「対応している」と宣言した機能は、必ず全部動かすこと。 中途半端な宣言は、認証テストで確実に落ちる(22 章)。

属性 ID の空間

範囲意味
0x0000〜0x4FFF標準属性(仕様定義)
0x5000〜0xFFF7予約
0xFFF8〜0xFFFFグローバル属性
上位 16 bit にベンダー IDメーカー独自属性

3. Command(コマンド)

動作を起こす要求。属性の書き込みでは表現しにくい操作に使う。

例クラスタ内容
ToggleOn/Off現在の状態を反転(書き込みでは表現できない)
MoveToLevelLevel Control指定時間をかけて明るさを変える
IdentifyIdentify「どれ?」を知らせるために点滅する
LockDoorDoor Lock施錠(PIN 付きなど、引数がある)

属性書き込みとコマンドの使い分け

「状態を設定する」なら属性書き込み。「動作をさせる」ならコマンド。

クラスタ仕様がどちらにするかを決めているので、実装者が選ぶ余地は基本的にない。 「なぜ OnOff 属性は書けないのか」と思ったら、コマンドを使う設計だからである。

応答

コマンドには応答があるものとないものがある。

種類例
ステータスのみOn, Off, Toggle
応答コマンドありAttestationRequest → AttestationResponse

4. Event(イベント)

過去に起きた出来事の記録。属性が「今の状態」なのに対し、イベントは「履歴」である。

性質内容
単調増加の Event Number順序が保証される
タイムスタンプいつ起きたか
PriorityCritical / Info / Debug
保存機器がバッファに保持し、購読者に配信
例内容
StateChange(Switch)ボタンが押された
DoorLockAlarmジャム、こじ開け検知
LockOperation誰がいつ施錠/解錠したか
StartUp / ShutDown起動・停止

属性では取りこぼす情報がある. ボタンを 2 回素早く押したとき、属性の値を見ているだけでは 1 回に見えるかもしれない。 イベントなら両方が記録され、順序も保たれる。

Critical 優先度のイベントは失われてはならない(施錠履歴、警報など)ので、 機器はバッファを確保し、配信されるまで保持する必要がある。 バッファ設計はメモリ制約と直結する(17 章)。

5. Descriptor クラスタ — 自己記述の要

Descriptor (0x001D) はすべての Endpoint に必須である。

属性内容
DeviceTypeListこの Endpoint のデバイスタイプとリビジョン
ServerListServer として実装しているクラスタ ID の一覧
ClientListClient として実装しているクラスタ ID の一覧
PartsListこの Endpoint が含む子 Endpoint の一覧
TagList意味付けのタグ(1.3 以降、複数の同種 Endpoint の区別に使う)

これがあるから、コントローラは事前知識なしに機器を理解できる.

  1. Endpoint 0 の PartsList を読む → Endpoint 1, 2, 3 があると分かる
  2. 各 Endpoint の DeviceTypeList を読む → 「Dimmable Light」と分かる
  3. ServerList を読む → On/Off と Level Control があると分かる
  4. 各クラスタの 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]
nullNullable 型では特定の値が null を意味する

派生型

型内容
percent0〜100
percent100ths0〜10000(0.01% 単位)
temperature0.01 °C 単位の int16
epoch-us / epoch-s2000-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-Sensitivestruct の中の特定のフィールドが、他 Fabric からは見えない
例内容
AccessControl.ACLFabric-Scoped。自分の Fabric の ACL しか見えない
BindingFabric-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 対応」と謳いながら、主要機能が自社アプリでしか使えない、という状態になる。

検討の順序:

  1. 既存の標準クラスタで表現できないか
  2. 複数のクラスタの組み合わせで表現できないか
  3. Endpoint を分けることで表現できないか
  4. どうしても無理なら → CSA に提案する(仕様は拡張され続けている)
  5. 当面の措置として独自クラスタ(ただし基本機能は必ず標準クラスタでも提供する)

Endpoint を分ける判断. 「独立に制御できるものは、別の Endpoint にする」が原則である。 3 口タップの各口、複数のセンサーを内蔵した機器の各センサー、 温度と湿度の両方を測るセンサー——これらは別 Endpoint にする。

逆に、1 つの機能の異なる側面(電球の ON/OFF と明るさ)は、 同じ Endpoint の異なるクラスタにする。

10. まとめ

要素一言で
Endpoint独立に制御できる機能単位。0 番は Root Node
ClusterAttribute + Command + Event のまとまり。Server / Client の別あり
Attribute状態。グローバル属性(FeatureMap 等)で自己記述する
Command動作の要求。属性書き込みで表せないものに使う
Event履歴。取りこぼしてはいけない情報に使う
Descriptor各 Endpoint の目次。これがあるから事前知識なしに理解できる
Binding機器どうしの直接連携。ハブなしで動く