金魚に餌をあげる装置を作る(成功)
から。
軌道修正
USBモデムを使えるまで頑張るのが面倒になったのと、そもそも、USBモデムでインターネットに接続できた際に、外部から接続できるように設定可能なのかも、不明なので、軌道修正する。
SSHポートフォワーディング
今回は、root での ssh は、さすがに避けて、一般ユーザーでの ssh ポートフォワーディングをします。
RPIマシンから、接続する。
-L -R で、逆向きなので注意する。
サーバーにログインして、トンネルを作る。
ssh -f -N -R 10022:localhost:22 _USER_@_SERVER_IP_
サーバー側で、トンネルを試す
/usr/bin/ssh _USER_@localhost -p 10022
ログインできる。はず。
公開鍵認証にしておく
鍵を作って、その鍵情報を、ログイン先の .ssh/authorized_keys に足す。
$ ssh-keygen $ cat .ssh/id_rsa.pub (中身を、ログイン先の .ssh/authorized_keys に追記する)
常時SSHトンネル@クライアント側(RPI)
「常時」は、autossh -N を活用する。
autossh -f -N -R 10022:localhost:22 _USER_@_SERVER_IP_
autossh の自動起動は、
ユーザー の crontab で、@reboot
を使用する。
自動でログインできるように、公開鍵認証にしておく。
これで、お互いに公開鍵認証になった。
※補足
環境によっては? sshトンネル越しにログインし、そのまま(ログインしたまま) OS を reboot かけたりすると、SSHが正常に切断されず?、OS立ち上がり後にログインできなくなります。
回避策として
#!/bin/sh sleep 5s killall autossh sleep 3s sudo reboot
を実行して速やかに切断(ログアウト)してます。
ssh でコマンドを投げるテスト
# /usr/bin/sudo -u _user_ /usr/bin/ssh _user_@localhost -p 10022 "ls"
などをテストする。
最終的には、RIP側でも、user から sudo で GIPO の操作を行う。
sudoの環境整備@サーバー側
まず、流れは、
(ざっくり) スマホのブラウザ > WEBサーバー > RPI (細かく) スマホのブラウザ > WEBサーバー:wwwrun > sudo -u _user_ ssh ===ssh接続(ポートフォワーディング)=== _user_@RPI > sudo GPIO操作
WEBサーバーから、RPIにコマンドを投げるに辺り、sudoを使用するので、WEBサーバーから sudo できるように、sudo の使用環境を整える。
WEBサーバーが立っている opensuse の apache2 は、ユーザー wwwrun に成っていた(デフォルトのまま)。
なので、wwwrun から、```sudo できるようにする。
visudo
visudo で、使用するプログラムに許可を与える。実行するスクリプトではない。
wwwrun ALL=(_USERNAME_) NOPASSWD: /usr/bin/ssh
sudoの環境整備@RPI側
GPIOを触るので、 user で、sudo できるようにしておく。
スクリプトにしておく
手順が多く、頭がこんがらがるので、触るファイルを少なくするため、スクリプトにしておく。
サーバー側
> cat kingyo.sh #!/usr/bin/sh if [ "$1" = "TEMPERATURE" ]; then /usr/bin/sudo -u _user_ /usr/bin/ssh _user_@localhost -p 10022 "/usr/bin/sudo /root/temperature.sh" elif [ "$1" = "AC_LED" -a "$2" = "ON" ]; then /usr/bin/sudo -u _user_ /usr/bin/ssh _user_@localhost -p 10022 "/usr/bin/sudo /root/ac_led__on.sh" elif [ "$1" = "AC_LED" -a "$2" = "OFF" ]; then /usr/bin/sudo -u _user_ /usr/bin/ssh _user_@localhost -p 10022 "/usr/bin/sudo /root/ac_led__off.sh" elif [ "$1" = "FEED" ]; then /usr/bin/sudo -u _user_ /usr/bin/ssh _user_@localhost -p 10022 "/usr/bin/sudo /root/feeding.py" fi
RPI側
# cat ac_led__on.sh #!/bin/sh /usr/bin/irsend SEND_ONCE ac_led on root@raspberrypi:~# cat ac_led__off.sh #!/bin/sh /usr/bin/irsend SEND_ONCE ac_led off # cat temperature.sh #!/bin/sh /bin/cat /sys/bus/w1/devices/w1_bus_master1/28-00000724377c/w1_slave | grep t= | /usr/bin/tr -s ' ' , | /usr/bin/cut --delimiter , -f 10 | sed -e "s/t=\(..\)\(...\)/\1.\2/" # cat feeding.py #!/usr/bin/python # coding: utf-8 import RPi.GPIO as GPIO import time import signal import sys def exit_handler(signal, frame): # Ctrl+Cが押されたときにデバイスを初期状態に戻して終了する。 print("\nExit") servo.ChangeDutyCycle(2.5) time.sleep(0.5) servo.stop() GPIO.cleanup() sys.exit(0) # 終了処理用のシグナルハンドラを準備 signal.signal(signal.SIGINT, exit_handler) GPIO.setmode(GPIO.BCM) # GPIO 21番を使用 gp_out = 21 GPIO.setup(gp_out, GPIO.OUT) # pwm = GPIO.PWM([チャンネル], [周波数(Hz)]) servo = GPIO.PWM(gp_out, 50) # 初期化 servo.start(0.0) val = [2.5, 3.6875, 4.875, 6.0625, 7.25, 8.4375, 9.625, 10.8125, 12] # 初期位置 servo.ChangeDutyCycle(val[0]) time.sleep(1.0) # 餌を落とす servo.ChangeDutyCycle(val[8]) time.sleep(1.0) # 初期位置 servo.ChangeDutyCycle(val[0]) time.sleep(0.5) # 終了 servo.stop() GPIO.cleanup() sys.exit(0)
固定IPをDHCPに直してテストする
/etc/dhcpcd.conf の、固定IPに設定した部分をコメントアウトする。
リブートして、動作確認する。
ffmpeg による動画 feeding が、reboot した際に上手く動いていない。
DHCPに変えたからなのか、エラーログを確認できず、確証は無いが、DHCPで、IPが確定する前に、コマンドが実行されてしまっているのではないかと考える。
そこで、しかたがないので、ffmpeg を起動する前に、 sleep 10s して、10秒またせて対処しました。
仕上げ
FFserver の ACLの変更
FFserver の Feed URL などを、推定されずらいようにハッシュ文字列を使用する。