ずいぶんほったらかしにしていたけれども、ラズパイの電源を簡単に落とせる方法を実現したので紹介する。
今日はラズパイ側の設定。
簡単な説明
Raspberry piには電源ボタンがなく、USBで給電を開始すると電源ONされる。
シャットダウンをするにはshutdownコマンドを実行しなければならない。
SSHでログインかモニタとキーボードで操作をしなければならない。
面倒
じゃあどうする?
Androidから実行しちゃおう。
AndroidのSSHクライアントの操作は面倒。
どうする?
ソケット通信で何とかしよう
どのようにしたか?
ソケット通信でコマンドを実行する方法はPythonで書いてみた。
Pythonについては素人なので、勉強をしながら書いたから、命名規則とかあっているのかわからない。
あと、python-daemonというライブラリを使用している。
はじめは、最新のPythonを勉強だ!python3系だ!とおもって書いていたのだけれども
このpython-daemonってのは2系でしか動かないみたいで、結局python2系で実行されるように書いた。
ちなみにこのpython-daemonってのは簡単にデーモン化してくれるライブラリ。
実行すれば実行元のプロセスは終了するけれども、デーモン化にしたい処理は子プロセスで生き残って処理が続行されるそうだ。
ソース
こんな感じ
#!/usr/bin/python import socket import os from daemon import daemon import sys ip_addr = '192.168.0.3' def socketmain() : host = socket.gethostbyname(ip_addr) port = 46493 while True: sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind((host,port)) sock.listen(1) (client_sock,client_addr) = sock.accept() connecting(client_sock) client_sock.close() sock.close() def connecting(client_sock): while True: msg = client_sock.recv(1024) msg = msg.rstrip() if len(msg) == 0: #disconnection break else: if (msg == 'please reboot my pi , sir') : os.system('shutdown -r 1' ) sys.exit() elif (msg == 'now ! shutdown my pi!'): os.system('shutdown -h 1') sys.exit() if __name__ == '__main__': with daemon.DaemonContext(): socketmain()
IPアドレスはRaspberry piのIPにして、
ポートは自由に好きなものを、とはいっても競合をしない奴に。
覚えやすく、よろしくさん(46493)にしてみた。
あとはソケット通信で、please reboot my pi , sir や now ! shutdown my pi! の文字列を受け取るとそれぞれのコマンドが実行されるというわけ。
再起動やシャットダウンは一分後に実行されることにした。
ログインしているユーザーにはおそらくブロードキャストで警告メッセージが流れるとおもう。
ラズパイ側の設定
上で紹介したスクリプトでは、shutdownなどのコマンドを実行するので、
スクリプトを実行するユーザーはrootにしておこう。
そして、ユーザーもグループもrootにしておいて、パーミッションは744にしておいた。
だが、素人が作ったスクリプトだ…どんな脆弱性が潜んでいるかわからないのでネットに公開せずに家庭内だけで公開しておく。
もし、ネットに公開するならば実行ユーザーを新しく作って
そのユーザーはvisudoでパスワードなしでshutdownコマンドのみ実行できるように細工をしておくなどの最低限の防衛は必要だろう。
さらには、クライアントとの認証やらなんやらを実装しないと不安で夜も眠れない。
つまり面倒が多いので、お外から接続できるようにするってのは無しにしてLAN内だけでのことにしておく。
そしてpythonコマンドでそのスクリプトを指定して実行しておけば、あとはバックグラウンドで常に接続を待機している状態になる。
クライアント側のアプリはまだ作ってないけれど
$ telnet 192.168.0.3 46493
このコマンドで通信ができるので、文字列を送信したらぶじ再起動できた。
課題は2つ
クライアントを作ること
それからinit.dに登録をして起動時にこのスクリプトが自動起動するようにすること。