WebIOPiを使ってRaspberryPiのGPIOを外出先から操作する
はじめに
RaspberryPiに外出先から(LANの外から)スマホなどでアクセスできると工作の幅がグッと広がる。 例えば、GPIOにアクセスできるだけでも外からLEDを操作したり、リレーを操作したり、サーボモータだって操作できるだろう。
RaspberryPiに外からアクセスする方法にもいろいろあるが、今回は手軽な方法として、WebIOPiを使った方法を試してみる。
WebIOPiとは
RaspberryPiに外部からアクセスしてGPIOなどを操作できるライブラリらしい。Python+RaspberryPi 2or3で動作し、REST APIもついてくる。
やはりこれもすでに試した人が多くいる。WebIOPiを使ってブラウザからRaspberry PiのGPIOを操作してみる | Developers.IOなどを参考に実装した。ここでも備忘録を兼ねて動作確認までの手順を述べる。
WebOIPiのインストール、動作確認
まず、WebIOPiをダウンロードする。2020/01/09現在の最新バージョンは0.7.1である。
ダウンロード・インストール手順はWebIOPiを使ってブラウザからRaspberry PiのGPIOを操作してみる | Developers.IOをそのまま実行して問題なし。
sudo systemctl start webiopi
でWebIOPiサーバを立てたらまずはLAN内のPCやスマホからアクセスしてみる。
例えば、ブラウザからアクセスする場合はhttp://"RaspberryPiのIPアドレス":8000
でアクセスできる。今はLAN内なのでIPアドレスは192.168...のような感じだろう。例えば、http://192.168.0.6:8000
のような感じ。アクセスするとIDとパスワードが聞かれる。デフォルトはID:webiopi, pass:raspberry
である。
最初に表示されるのは以下の画面。
今回使うのはGPIO Headerである。クリックすると以下のIO一覧が見える。
それぞれのピンの横に書いてあるのが現在のそのピンの属性(INなら入力、OUTなら出力)、数字の色が出力状態を表す(黒:L、黄:H)。 出力がOUTになっているピンなら、数字をクリックするだけでON/OFFが切り替わる。少なくともLAN内からのアクセスなら瞬時に切り替わる。
WebIOPiをRaspberryPiブート時に自動起動
基本的にWebIOPiはRaspberryPiを再起動する度にstartさせる必要があるが、面倒なので以下のコマンドでブート時に自動起動できる。
sudo update-rc.d webiopi defaults
逆に自動起動をやめたい場合は以下のコマンド。
sudo update-rc.d webiopi remove
REST APIで操作する
ピンの状態取得などをGET,POSTで行うことも可能だ。(以下IPアドレス192.168.0.6、GPIO21の場合)
状態取得
GET http://192.168.0.6:8000/GPIO/21/value
属性の変更(OUT:出力に変更)
POST http://192.168.0.6:8000/GPIO/21/function/out
ピンをH
POST http://192.168.0.6:8000/GPIO/21/value/1
ピンをL
POST http://192.168.0.6:8000/GPIO/21/value/0
ブラウザのURLバーからアクセスする場合はGETなので、状態取得はブラウザでできる。以下はGPIO21の状態を取得した場合だが、ただただ数字で0or1が帰ってくる。
URLバーからPOSTはできないので、ChromeならAdvanced REST client - Chrome Web Storeなどの拡張機能を入れてPOSTの試験ができる。
LANの外からアクセスする
家の中だけでやっていてもつまらないので、外出先からいじりたくなる。そうなると、ルータの設定をいじる必要がある。
基本的に一般的な家の中なら、ルータで各機器にプライベートIPを割り当てているはずである。我が家の場合ならRaspberryPiに192.168.0.6を当てている。 外からアクセスする場合は、グローバルIPでアクセスするわけだが、グローバルIPはルータに割り当てられているわけであって、RaspberryPiには割り当てられていない。なので、グローバルIPだけではプライベートIPしか割り当てられていないRaspberryPiにはアクセスができない。
そこで、ルータのポートマッピング機能を使う。ポートマッピングとは、ルータが持つ機能の一つで、グローバルIPアドレスの特定のポートを、特定のプライベートIPアドレスの特定のポートに転送するものである。
今回の事例では、WebIOPiはポート番号8000を使っているので、グローバルIP宛でポート8000宛のパケットをRaspberryPiに転送してやることで外部からRaspberryPiにアクセスする。
ポートマッピングの設定は一般的にルータの管理画面からできる。
我が家はAtermのルータだが、詳細設定→ポートマッピング設定から設定できる。
これが設定できたら、http://"グローバルIP":8000
でWebIOPiにアクセスできる。
なお、グローバルIPはルータ設定画面やアクセス情報【使用中のIPアドレス確認】などでわかる。 CUIでグローバルIPを知りたい場合は、What Is My IP Address? - ifconfig.meのサービスを利用できる。
curl ifconfig.me
でグローバルIPを取得できる。
WebIOPiのパスワードを変更する
外部からアクセスする場合は、パスワードがデフォルトのままでは不安である。 パスワードは以下の通り変えられる。
$ sudo webiopi-passwd WebIOPi passwd file generator Enter Login: webiopi Enter Password: Confirm password: Hash: e70c940a189251e9cd4515b3a1a6c6f02aa05c744a456ce360fe14bf2c5c0353 Saved to /etc/webiopi/passwd
パスワードを変更したら、stop,startすること。これで反映される。
WebIOPiからサーボモータを操作する
上記の使い方は、あくまでGPIOのIN/OUT, H/Lを設定するものだった。外出先からWebIOPiを使って簡易的にサーボモータを操作できないだろうか?
今回は以下の方法で実装した。
GPIO20の出力状態(On/Off)をポーリングで監視する
WebIOPiでGPIO20の出力状態を変更する(Off→On)
ポーリングでGPIO20がOnになったことを確認したら、サーボモータを操作する関数を呼び出す
少しまどろっこしいが、WebIOPiを使って気軽にサーボモータをいじるならこれが楽ではないだろうか。 例えば、以下は常にGPIO20を監視して、WebIOPiでGPIO20をOnしたらサーボモータを動かすスクリプトだ。
import pigpio import time def servoPush(): moveServo(SERVO_PUSH) time.sleep(SERVO_TIME) moveServo(SERVO_RELEASE) def calcServoDuty(ratio): duty = 25000 + (120000 - 25000) * ratio return duty def moveServo(ratio): duty = calcServoDuty(ratio) pi.hardware_PWM(PORT_PWM, SERVO_PERIOD, int(duty)) # pigpioの設定 pi = pigpio.pi() PORT_PWM = 18 PORT_WEBIOPI = 20 pi.set_mode(PORT_WEBIOPI, pigpio.OUTPUT) # サーボモータ設定 SERVO_RELEASE = 0.5 SERVO_PUSH = 0.35 SERVO_TIME = 0.2 SERVO_PERIOD = 50 pi.set_mode(PORT_PWM, pigpio.OUTPUT) moveServo(0.5) pi.write(PORT_WEBIOPI, 0) while True: try: #WebIOPi polling if pi.read(PORT_WEBIOPI): pi.write(PORT_WEBIOPI, 0) servoPush() time.sleep(1) except KeyboardInterrupt: break
(2020年1月10日追記)
上のコードでサーボモータを操作してみた。 スマホはWiFiを切って、モバイル回線につないでおり、グローバルIPでアクセスしている。
スマホ(モバイル回線接続)を使ってWebIOPiからRaspberryPiのサーボモータを操作できた!(WebIOPiから直接サーボはいじれないのでラズパイでGPIOポーリング→サーボ関数呼び出しをしている)
— 水田かなめ (@kmizta) January 10, 2020
これで外出先からリモート操作できるぞー pic.twitter.com/j2ze5HuR4L