コンテンツにスキップ

idryer-coreベースの新しい製品を追加する

このガイドは、idryer-core上で新しい製品(フィラメント乾燥機、加熱ブロック、照明、センサー、その他のモジュール)を作るときに使います。コアが代わりに行うことと、製品コードが追加すべきことを示します。

ビルドできる完全な例は、Build-Your-Own-iDryerドキュメントの加温式保管キャビネット(example/09-cabinet)です。このページの内容をすべて通しています。


製品の土台

製品は1つのオブジェクト — iDryer::Linkファサード(<iDryer.h>)を通じてコアとやり取りします。s_link.begin()とs_link.loop()の中で、コアは次を行います:

  • iDryerアプリから無線(ESPTouch)で、またはWebインストーラーからUSB(Improv)でWi-Fiネットワークを受け取り、接続を維持する;
  • デバイスをアカウントに紐付ける:使い捨てのペアリングトークンを、アプリからローカルネットワーク経由、またはシリアルポート経由(PAIR_TOKEN:<token>)で待ち、ポータルで永続的なシークレットと交換する;
  • MQTTに接続し、Configの周期でtelemetryとstatusを公開する;
  • ローカルネットワークで自分を告知し(mDNS _idryer._tcp)、WebSocketでアプリからのコマンドを受け付ける;
  • デバイスカードのcardマニフェストを公開する。

下位のクラス(IdryerRuntime、CloudStateMachine、LocalAccessなど)はコアの内部です。ペアリングトークンがクラウド部分に届くのはiDryer::Linkの中だけです。製品はファサードの上に作ってください。


1. プロジェクト

idryer-coreはlib/idryer-core/に置きます(コピーまたはシンボリックリンク)。PlatformIOはコアのライブラリをそのlibrary.jsonから取得します。最小限のplatformio.ini:

[env:my-device]
platform    = espressif32
framework   = arduino
board       = esp32-c3-devkitm-1

; espMqttClient の依存に含まれる ESP8266 用トランスポート:ESP32 ではビルドできない
lib_ignore = ESPAsyncTCP

build_flags =
    -DIDRYER_API_BASE='"https://portal.idryer.org/api"'
    -DMQTT_BROKER='"mqtt.idryer.org"'
    -DMQTT_PORT=8883
    -DMQTT_USE_TLS=1

lib_ignore = ESPAsyncTCPがないとビルドはESPAsyncTCP.cppで失敗し、MQTT_BROKERとMQTT_PORTがないとコアはコンパイルできません。


2. 最小限のファームウェア

#include <iDryer.h>

static const iDryer::Config CFG = {
    .deviceType      = iDryer::DeviceType::Unknown,   // iDryer製品ではない:カードはマニフェストから作られる
    .unitsCount      = 1,
    .hasAirTemp      = true,
    .hasAirHumidity  = true,
    .hardwareVersion = "1.0",
    .firmwareVersion = "0.1.0",
    .model           = "My Device",
};
static iDryer::Link s_link(CFG);

void setup() {
    s_link.begin();
    // ポータルで紐付けが解除された:シークレットを消去し、新しいペアリングを待つ
    s_link.onCommand("revoke", [](JsonObjectConst) { s_link.handleRevoke(); });
}

void loop() {
    s_link.loop();
    s_link.telemetry.airTempC[0]       = readTemp();       // あなたのセンサー関数
    s_link.telemetry.airHumidityPct[0] = readHumidity();
}

s_link.begin()がWi-Fi、紐付け、MQTT、ローカルアクセスを開始します。s_link.loop()はdelay()なしで常に回し続ける必要があります。revokeコマンドは、デバイスがアカウントから紐付け解除されたときにポータルから届きます。handleRevoke()がシークレットを消去し、デバイスは新しいペアリングトークンを待ちます。


3. Wi-Fiと紐付け — コードには書かない

ファームウェアにはネットワークのパスワードもアカウント情報も入っていません。ユーザーはiDryerアプリでデバイスを接続します:新しいデバイスを接続 → **Wi-Fi**ステップ(アプリがESPTouchでネットワークを送信)→ **ペアリング**ステップ(アプリがmDNSでデバイスを見つけ、ポータルから使い捨てトークンを取得してデバイスに渡す。トークンのポータルでの有効化はデバイス自身が行う)。Wi-Fiがつながるまで、シリアルポートには何も出ません。コアがWebインストーラー(Improv)のために空けておくからです。

手順と期待されるログ — Build-Your-Own-iDryer、章「コアでのファームウェアの開始」。


4. データ:テレメトリとステータス

  • Configのhas*フラグは、どの語彙フィールドがテレメトリに入り、どのセルがカードに表示されるかを決めます。
  • 値はs_link.telemetry(airTempC、airHumidityPct、heaterTempC、heaterPower01、fanOn、servoOpen)とs_link.status(mode、targetTempC、durationS、elapsedS)に書き込みます。コアはConfigの周期でそれらを公開し、s_link.publishStatusNow()はステータスをすぐに送ります。
  • 独自のフィールドはs_link.onTelemetryPublish()で、カードにはs_link.card().sensor()で — デバイスカードを参照。

5. 設定:メニュー

設定はsrc/menu/menu.yamlに記述します。ジェネレーターmenu_gen.pyがそこからC++コード、NVSへの保存、メニューのJSONを作ります(プロトコルとしてのメニュー)。製品コードは:

  • s_link.begin()の前にメニューを読み込む:menu.initDefaults()、menu.loadFromNVS()、menu_sync_state_to_cache();
  • menu_buildFullJson()とs_link.devicePublisher()->publishConfigRaw()で公開する — オンラインになったときとget_configコマンドを受けたとき;
  • setコマンドをmenu_apply_by_bind()で適用し(値、NVS、キャッシュを一度に)、メニューを再公開する。

完全なコード — Build-Your-Own-iDryer、章「YAMLからのメニュー」。


6. デバイスカード

カードに何を表示し、どの操作を開始するかはs_link.card()で宣言します — デバイスカード: card マニフェスト。


7. コントラクト

新しいトピックを追加したりペイロードを変更したりするとき:

  1. contracts/mqtt_contract.yamlを更新する;
  2. contracts/regen.shを実行し、生成されたファイルをコミットする。

2チップのデバイス

UARTで別のコントローラー(例:RP2040)と連携するESP32向けに、コアにはUARTブリッジidryer_uart.hがあります。動作する参考実装はidryer-linkファームウェアです。