ArduinoGPIOにRESTful APIを生やした
はじめに
ArduinoをREST APIで操作できるESP32向けのファームウェアを作りました。基本的なGPIO状態の操作と取得、GPIO状態のEEPROMへの保存などがHTTP通信経由でできます。
これは何??
組み込み開発において、開発効率を上げるためのソフトウェアの取り組みとして、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
が完全に上ですね。
↓詳しくはこちら
でも、開発環境が増えるという意味ではRESTuino
もいいと思います。
RESTuino(これ)
これらと比較すると、
- 駆動部部分だけをうまく分離して特定のアクチュエータだけに絞ることなく、一般的な入出力に対応できた
- より普及しているHTTP通信経由で行うことができる
という点で、かなり使いやすいのではないでしょうか?
RESTuinoのライバル的な、GPIOをHTTP通信で操作するというソフトウェアは今の所見つかっていません。(あったら教えてほしいです。)(というか、いままで何故なかったんだとは思う…)
IoTでの通信は、MQTTやHTTPがありますが、なぜHTTPを採用したのかと言うと、一番普及しているためweb系の人にもわかりやすいと感じたからです。IoT界隈だけで完結させたくなかったというのが大きいですね。(HTTPには、リアルタイム性の問題も色々あるけど、メリットのほうが多いと感じています)
問題点
リアルタイム性
リアルタイム性の確約はできていません。これは、RESTuinoで使用するHTTP通信によるものです。
詳しくはこちらをご覧ください。
現場的な運用の話をすると、普通のネットワーク環境(jcomのルーター)でESP32ボードを使用していれば十分に実用的です。
iphoneから操作して、スイッチを押す行為が「失敗」したことは3ヶ月運用(毎日、少なくとも起きる・寝るで2回は操作)して一回だけです。それも多分、DNSの問題。(homebridgeと接続するときは、IPアドレスではなくて、host名.localで接続しています)
また、iphoneから操作して、スイッチを押すまでの時間も遅いと思ったことはありません。
通信系未実装
やっていないだけなので、がんばります。
例えば、BME280の温湿度センサーはI2C通信なので、温湿度センサーを各部屋に設置してIoTサーバーから各部屋の温湿度状態を取得とかもやりたいですよね。
暗号化されていない
今回作ったRESTuinoは単純なHTTP通信を用いて、実装されているため認証などの機構は未実装です。
そのため、悪意のある第三者にご飯を炊かれてしまう脆弱性があります。
これも、後々実装していけたらと思います。
homebridgeなどをインストールしたIoTサーバー(エージェント)が必要
(問題点というより注意点ですが)ローカルネットワーク内での操作を想定しているので、外部ネットワークからのアクセス・HomeKit APIなどへの対応は別で行う必要があります。
しかし、homebridgeというOSSなIoTサーバー(HomeKitエミュレータ)なら簡単に設置・運用できます。homebridgeはラズベリーパイに簡単にインストールできて、configをブラウザで操作できるので、初心者でも簡単だと思います。
Homebridgeサーバーと接続したときの技術構成はこんな感じになります。
↓GitHubはここで、
↓RaspberryPiへのインストールはここに書いてあります。wifi設定して、このページのコピペすればいいです。
外部アクセスのためには、本来HomePodや据え置きiPadなどが必要ですが、自分はラズベリーパイにPiVPNというVPNソフトウェアを入れています。それによって、外にいるときは、iPhoneから家のネットワークにVPNでアクセスして、ブラウザからhomebridgeサーバーのローカルIPを入力し、ブラウザからスイッチの操作をしています。
使い方
RESTuinoファームウェアの書き込み
-
リポジトリをクローンします。
$ git clone https://github.com/takeyamayuki/RESTuino.git
-
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"};
-
複数のRESTuinoを設置する場合は、
host_name
(lin 29)を変更する必要があります。$ vi src/main.cpp
static const char *host_name = - "restuino"; + "restuino2";
-
RESTuinoをビルドしてアップロードします。
# for esp32-devkit $ pio run -e esp32dev -t upload # for MH ET LIVE ESP32DevKIT $ pio run -e mhetesp -t upload
-
EEPROMをクリアします。
シリアルモニタに
WiFi connected.
が表示されたら、RESTuinoシステムを初期化します。$ curl restuino.local/ -X DELETE Change all pins to nan status...
-
RESTuinoが使用可能になります。
次の項目で、同じネットワークにつながったホストからAPI経由でRESTuinoを実際に操作します。
API経由でのGPIO操作
- URLにGPIO番号を指定する
-
POST
でピンの状態を定義(digitalWrite、digitalReadなど) -
PUT
で値を更新 (digitalWriteはHIGHなど) -
GET
で現在の情報を取得 (digitalReadなど) -
DELETE
ピンの状態を無効にする
Note
リクエストボディを送信する時は、ヘッダにContent-Type: text/plainを指定してください。
具体例として、GPIO15でdigitalReadしたいときは、
-
http://restuino.local/gpio15
に対して、リクエストボディにdigitalRead
を入れて、POST
を実行 -
http://restuino.local/gpio15
に対して、GET
を実行
GPIO15で88°にサーボモーターを動かしたいときは、
-
http://restuino.local/gpio15
に対して、リクエストボディにServo
を入れて、POST
を実行 -
http://restuino.local/gpio15
に対して、リクエストボディに88
などの0~180の整数で表される角度を入れて、PUT
を実行
詳しいAPIドキュメントについては、GitHubのREADMEを見てください。
examplesもGitHubにありますので、御覧ください。
実際に使ってみた所…
IoTクライアントとして、スイッチボットを模して設置を行いました。
こんな感じで両面テープでSG90サーボモータを壁付けスイッチにつけて、ESP32ボード(MH ET LIVE ESP32DevKIT)と接続します。もちろん、ESP32ボードには、RESTuinoをアップロードします。
そして、homebridgeのconfigのアクセサリーセクションにこんな感じで書きます。家の中にRESTuinoが2つ以上有るので、host名はrestuino0になっています。
できました。
今の所、いい感じです。
これの前のバージョン?として、RESTful-servo-motorを作っていたのですが、この場合だと、上記のように3ヶ月運用して、不具合は0でした。
技術解説
コンピュータソフトウェアの考え方に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のスター🌟、この記事のいいね👍よろしくおねがいします🙏
あと、今年の技育展2022 開発スキル支援部門で発表する予定ですので、ぜひ聞きに来てください。アーカイブ残るらしいので、リアルタイムで聞かなくても大丈夫そうです。
Discussion