OKI AE2100 & Node-REDでローコードIoTしてみた。その１ 準備編

#  PythonでRS-485圧力センサーシミュレータ作成

# はじめに
OKIが販売するAE2100というゲートウェイは「AIエッジコンピューター」として大注目の製品なのですが、RS-232C、RS-485といったレガシーインターフェースを備える、信頼性の高いインダストリアル向けの製品でもあります。

先日RS-485出力の圧力センサーをAE2100で評価した際に、ついでに使い慣れた Node-RED をインストールして AE2100 をローコードIoT開発のプラットフォームにしてみた内容を記事にまとめました。

まとめてみたら、長文になってしまったので4編に分けます。
本記事はその準備編になり、Pythonで圧力センサーのシミュレータを作ります。 

[その１ 準備編「PythonでRS-485圧力センサーシミュレータ作成」](https://qiita.com/marufumio/items/d3182574e5bed35f94e0)  **(本記事)**
[その２ 構築編「DockerでローコードIoTプラットフォーム構築」](https://qiita.com/marufumio/items/f6bd3088c9c60e5e7f57)
[その３ 実践編 1「Node-REDでダッシュボード作成」](https://qiita.com/marufumio/items/7e04006f48036cc37f21)
[その４ 実践編 2「Node-REDでMQTT Pub/Sub」](https://qiita.com/marufumio/items/afdae6eb83b7752ce57d)

# 前提

ソフトとしては、Linux と Docker コマンドの経験が必要です。
Node-RED は初心者向けの内容です。プログラミングは行わず、直感的にできる簡単な設定しか行わないため、経験のない方はこれを機会にトライしてみてください。
プログラミングとしてはPythonが出てきますが、Windows PC側で動かすシミュレータとして使うだけなので、Python自体を知っている必要はありません。

ハードはWindows 10 PCとUSB-RS485変換アダプター、そして AE2100 が必要です。

ネットワークに関してはMQTTを使います。
Qiitaに限らず、WebにはMQTTに関する良記事がたくさんあるので、MQTT初心者の方々はご参照ください。

# AE2100
AE2100 自体に関してはOKIの[製品ページ](https://www.oki.com/jp/AIedge/ae2100/)を見ていただくとして、ここではこの記事に関係するポイントだけ記載します。
ハードウェアの基本スペックは以下の通り。

- CPU : Intel Atom E3950 (4コア@1.6GHz)
- RAM 4GB
- ストレージ : 32GB (eMMC)
- 1Gb Ethernet x 2

ソフトウェアとしては、OS は Yocto Linux です。 Debian 系で動いている他のゲートウェイ製品と比べてアプリの追加に難あり、と思いきや、Docker CEが組み込まれていて、アプリはDockerコンテナにして追加するようになっています。
上記のハードウェア・スペックはけっこう絶妙で、発熱も少なく、4つや5つのコンテナを同時実行しても全く問題なく動作します。（もちろん、どんなコンテナを実行するかに依存するわけですが、コンテナ技術ってホントにすごいですね。）

以降ではOKIのプロプライエタリな情報にはなるべく触れず、一般によく使われているオープンソースだけを使って作業を進めます。
初心者向けの内容でつまずくことはないと思うのですが、以下の作業は筆者の見解と経験に基づくものであり、動作の保証やサポート等に関してOKIは何も関知しないことをご了承ください。

# こんなことやりました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192538/61d30173-5afc-61b3-509a-ddaf995aa365.png)

圧力センサーからの出力をNode-REDでReadしてダッシュボードに出力するとともに、MQTTブローカーにパブリッシュします。

この図のデモアプリは40MBぐらいのコンテナに20行ぐらいのPythonスクリプトを追加してできてしまったのですが、ここではあえてDocker HubにあるNode-REDコンテナを利用して、AE2100をローコードIoT開発のプラットフォームにしてみました。

# こんなふうにやりました

## 圧力センサー(シミュレータ)

本記事では圧力センサーは実機ではなく、Window 10 PC + USB-RS485変換アダプターを圧力センサーと見立て、Pythonで出力をシミュレーションします。

## USB-RS485変換アダプター

AE2100のRS485端子台（上）とUSB-RS485変換アダプター（下）です。
![USB-Serial.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192538/902bd475-dcfc-23d4-7114-4514dec5a847.png)

AE2100 が対応するRS-485は半二重の2線式です。
今回は余興でGND付きの3端子で最安値のUSB-RS485変換アダプターを買ってみました。
このアダプターはAmazonでほとんど最安値の323円(配送料69円)の代物ですが、FTDIのチップ（FT232RL。たぶん本物）が使われていて、Windows 10 ではドライバーの追加なし使えます。
FT232RLを上下に挟んでLEDが付いていて、実際に TX, RX があると点滅してくれるので、デバッグの初期に何気に便利です。写真はちょうど TX が出ている瞬間です（よく写ったな）。

PCと接続するコネクタが USB 2.0 Standard Type B レセプタクルなのもうれしいポイントで、A to B ケーブルを久しぶりに使うことができます。捨てないで良かった！
端子台も大きくしっかりしていて、マットブラックの基盤にUSBコネクタのシルバーがキラリと光る、カッコ良い一品です（裏の半田面は秘密です）。
中国発送で到着まで2週間ぐらいかかりましたが、非常に満足度の高い買い物でした！ 

シミュレーターでも AE2100 とは実機と同様に接続します。
AE2100側の端子台のD+をアダプタのA端子に、D-をB端子に接続します。
GND同士もしっかり接続しました。
AE2100 のD+,D-間には AE2100 付属のターミネーター(太いやつ)を接続して、これでぬかりはないはずです。
接続に使用したワイヤーは40本で120円のオス-オスのジャンパー線ですが、10cm くらいの距離なので問題ないでしょう！

## Pythonによるシミュレータ実装
シミュレータの開発言語には Python を選択しました。
簡単な事をやるには Python が一番簡単にできるのではないでしょうか。
処理は確かに遅いですが、１秒以上の応答で良ければ十分です。

今回 Windows 10ホストで実行したPythonのバージョンは3.6.9でしたが、最新のものでOKでしょう。
シリアル通信ライブラリ pyserial のインストールが必要です。

- pip3 install pyserial

COMポートの番号はデバイスマネージャで確認する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192538/ce31d4f1-bdf0-0f72-8a11-ff27de6d3256.png)
今回は COM11 でした。
ビットレートは、圧力センサーと同じ 9600 に設定します。
この圧力センサーは、計測した圧力値を1秒ごとに kPa で出力する設定になっていて、デリミターは'\r\n'です。
Pythonにより、low_pressとmax_pressの間を1秒に0.05kPa単位でインクリメント、デクリメントして出力をシミュレートします。

```send_press.py
import serial
from time import sleep

PORT = 'COM11'  # 番号は環境依存です！
BITRATE = 9600
TIMEOUT_SEC = 10.0
min_press = cur_press = 98.0
max_press = 102.0
interval = 0.05
SLEEP_SEC = 1

ser = serial.Serial(PORT, BITRATE, timeout=TIMEOUT_SEC)

def send_press(cur_pres):
    data = f'{cur_press:.1f}'+" kPa\r\n"
    msg = bytes(data, 'utf-8')
    ser.write(msg)
    print(msg)

while True:
    while cur_press < max_press:
        cur_press += interval
        send_press(cur_press)
    while cur_press > min_press:
        cur_press -= interval
        send_press(cur_press)
    sleep(SLEEP_SEC)
```
TIMEOUT_SEC 経ってもシリアルポートに接続できない場合、終了します。
BITRATEはデフォルトで9600bpsなので、今回はシリアル通信をほとんど意識せず、１バイト毎に1ビットのスタートビット 0、1ビットのストップビット 1 を挟んで1秒間に9600ビット送信できるプログラムができました。
（このシミュレータは1秒ごとに20バイトぐらい送信します。）

実は **pySerial** ライブラリには RS-485 に特化したサブクラスが用意されているのですが、RS-485 特有の機能（マルチドロップ時のRTS制御）を使わない場合、**serial.Serial** クラスを使った方が安定していて処理も早いそうです。
今回は1対1通信なので、そのまま **serial.Serial** クラスを使っています。

## シミュレータ実行

コマンドプロンプトでシミュレータを実行します。
このような出力が1秒ごとに出ればシミュレーションOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192538/78b036b8-cf37-f2a4-3df2-f92ad38f798e.png)
Ctrl+C で終了します。

# さいごに
RS-485で出力する圧力センサーのシミュレータができました。
つまらないプログラミングの話はこれで終了です。

次回はいよいよ AE2100 で Node-RED を動かします！