デバイスへの接続には成功しても、アプリケーションから安定して利用できないことがあります。不足している情報は、多くの場合コマンド表の外にあります。たとえば、リクエストが許可されるタイミング、レスポンスの照合方法、タイムアウトの意味、ファームウェア更新後に変わる動作などです。このガイドでは、ファームウェア、アプリケーション、バックエンドの各チームが同じ契約を実装できるように、デバイスプロトコル仕様書に含めるべき内容を説明します。
デバイスプロトコル仕様書とは?
デバイスプロトコル仕様書は、デバイスと、それと通信するソフトウェアとの間の実装契約です。
通信の確立方法、リクエストのエンコード方法、レスポンスの解釈方法、問題発生時の復旧方法を定義します。また、各操作によってデバイス上の何が変わるのか、その変更がいつ有効になるのか、アプリケーションがそれをどのように確認できるのかも説明します。
コマンド表は、この契約の一部にすぎません。
たとえば、「測定を開始するには0x21を送信する」という記載だけでは、重要な疑問が未解決のままです。
- どのデバイス状態でコマンドが許可されるのか?
- レスポンスは受理を確認するものか、それとも完了を確認するものか?
- 測定には最長でどのくらいかかるのか?
- タイムアウト後にアプリケーションは再試行できるのか?
- 結果はレスポンスとして届くのか、それとも非要求イベントとして届くのか?
有用な仕様書は、開発者がデモアプリケーションから動作を推測しなくても、これらの疑問に答えられるものです。
範囲、所有者、対応バージョンを定義する
まず、文書が何を記述するものなのかを正確に特定します。
デバイスファミリー、ハードウェアリビジョン、ファームウェアバージョン、プロトコルバージョン、文書リビジョンを含めます。仕様書の保守と実装上の質問への対応を担当するチームを明記します。
ファームウェアバージョンとプロトコルバージョンは分けて管理してください。ファームウェアリリースでは通信契約を変更せずに内部動作を修正する場合がある一方、プロトコルの変更は複数のファームウェアリリースに影響する場合があります。
文書には、その対象範囲の境界も明記する必要があります。例:
「本仕様書は、モバイルアプリケーションとコントローラー間の通信を対象とします。コントローラー内部のセンサーバスまたはクラウドAPIは定義しません。」
未解決の動作ごとに、担当者と決定期限を記録します。「要確認」は文書化されていない前提より有用ですが、依存する統合作業が始まる時点まで未解決のままにしてはいけません。
トランスポートと接続手順を説明する
個々のコマンドを説明する前に、アプリケーションがデバイスに到達する方法を説明します。
必要な情報はインターフェースによって異なります。
BLE GATT
検出識別子、サービスおよびキャラクタリスティックのUUID、キャラクタリスティックのプロパティ、セキュリティ要件、通知またはインディケーションの設定、ペイロード制限を文書化します。
UUIDの一覧だけでは不十分です。どのキャラクタリスティックがコマンドを伝送し、どれが結果を伝送するのか、また通信開始前にどのような初期化が必要なのかを仕様書で説明する必要があります。
GATTは、サービス、キャラクタリスティック、ディスクリプター、および読み取り、書き込み、通知、インディケーションなどの手順を定義します。デバイス固有の文書では、それらの仕組みによって製品ワークフローをどのように実装するかを説明する必要があります。
Bluetooth SIG Bluetooth LE Primer(https://www.bluetooth.com/bluetooth-le-primer/)は、基礎となる用語を提供しています。
UARTまたはシリアル
電気的インターフェース、コネクタのピン配置、電圧レベル、ボーレート、データビット、パリティ、ストップビット、フロー制御を文書化します。
物理インターフェースとメッセージ形式を区別してください。シリアル設定が一致していても、2つの実装がパケット境界やコマンドの意味について合意しているとは限りません。
TCP
接続開始側、アドレス検出、ポート、暗号化要件、メッセージフレーミング、再接続時の動作を文書化します。
受信側がバイトストリームからメッセージを再構築する方法を説明します。1回の読み取り操作で完全なアプリケーションメッセージが1つ返されると想定してはいけません。
UDP
エンドポイント、データグラムの制限、検出動作、およびパケットの損失、重複、順序入れ替わりに関するアプリケーションルールを文書化します。
アプリケーションに確認応答が必要かどうか、および繰り返されたリクエストをどのように識別するかを明記します。
MQTT
ブローカー接続要件、トピック構造、QoS、保持ポリシー、セッション動作、コマンドとレスポンスの対応付けを文書化します。
デバイスIDとトピックの関係、およびアプリケーションがメッセージ配信とデバイス実行をどのように区別するかを説明します。
接続開始シーケンス
製品に適した番号付きの開始シーケンスを含めます。
- 対象のデバイスを検出する。
- 接続と必要なセキュリティを確立する。
- 利用可能なインターフェースを検出する。
- 結果通知またはサブスクリプションを有効にする。
- プロトコルバージョンと機能を読み取る。
- 現在のデバイス状態を読み取る。
- アプリケーションコマンドを開始する。
いずれかの手順が失敗した場合に何が起こるか、および安全に繰り返せるかどうかを定義します。
メッセージ境界とフィールドエンコーディングを規定する
受信側は、各メッセージの開始位置と終了位置を正確に把握できなければなりません。
カスタムバイナリプロトコルでは、以下を文書化します。
- ヘッダーまたは同期バイト。
- 長さフィールドのサイズと、その長さに含まれる範囲。
- メッセージタイプとリクエスト識別子。
- ペイロードのレイアウトと最大サイズ。
- 使用する場合は、チェックサムまたはCRC。
- エスケープ、パディング、フラグメンテーションのルール。
- 不正な入力後の復旧動作。
フレーミングルールでは、不完全な入力や複数のメッセージをまとめて受信した場合の処理方法を説明する必要があります。
各フィールドについて、オフセット、幅、型、バイトオーダー、許容値、意味を定義します。該当する場合は、単位、スケーリング、符号の有無、無効値マーカーも含めます。
例:温度フィールド
以下はフィールド定義の例であり、標準的なデバイス形式ではありません。
- フィールド名:temperature。
- 型:2の補数を使用する符号付き16ビット整数。
- バイトオーダー:リトルエンディアン。
- 単位:摂氏0.01度。
- バイト例:29 09。
- デコード後の整数:2345。
- 表示値:摂氏23.45度。
- 無効マーカー:00 80。有効な測定値がないことを意味します。
「2バイトの温度データ」だけでは、同じ値を一貫してデコードするための情報として不十分です。
チェックサムとCRCの定義
CRCを使用する場合は、以下を指定します。
- 多項式。
- 初期値。
- 入力および出力の反転設定。
- 最終XOR値。
- 対象となるバイト範囲。
- 送信時のバイトオーダー。
- 検証済みのテストベクトル。
「CRC-16」という名称だけでは、互換性のない実装が生じる余地があります。
既存の標準プロトコルについては、正確な仕様を参照し、デバイス固有のマッピングと拡張を文書化します。たとえば、Modbus Organizationの仕様(https://www.modbus.org/modbus-specifications),は基本契約を提供しますが、個々の製品については、対応する機能とレジスターの意味を別途文書化する必要があります。
すべてのコマンドを動作契約として定義する
各コマンドには、識別子とペイロード例だけでなく、完全な項目が必要です。
以下の情報を文書化します。
- 識別子と名前: 受信側が操作を認識する方法。
- 目的: 操作が行うこと。
- 事前条件: 必要なデバイス状態、権限、設定。
- リクエスト: フィールド定義と検証ルール。
- レスポンス: レスポンスフィールドとその意味。
- 完了の証拠: 要求された結果を証明するもの。
- タイミング: 受理と完了に関する想定。
- 副作用: ハードウェア、保存済み設定、またはその他の操作への変更。
- 再試行ルール: リクエストを繰り返しても安全かどうか。
- エラー: 拒否および実行失敗の条件。
例:SET_REPORT_INTERVAL
以下の例は、必要な詳細レベルを示すものです。その動作は参照設計であり、特定の製品の仕様ではありません。
目的
定期的なテレメトリレポートに使用する間隔を変更します。
リクエストフィールド
- requestId:アプリケーションのリクエスト識別子。
- intervalSeconds:1から3600までの整数。
事前条件
セッションが認証済みであり、デバイスがファームウェア更新中でないこと。
受理
デバイスはリクエストを検証し、処理対象として確保します。
完了
デバイスは間隔を永続化し、読み戻して検証します。
結果
レスポンスにはrequestIdと有効なintervalSecondsが含まれます。
有効化
コマンドが成功すると、次のレポート間隔が開始されます。
永続性
設定は再起動後も保持されます。
重複処理
文書化された重複排除期間中、同じrequestIdとペイロードに対しては、既存のステータスまたは結果が返されます。
競合処理
同じrequestIdでペイロードが異なる場合は拒否されます。
エラー
- INVALID_ARGUMENT。
- BUSY。
- UNAUTHORIZED。
- STORAGE_FAILURE。
実際の仕様書では、実製品の識別子形式、重複排除期間、タイミング制限、エラーエンコーディングも定義する必要があります。
メッセージ受信と実行成功を分ける
低レベルのレスポンスは、データが通信コンポーネントに到達したことを確認するだけで、要求された操作の完了を証明しない場合があります。
アプリケーションが確認できる確認応答の段階を定義します。
- 受信済み: メッセージがアプリケーションハンドラーに到達した。
- 受理済み: 検証に合格し、実行がスケジュールされた。
- 完了済み: 文書化された成功条件を満たした。
- 拒否済み: リクエストが実行対象として受理されなかった。
- 失敗: 実行は試みられたが、完了条件を満たさなかった。
すべてのコマンドにすべての段階が必要なわけではありません。単純な読み取りでは結果を即座に返せますが、キャリブレーションでは受理レスポンスの後に完了イベントが必要になる場合があります。
各レスポンスを元のリクエストと照合する方法を文書化します。非要求イベントが同じチャネルを使用するかどうか、およびクライアントがそれらをどのように区別するかを指定します。
証拠の限界も定義してください。出力レジスターの読み戻しはレジスター値を確認するものですが、接続された機構が動いたことを必ずしも証明するものではありません。
アプリケーションには、プロトコルが実際に立証できる最も確かな結果を表示する必要があります。
デバイス状態、並行処理、タイミングを文書化する
同じコマンドでも、アイドル中は有効で、キャリブレーション中やファームウェア更新中は無効になる場合があります。
外部から見て重要なデバイス状態と、各状態で許可される操作を一覧にします。コマンド、物理入力、エラー、再起動によって生じる遷移を説明します。
並行処理ルール
以下の質問に明確に答えてください。
- 複数のリクエストを未完了のまま同時に保持できるか?
- コマンドは順番どおりに実行されるか?
- 長時間実行される操作中に読み取りを行えるか?
- デバイスは競合するコマンドをキューに入れるのか、それとも拒否するのか?
- 権限を持つ2つのクライアントが競合するリクエストを発行した場合、どうなるのか?
リソース制限が重要な場合は、最大キュー深度またはリクエストレートを含めます。
タイミングとタイムアウトのルール
受理タイムアウトと完了タイムアウトを別々に指定します。
受理タイムアウトは、デバイスがリクエストを受理または拒否するまで呼び出し側が待つ時間を示します。完了タイムアウトは、受理後に操作にかかり得る時間を示します。
タイムアウトは、呼び出し側が把握していることを示す必要があります。レスポンスが失われる前にデバイスがコマンドを実行していた可能性がある場合、結果は不確実です。
再試行を推奨する前に、仕様書でステータス照会、整合手順、またはその他の復旧経路を提供する必要があります。
エラーと復旧動作を定義する
無効なリクエスト、一時的な動作条件、ハードウェア障害を区別する、一貫したエラーモデルを作成します。
各エラーについて、以下を文書化します。
- 安定した機械可読コード。
- エラーが発生する条件。
- 実行が開始されたかどうか。
- 部分的な影響が生じる可能性があるかどうか。
- 推奨される次の対応。
たとえば、INVALID_ARGUMENTでは通常、リクエストの修正が必要です。BUSYでは、定義されたポリシーに従って後で再試行できる場合があります。STORAGE_FAILUREでは、繰り返し再試行するのではなく、点検が必要になる場合があります。
切断と再起動
切断および再起動後に何が起こるかを説明します。
どの設定が保持されるか、どの保留中コマンドが維持されるか、以前の結果を引き続き利用できるかを明記します。
デバイスが操作を実行した後、結果を記録する前に再起動する可能性がある場合、システムがその不確実性をどのように解消するかを説明します。コマンドの繰り返しは、構成設定では無害でも、払い出しやその他の物理的動作では許容できない場合があります。
不正なメッセージ
バイナリストリームでは、無効な長さ、未知のメッセージタイプ、整合性チェックの失敗後にパーサーがどのように復旧するかを指定します。
成立し得ないフレームをパーサーが無期限に待つと、正常なトラフィックまでブロックされる可能性があります。
バッファー制限と、入力を破棄または接続をリセットする条件を定義します。
セキュリティとアクセスルールを含める
誰が接続を許可され、各IDが何を実行できるかを説明します。
該当する場合は、認証、認可、暗号化要件、プロビジョニング、認証情報のローテーション、デバイス所有権の移転を扱います。
トランスポートセキュリティと操作権限を分けてください。接続が暗号化されていても、そのクライアントにデバイスのリセットや構成の置き換えを許可すべきとは限りません。
リプレイ保護が必要なコマンドについては、鮮度を保証する仕組みと、再起動またはクロック喪失後の動作を定義します。
リクエスト識別子は照合に役立ちますが、それだけでリクエストが真正または最新であることの証明にはなりません。
実際の本番用認証情報を仕様書に記載しないでください。プレースホルダーを使用し、権限を持つチームが必要な構成を取得する方法を説明します。
ファームウェアとプロトコルの変更に備える
クライアントが使用前に対応動作を検出する方法を説明します。
ハードウェア、ファームウェア、プロトコルの各バージョンを関連付ける互換性マトリックスを含めます。機能が任意の場合は、アプリケーションに製品名から対応状況を推測させるのではなく、機能検出を提供します。
実装が以下をどのように処理するかを文書化します。
- 未知のコマンド識別子。
- 未対応の列挙値。
- 追加の任意フィールド。
- 必須フィールドの欠落。
- 非推奨の操作。
未知の値によって、別の物理的動作が暗黙に実行されてはいけません。
プロトコルの変更ごとに、影響を受けるフィールド、動作の違い、互換性への影響、移行ガイダンスを記録します。
以前のファームウェアで稼働し続けるデバイスのために、古い仕様書も利用可能な状態にしておきます。
テストにできる例を提供する
成功するリクエストとレスポンスだけでなく、ほかの例も含めます。
以下のフィクスチャを提供します。
- 有効値の最小値と最大値。
- 無効な入力。
- 未対応のコマンド。
- 途中で切れたフレーム。
- 重複リクエスト。
- 中断された操作。
- 遅延または欠落したレスポンス。
各フィクスチャでは、プロトコルバージョン、正確な入力、期待されるデコード値、期待されるレスポンス、期待されるデバイス動作を特定する必要があります。
バイナリプロトコルでは、デコードした解釈とともに生の16進数メッセージを含めます。
ストリームトランスポートでは、同じメッセージを複数回の読み取りに分割した場合と、複数のメッセージを1回の読み取りにまとめた場合をテストします。
デバイスとファームウェアのコンテキストが明確な場合、キャプチャしたトラフィックは有用です。機密性の高い識別子と認証情報を削除し、観測された動作と仕様書で保証された動作を区別してください。
シミュレーターがあれば、チームはハードウェアに常時アクセスせずに開発できますが、タイミング、永続性、物理的な結果を検証するには、実機テストも必要です。
このプロトコル引き継ぎチェックリストを使用する
インターフェースを別のチームに引き渡す前に、パッケージに以下が含まれていることを確認します。
- 文書の所有者、改訂履歴、対応バージョン。
- 接続設定と初期化シーケンス。
- メッセージフレーミングと完全なフィールド定義。
- コマンドのリクエスト、レスポンス、完了条件。
- デバイス状態と並行処理ルール。
- タイミング、再試行、有効期限、重複処理のルール。
- エラーコードと復旧手順。
- 認証と操作権限。
- 互換性と機能検出のルール。
- 検証済みの例、テストフィクスチャ、既知の制限。
ファームウェアを設計していないエンジニアに、文書だけを使用して、読み取りコマンドを1つ、状態を変更するコマンドを1つ、障害復旧経路を1つ実装してもらいます。
その際に必要となる確認事項はすべて、解消すべき不備を示しています。
よくある質問
プロトコル仕様書がなくても、ベンダーのSDKだけで十分ですか?
SDKは統合を簡素化できますが、そのAPIによってトランスポート動作、再試行ポリシー、デバイスの制限が隠される場合があります。
対応するワークフロー、エラー、スレッドモデル、バージョン互換性、診断機能に関する文書を入手してください。
障害を調査する場合や、SDKが対応していないプラットフォームをサポートする場合は、基盤となるプロトコルへのアクセスが特に有用です。
パケットキャプチャで不足している文書を代替できますか?
パケットキャプチャから、メッセージ構造や観測された動作を把握できます。しかし、すべての有効値、未対応状態、タイミング保証、ファームウェアの違いを確定することはできません。
完全な仕様書としてではなく、デバイスチームと検証するための証拠として扱ってください。
アプリチームとファームウェアチームは別々の仕様書を管理すべきですか?
所有者が明確な、信頼できる唯一の通信契約を使用してください。
各チームが実装メモを管理することはできますが、コマンドの意味やワイヤー形式が別々の文書間で食い違ってはいけません。
時間が限られている場合、最初に何を文書化すべきですか?
接続設定、フレーミング、重要なコマンド、完了の証拠、障害復旧から始めます。
未検証の動作を明示し、テストを妨げる不備や、意図しないデバイス動作を引き起こす可能性のある不備を優先してください。
プロトコルメモを実装可能なインターフェースに変える
有用なプロトコル仕様書があれば、異なるチームが互換性のある実装を作成し、共有された証拠に基づいて障害を診断できます。
現在、インターフェースに関する情報がスプレッドシート、SDKサンプル、パケットキャプチャ、ファームウェアのコメントに分散している場合、YUNJIのDevice Protocol Integrationサービス(https://yunji-node.com/solutions/device-protocol-integration)は、それらの資料を文書化および検証された通信レイヤーとして整理するのに役立ちます。
統合レビューに向けて、現在のプロトコルメモ、代表的なハードウェア、ファームウェアバージョン、サンプルトラフィック、安定して動作する必要があるアプリケーションワークフローを準備してください。



