Ohara Lab

デバイスサーバー開発ガイド

トップページへ戻る / 設計方針 / システム構成

開発記事の案内

  ese774 Frame gRPC Frame
最小構成 Quick Start Quick Start
実装手順 開発ガイド 詳細ガイド
実装例 Router・Clientの例 ストリーミング等の実装例

API公開方式は動的ディスパッチと明示的API、クライアント登録はDeviceProxyとFactory、導入・配布はインストールマニュアルを参照する。

このマニュアルの対象

このページは 新しい DeviceClass を実装し、必要に応じて通信 Frame で公開する開発者のための入口である。利用者向けのパッケージ導入、依存関係、同梱起動スクリプトの配置は、独立したインストールマニュアルにまとめてある。ここでは繰り返さない。

スサノオの基本単位は、通信方式を知らない通常の Python クラスである DeviceClass である。ローカル利用にデバイスサーバーは不要。ネットワーク利用が必要になったときだけ Frame を付加する。Frame を導入するために DeviceClass の制御 API を書き直さない。

ローカル:       利用プログラム ── DeviceClass ── 機器
ネットワーク:   利用プログラム ── Client / DeviceProxy ── 通信 ── Frame / Server ── DeviceClass ── 機器

最初に作るデバイスサーバー:ese774 Frame

  1. 通信FrameをimportしないDeviceClassを実装し、ローカルで動作確認する。
  2. ese774 Frame開発手順の動的ディスパッチを使い、DeviceClassのPython APIをネットワーク越しに公開する。最初からPydanticモデルやApiSpecを二重に定義しない。
  3. 同期・非同期クライアントから動作を確認する。DeviceProxyは必要に応じて登録する。
  4. 通信境界に固有の処理が必要な場合に限りRouterやクライアントを継承・拡張する。機器制御の処理はDeviceClassに残す。
  5. 明示的なHTTP API/OpenAPIが必要な場合はApiSpecとPydanticモデルを採用する。これは動的ディスパッチに代わる選択肢であり、すべての機器の必須作業ではない。

最小動作例はese774 Quick Start、公開方式の詳細は動的ディスパッチと明示的APIを参照する。

gRPC Frameによるデバイスサーバー

gRPC Quick Startでサーバーとクライアントの基本的な接続を確認する。通常RPC、ストリーミング、イベント購読の実装はgRPC Frame開発ガイドを参照する。DeviceClassの制御APIは通信方式に依存しない。

開発の順序と各記事の責務

  1. DeviceClass:機器固有の操作・状態・機器固有のエラー処理を、通信に依存しない Python API として実装し、ローカルで検証する。
  2. 通信方式の選択:要件に応じてese774 Frame、gRPC Frameなどの通信方式を選ぶ。同じ DeviceClass に複数の Frame を付加してもよい。
  3. サーバー側:DeviceClass を Frame に接続する。サーバーで実行すべき通信境界の変換だけを Router やストリーム用オブジェクトに置く。
  4. クライアント側:Frame のクライアントを継承する必要がある場合、戻り値の復元、ローカル保存、複数呼び出しの組合せなど、クライアント側で実行すべき処理を実装する。
  5. 公開と型情報:必要に応じて DeviceProxy の登録・公開窓口、.pyi を整備し、直接利用とネットワーク利用の API の対応を確認する。
  6. 配布・起動:パッケージの依存関係と利用者向けの起動スクリプトについてはインストールマニュアルを参照する。

実装方法の詳細は ese774 Frame 開発手順 と gRPC Frame 開発手順 に分ける。動的ディスパッチと明示的 APIは公開方式の説明、DeviceProxy と Factoryは生成・登録・型情報の説明、ese774 Quick Startは最小動作確認のための記事である。個別機器の操作マニュアルではない。

パッケージの基本構造

以下は UR、COBOTTA、MiniPIX、aandd_reader のソースツリーに共通する責務の配置例であり、すべてのファイルや両 Frame の実装を必須とする規格ではない。

project/
├── pyproject.toml
├── src/
│   └── device_package/
│       ├── __init__.py
│       ├── device_ctrl.py             # DeviceClass(説明用の名前)
│       ├── server_fastapi/            # ese774 Frameを採用する場合
│       │   ├── __init__.py            # 公開窓口・登録
│       │   ├── spec_ctrl.py           # 明示APIを採用する場合
│       │   ├── models/                # Pydanticモデル(必要な場合)
│       │   ├── routers/               # DeviceRouterの派生クラス(必要な場合)
│       │   ├── clients/               # 同期・非同期クライアント
│       │   └── make.py                # .pyi生成(必要な場合)
│       └── server_grpc/               # gRPC Frameを採用する場合
│           ├── __init__.py
│           ├── device_grpc_server.py
│           ├── device_grpc_client.py
│           ├── async_device_grpc_client.py
│           └── make_pyi.py
└── examples/                          # 起動・操作の実行例

device_package や device_ctrl.py は説明用の名前である。build/、*.egg-info/、__pycache__/ は開発用の正本ソースではない。server_fastapi/ と server_grpc/ の内部構成が同じである必要もない。

責務を置く場所の判断

処理 主な責務の場所 判断基準
機器との接続、測定、移動、機器状態 DeviceClass ローカル呼び出しでも同じ意味を持つ
機器固有のエラー判定・復旧 DeviceClass または機器サポート層 HTTP/gRPCを前提にしない
要求・応答の変換、通信境界のエラー伝達 Frame / サーバー側アダプタ 通信によって初めて必要になる
サーバー側で取得したファイル内容の返却 DeviceClass と必要に応じた Router サーバー側の処理と転送可能なデータを区別する
クライアントPCへのファイル保存 クライアント側 サーバーのパスをクライアントのパスと取り違えない
クライアントの公開メソッドの補正・複合操作 クライアント派生クラス DeviceClassの通信非依存性を保つ
API登録・型ヒント パッケージの通信別サブパッケージ .pyi は実行処理ではなく型情報

透過型プロキシは通信境界が存在しないという意味ではない。実行場所、シリアライズ可能な型、例外、タイムアウト、イベント、並行実行、ファイルの副作用は確認する。内部の転送メソッド名を利用者向け API として固定しない。

Frame ごとの開発上の違い

観点 ese774 Frame gRPC Frame
サーバー構築 FastApiServer に DeviceClass のクラス等を渡す実装例 create_grpc_server(ctrl_obj=...) に生成済みインスタンスを渡す実装例
公開方式 自動ディスパッチ(api_spec=None)または Pydantic / ApiSpec による明示的 API Describe / Call に基づく自動ディスパッチ
サーバー側拡張 DeviceRouter 派生クラスなど 必要に応じてストリーム用オブジェクトなど
クライアント側拡張 SyncDeviceClient / AsyncDeviceClient GrpcClient / AsyncGrpcClient
参照する開発手順 ese774 Frame gRPC Frame

実装時の確認事項

参照した実装

ese774_dummy、UR、COBOTTA、MiniPIX、aandd_reader。これらは Framework の使用例であり、装置別記事をトップメニューに増やすためのものではない。

旧版は保存資料を参照する。