1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IoTLT (IoTや電子工作ネタなど)Advent Calendar 2024

Day 20

小ロットの量産でOTAに挑戦した話

Last updated at Posted at 2024-12-19

はじめに

マイコンでLチカができて、サーバとの通信も一通り実現できたけれど、意外と手が届かないのがOTA(Over the Air)
今回は、30台程度の小規模ロットのIoT端末開発・運用を通じて得た、OTAの実装方法を紹介したいと思います。

※初投稿のため、至らない点があるかもしれませんが、よろしくお願いいたします。orz

前提条件

  • 作りたいモノ
    複数のIoT機器を監視・制御・メンテナンスする、よくある(?)構成を想定しています
    • 通常時:サーバとマイコンでいろいろ送受信(MQTT)したい
      1. (定期)マイコンからセンサデータをサーバに送信
      2. (オンライン)サーバからマイコンにつながる駆動部を制御
    • メンテナンス時(今回のメイン)OTAしてマイコンのアップデートがしたい
      1.(定期)マイコンからファームウェアのバージョン確認
      2.(1.でアップデートあれば)マイコンがサーバ上のファームウェアのダウンロードと更新
  • 使用機材と用途
    • クラウドサーバ:AWS
      1. IoT Core経由で通信(MQTT)
      2. ファームウェアのバージョン情報やファームウェアはS3に格納
    • 通信機器:WiFiルータを使って、サーバとマイコンを中継
    • マイコン: Raspberry Pi Pico WをArduino化して利用 
    • その他:各種センサおよび駆動部をマイコンと接続

OTAでやりたい要件

  1. マイコン全台をまとめてOTAしたい
    • 小ロットとはいえ、一台ずつOTAするのは非現実的
    • OTAするファームウェアは全台共通だが、各マイコン固有の設定情報は保持したい
  2. 万が一に備え、個別アップデートも可能にしたい
    • その際、個別の設定情報も書き換えられるようにしたい
  3. OTA失敗時にはリトライやアラートが欲しい
    • OTAが失敗すると現地対応が必要になり非常に辛い。可能な限りリトライして欲しい

解決した仕組み概要

  1. マイコン上のファイル構成
    • マイコンのメモリ内にFileSystem領域を用意し、マイコンの識別ID等の個体情報に書き込み、ファームウェア領域とは分離します
      void setup() {
        mountFlashMemory();//FileSystemへのアクセス確認
        #ifdef FILE_WRITE_ENABLED
          setupInitialConfig(deviceConfig);//deviceConfigを設定
          saveConfigToFS(deviceConfig);  // deviceConfigを書き込み
        #elif defined(FILE_WRITE_DISABLED)
          loadConfigFromFS(deviceConfig);  //deviceConfigを読み込み 
        #else
          #error "No FILE_WRITE selected! Please define FILE_WRITE setup."
        #endif
        setupMQTT();//通信関連の初期設定
        checkForUpdates(ota_univ_version_url);//全体のアップデート確認
        checkForUpdates(ota_device_version_url);//個別のアップデート確認
        healthCheckPolling();//サーバへ諸々送信
      }
      
      void loop(){          
        checkForUpdates(ota_univ_version_url);//全体のアップデート確認
        checkForUpdates(ota_device_version_url);//個別のアップデート確認
        healthCheckPolling();//サーバへ諸々送信
        delay(10000);//定期的にOTAチェック
      
      }
      
    • 個別のファームウェアを書き込む場合
      #define FILE_WRITE_ENABLED //FileSystemへ以下を書き込み保存
      inline void setupInitialConfig(DeviceConfigData &deviceConfig) {
      deviceConfig.deviceId = "device_dev_00001";
      deviceConfig.deviceVersion = "ver1.0.0";
      deviceConfig.wifiSSID = "hogehoge";
      deviceConfig.wifiPassword = "piyopiyo";
      }
      
    • 全体のファームウェアを書き込む場合
      #define FILE_WRITE_DISABLED ////FileSystemから読み込むのみ
      inline void setupInitialConfig(DeviceConfigData &deviceConfig) {
      deviceConfig.deviceId = "";
      deviceConfig.deviceVersion = "";
      deviceConfig.wifiSSID = "";
      deviceConfig.wifiPassword = "";
      }
      
  2. サーバ上のファームウェアとバージョン情報のファイル構成
    • 個別書き込み用と全体書き込み用のファームウェアおよびバージョン情報を用意し、以下のようにS3に格納します
      ##ファイル構成
      s3-bucket/
      ├── firmware/
      │   ├── device_dev_00001/                       
      │   │   └── firmware.bin        // device_dev_00001向けの個別ファームウェア    
      │   ├── device_dev_00002/                       
      │   │   └── firmware.bin        // device_dev_00002向けの個別ファームウェア 
      │   ├── device_dev_00003/                       
      │   │   └── firmware.bin        // device_dev_00003向けの個別ファームウェア 
      │   ├── device_dev_00004/                       
      │   │   └── firmware.bin        // device_dev_00004向けの個別ファームウェア 
      │   └── universal/                           
      │       └── firmware.bin        // 全体向けファームウェア
      └── version/
          ├── device_dev_00001.txt    // device_dev_00001向けの個別ver情報    
          ├── device_dev_00002.txt    // device_dev_00002向けの個別ver情報    
          ├── device_dev_00003.txt    // device_dev_00003向けの個別ver情報    
          ├── device_dev_00004.txt    // device_dev_00004向けの個別ver情報    
          └── universal.txt           // 全体向けver情報
      
  3. OTAの流れ
    マイコンからの起動時や定期で下記を確認します
    1. 個別用・全体用バージョン情報を取得
    2. マイコン自身のバージョンと比較
      1. 新しいverがなければ終了
      2. 新しいバージョンがあればファームウェアをダウンロード・書き込み
        • ※全体向けファームウェアを書き込んでもFileSystem側に保存された個体情報は影響を受けません。

おわりに

一旦上記の設計で作りましたが、まだ改善点はあります。
特に現状の仕組みでは、個別ファームウェアを書き込む際のバージョン管理が煩雑になりがちです。
例えば、全体のファームウェアverが1.2.0の時に個別のファームウェアでOTAしたい際には、個別のverを1.2.1等に値を上げて書き込む必要があります。
次に全体のアップデートしたい場合、個別のverの最新が1.2.1のために全体のファームウェアverが1.2.2以上にする必要があります。
現状の3桁管理ではなく、個別の書き込み用に4桁管理へと増設をしておく方が良いかもしれません。
他にもS3のテキストでバージョン管理するよりはDBで管理した方が良いなぁとか、まだまだOTAは奥が深いです。

今回の記事が皆さんのIoT開発の参考になれば幸いです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?