🐞

ArduinoGPIOにRESTful APIを生やした

2022/09/11に公開

はじめに

ArduinoをREST APIで操作できるESP32向けのファームウェアを作りました。基本的なGPIO状態の操作と取得、GPIO状態のEEPROMへの保存などがHTTP通信経由でできます。

https://twitter.com/takeyamaaaaa/status/1568199856648499200?s=20&t=D3oseAf7lppswQM6Sew-dg

https://github.com/takeyamayuki/RESTuino

これは何??

組み込み開発において、開発効率を上げるためのソフトウェアの取り組みとして、ArduinoやCircuitPythonなどがありますね。今日から組み込み開発における新しいスタンダードが誕生します。(キリッ)
ESP32向けの対話型組み込み開発ファームウェアRESTuinoです。

ハードウェア抽象化レイヤーに対して、外部APIレイヤーを作って、マイコンの外からGPIO操作できるようにしました。今回は、ESP32というマイコンの中で、Arduinoというハードウェア抽象化レイヤーに対して、RESTful APIでGPIO操作できるようにしました。

具体的な使い方としては、URLでGPIO番号を指定して、POSTでピン状態定義(digitalWrite、digitalReadなど)、PUTで値更新(digitalWriteでHIGH、LOWなど)、GETで現在情報取得、DELETEでピン状態の無効化ができます。そして、saveをしておけば、電源を切ってもピン状態をEEPROMに保存するので、IoTでのクライアント側ソフトウェアとして運用しやすいです。

時間的な処理(delay, sleep)はエージェント側で行って、RESTuinoはGPIOの処理をするだけを想定しています。そのため、Aruduinoの処理ができると行っても、delayは実装されていません。

何が嬉しい?

1. 対話型組み込み開発の選択肢が増える

MATAB・Python・シェルなどでは対話型プログラミングが可能です。
対話型プログラミングというのは、一行ずつプログラムを実行することによって、プログラムを気軽に行えるというものです。

組み込み開発においては、いままでMicroPython REPLぐらいだったのですが、RESTuinoも選択肢の1つになります。といっても、完全なC++での対話型プログラミングではないのですが、擬似的なものが可能です。(今後、Web上でのUIを完成させれば、†GUI対話型組み込み開発†が可能になります)

そして、この対話型プログラミングを人間相手ではなくて、IoTサーバー相手に行うと、2番目のメリットが得られます。

2. IoTのクライアント側のソフトウェアが(簡単なものなら)必要なくなる

IoT突入時代になっています。

  • Switchbot
  • Airtag
  • スマートロック
  • 温湿度センサー

とかとか。将来は、様々な電化製品や電子機器がネットワークに接続されて自動化されていくでしょう。

RESTuinoはこれらのOSにもなりうるソフトウェアです。
SwitchbotはREST API経由でモーターのみを動かしますが、RESTuinoだとArduinoの機能が使えるので、モーターはもちろんのこと、周辺回路を変更することでリレーLEDといった駆動部から、各種センサの入力まで遠隔で操作できます。

新規性・類似技術解説

そもそも、IoT全般でよくあるのは、MQTTやHTTPを用いて、データそのものを交換するというものです。このアプリケーションは、システムの機能自体もHTTPでやり取りできないのではないか?というのがコンセプトです。

SwitchBot

SwitchBotは、知っている人も多いと思いますが、スマホから壁付けスイッチやちょっとしたスイッチをオンオフできます。

類似点
REST APIを提供しています。また、SwitchBot本体とHubが必要で、外部ネットワークからの接続にはHubを経由して、SwitchBot本体を操作します。同様に、RESTuinoも外部ネットワーク接続のために、homebridgeなどのIoTサーバーと接続することを想定しています。

相違点
SwitchBotは、REST APIで操作できるのはアクチュエーターだけです。RESTuinoはGPIOを操作・取得できます。

microROS

microROSはマイコンがROSのpubsub通信を行うというものです。microROSの嬉しさは、マイコンとROSの連携が簡単になるということにあると思います。

そのため、microROSはROSのpubsubの知識が必要です。RESTuinoは、マイコンに最初に書き込むだけで、web系では基本技術であるHTTP通信だけで操作できます。

OTA

OTAはOver The Airの略で、ネットワーク経由でプログラムを書き込めるというものです。ESP32のArduinoライブラリにはこのOTAのサンプルプログラムが最初から入っています。そのため、類似技術と言ってOTAと何が違うのかと思った人も多いのではないでしょうか?

答えは、プログラムの場所です。OTAはネットワークを使いますが、プログラムをESP32に書き込みます。
RESTuinoは、エージェント側にプログラムがあります。そして、REST API経由でESP32を制御します。ここが大きな違いです。同じくネットワークを使うところは似ていますが、それ以外のコンセプト・制御方法はかなり違います

MicroPython REPL

自分も最近まで、全く知らなかったのですが、対話型組み込み開発はJupyterLabでMicroPythonの開発ができるらしいです。しかも、シリアルとWebでの対話型開発が差p「おーとされていて、使ってないのですがかなりいい感じだと思いました。
対話型組み込み開発だと、MicroPython REPLが完全に上ですね。

↓詳しくはこちら
https://micropython-docs-ja.readthedocs.io/ja/latest/esp8266/tutorial/repl.html

でも、開発環境が増えるという意味ではRESTuinoもいいと思います。

RESTuino(これ)

これらと比較すると、

  • 駆動部部分だけをうまく分離して特定のアクチュエータだけに絞ることなく、一般的な入出力に対応できた
  • より普及しているHTTP通信経由で行うことができる

という点で、かなり使いやすいのではないでしょうか?

RESTuinoのライバル的な、GPIOをHTTP通信で操作するというソフトウェアは今の所見つかっていません。(あったら教えてほしいです。)(というか、いままで何故なかったんだとは思う…)

IoTでの通信は、MQTTやHTTPがありますが、なぜHTTPを採用したのかと言うと、一番普及しているためweb系の人にもわかりやすいと感じたからです。IoT界隈だけで完結させたくなかったというのが大きいですね。(HTTPには、リアルタイム性の問題も色々あるけど、メリットのほうが多いと感じています)

問題点

リアルタイム性

リアルタイム性の確約はできていません。これは、RESTuinoで使用するHTTP通信によるものです。

詳しくはこちらをご覧ください。
https://zeam-vm.github.io/papers/realtime-protocol-3rd-WSA.html

現場的な運用の話をすると、普通のネットワーク環境(jcomのルーター)でESP32ボードを使用していれば十分に実用的です。
iphoneから操作して、スイッチを押す行為が「失敗」したことは3ヶ月運用(毎日、少なくとも起きる・寝るで2回は操作)して一回だけです。それも多分、DNSの問題。(homebridgeと接続するときは、IPアドレスではなくて、host名.localで接続しています)
また、iphoneから操作して、スイッチを押すまでの時間も遅いと思ったことはありません。

通信系未実装

やっていないだけなので、がんばります。
例えば、BME280の温湿度センサーはI2C通信なので、温湿度センサーを各部屋に設置してIoTサーバーから各部屋の温湿度状態を取得とかもやりたいですよね。

暗号化されていない

今回作ったRESTuinoは単純なHTTP通信を用いて、実装されているため認証などの機構は未実装です。
そのため、悪意のある第三者にご飯を炊かれてしまう脆弱性があります。

https://twitter.com/TETRA_IT/status/1527812343178342400

これも、後々実装していけたらと思います。

homebridgeなどをインストールしたIoTサーバー(エージェント)が必要

(問題点というより注意点ですが)ローカルネットワーク内での操作を想定しているので、外部ネットワークからのアクセス・HomeKit APIなどへの対応は別で行う必要があります。

しかし、homebridgeというOSSなIoTサーバー(HomeKitエミュレータ)なら簡単に設置・運用できます。homebridgeはラズベリーパイに簡単にインストールできて、configをブラウザで操作できるので、初心者でも簡単だと思います。

Homebridgeサーバーと接続したときの技術構成はこんな感じになります。

↓GitHubはここで、
https://github.com/homebridge/homebridge

↓RaspberryPiへのインストールはここに書いてあります。wifi設定して、このページのコピペすればいいです。
https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Raspbian

外部アクセスのためには、本来HomePodや据え置きiPadなどが必要ですが、自分はラズベリーパイにPiVPNというVPNソフトウェアを入れています。それによって、外にいるときは、iPhoneから家のネットワークにVPNでアクセスして、ブラウザからhomebridgeサーバーのローカルIPを入力し、ブラウザからスイッチの操作をしています。

使い方

RESTuinoファームウェアの書き込み

  1. リポジトリをクローンします。

    $ git clone https://github.com/takeyamayuki/RESTuino.git
    
  2. ssid_define.cpp を変更して、wifi ルータの ssid, password を定義します。

    $ cd RESTuino
    $ vi src/ssid_define.cpp
    

    ssid_def[]*ssid_pass[]をあなたの無線LANのSSIDとパスワードに、len_ssidをあなたが定義したssidとパスワードの数に変更します。

    uint8_t len_ssid = 2;
    const char *ssid_def[] = {"ssid1", "ssid2"};
    const char *ssid_pass[] = {"pass1", "pass2"};
    
  3. 複数のRESTuinoを設置する場合は、host_name(lin 29)を変更する必要があります。

    $ vi src/main.cpp
    
    static const char *host_name = 
    -  "restuino"; 
    +  "restuino2"; 
    
  4. RESTuinoをビルドしてアップロードします。

    # for esp32-devkit
    $ pio run -e esp32dev -t upload
    # for MH ET LIVE ESP32DevKIT
    $ pio run -e mhetesp -t upload
    
  5. EEPROMをクリアします。

    シリアルモニタに WiFi connected. が表示されたら、RESTuinoシステムを初期化します。

    $ curl restuino.local/ -X DELETE  
    Change all pins to nan status...  
    
  6. RESTuinoが使用可能になります。
    次の項目で、同じネットワークにつながったホストからAPI経由でRESTuinoを実際に操作します。

API経由でのGPIO操作

  1. URLにGPIO番号を指定する
  2. POSTでピンの状態を定義(digitalWrite、digitalReadなど)
  3. PUTで値を更新 (digitalWriteはHIGHなど)
  4. GETで現在の情報を取得 (digitalReadなど)
  5. DELETEピンの状態を無効にする

Note
リクエストボディを送信する時は、ヘッダにContent-Type: text/plainを指定してください。

具体例として、GPIO15でdigitalReadしたいときは、

  1. http://restuino.local/gpio15に対して、リクエストボディにdigitalReadを入れて、POSTを実行
  2. http://restuino.local/gpio15に対して、GETを実行

GPIO15で88°にサーボモーターを動かしたいときは、

  1. http://restuino.local/gpio15に対して、リクエストボディにServoを入れて、POSTを実行
  2. http://restuino.local/gpio15に対して、リクエストボディに88などの0~180の整数で表される角度を入れて、PUTを実行

詳しいAPIドキュメントについては、GitHubのREADMEを見てください。
https://github.com/takeyamayuki/RESTuino#usage

examplesもGitHubにありますので、御覧ください。
https://github.com/takeyamayuki/RESTuino#examples

実際に使ってみた所…

IoTクライアントとして、スイッチボットを模して設置を行いました。

こんな感じで両面テープでSG90サーボモータを壁付けスイッチにつけて、ESP32ボード(MH ET LIVE ESP32DevKIT)と接続します。もちろん、ESP32ボードには、RESTuinoをアップロードします。

そして、homebridgeのconfigのアクセサリーセクションにこんな感じで書きます。家の中にRESTuinoが2つ以上有るので、host名はrestuino0になっています。

できました。

今の所、いい感じです。

これの前のバージョン?として、RESTful-servo-motorを作っていたのですが、この場合だと、上記のように3ヶ月運用して、不具合は0でした。

https://github.com/takeyamayuki/RESTful-servo-motor

技術解説

コンピュータソフトウェアの考え方にCRUDというものがあります。新規作成(Create)、参照(Read)、変更(Update)、削除(Delete)の頭文字をとったもので、主にデータベースでよく使われる考え方ですが、このCRUDって、何かと似てませんか?そう、arduinoでの組み込み開発と似てるんです。新規作成POST(setup), 更新PUT(digitalwriteとか), 参照GET(analogread)とか。

CRUDとArduinoのプログラムの類似性

HTTP通信はesp32 arduinoのライブラリを使っています。

GPIO状態(pinModeなど)は、以下の場所に保存しています。

  • キャッシュ(gpio_arr)
  • 実際の状態
  • EEPROM(電源を切っても保存される)

基本的に、キャッシュと実際の状態は常に同じ値です。

以下のように、状態遷移を行います。

ちなみに、RESTuinoというネーミングは、「MAXduino」とか「びんでいーの」のようにArduino基板にオリジナリティをつけるときによく使われるネーミングをもじっています。今回は、基板ではなく、ソフトウェアですが、重要な要素であるRESTと合わせて、RESTuinoとしました。

まとめ

ここまでご覧いただきありがとうございます。間違っている部分もあると思いますので、ご指摘いただければ幸いです。

最後に、このプロジェクトを応援したい方、この記事が面白いと思った方は、GitHubのスター🌟、この記事のいいね👍よろしくおねがいします🙏

https://github.com/takeyamayuki/RESTuino

あと、今年の技育展2022 開発スキル支援部門で発表する予定ですので、ぜひ聞きに来てください。アーカイブ残るらしいので、リアルタイムで聞かなくても大丈夫そうです。

https://talent.supporterz.jp/geekten/2022/

Discussion