ArduinoGPIOにRESTful APIを生やした


# はじめに

ArduinoをRESTful 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**です。

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

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

# 何が嬉しい？


## 1. 対話型組み込み開発ができる

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

組み込み開発においては、いままで対話型プログラミングはできていなかったと思いますが、RESTuinoによって可能になります。といっても、完全なC++での対話型プログラミングではないのですが、擬似的なものが可能です。

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

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

IoT突入時代になっています。
- Switchbot
- Airtag
- スマートロック
- 温湿度センサー

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

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



# 問題点

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

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

現場的な運用の話をすると、普通のネットワーク環境（jcomのルーター）でESP32ボードを使用していれば十分に実用的です。
iphoneから操作して、スイッチを押す行為が「失敗」したことは３ヶ月運用(毎日、少なくとも起きる・寝るで２回は操作)して一回だけです。それも多分、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サーバーと接続したときの技術構成はこんな感じになります。
![](https://storage.googleapis.com/zenn-user-upload/3f889ac6f24c-20220911.png)


↓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を入力し、ブラウザからスイッチの操作をしています。



# 使い方

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`を実行

詳しいREST 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をアップロードします。

![](https://storage.googleapis.com/zenn-user-upload/f41a4a2fe5c3-20220911.jpg)


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

![](https://storage.googleapis.com/zenn-user-upload/15af4ccae3c4-20220911.png)

できました。

![](https://storage.googleapis.com/zenn-user-upload/f8a74b0e90da-20220911.gif)

今の所、いい感じです。

これの前のバージョン？として、RESTful-servo-motorを作っていたのですが、この場合だと、上記のように３ヶ月運用して、失敗はほぼ０でした。
https://github.com/takeyamayuki/RESTful-servo-motor

# 技術解説

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

CRUDとArduinoのプログラムの類似性
![](https://storage.googleapis.com/zenn-user-upload/a1a6e3ef0385-20220911.png)

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

GPIO状態(pinModeなど)は、以下の場所に保存しています。
- キャッシュ(gpio_arr)
- 実際の状態
- EEPROM（電源を切っても保存される）

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

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

![](https://storage.googleapis.com/zenn-user-upload/5a967a09a758-20220911.png)

![](https://storage.googleapis.com/zenn-user-upload/834e77953203-20220911.png)


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


# 新規性・類似技術解説

そもそも、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通信だけで操作できます。



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

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

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


# まとめ

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

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

https://github.com/takeyamayuki/RESTuino

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

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