Unity WebGL x IoT ~スマートロックをつくったよ~ ラズパイ編


はじめに

 とある事情があり、スマートロックほしい。スマートロック超便利。作ろう。となったので作ったのですが。色々な罠を踏み抜いたのでそれを書いていきます。なお、大量に罠を踏み抜いた理由は以下のような変な構成にしたからです。(この構成にした理由は、上からの「早く作りなさい」という圧力と、私のスキル)

さて、最終回の今回はラズパイ編です。

スマートロックを組む

 それでは、ハード側に移ります。こちらのほうは、すんなりと行きました。参考資料をもとにすれば作れるはずです。
※参考資料

OSをラズパイに入れる

 
 公式ページにOSとしてNOOBSとRaspbianの二種類がありますがどちらでもいいのでダウンロードします。NOOBSのほうが簡単と聞きましたが、私はRaspbianのいろいろ入ったものを選びました。(noobが気にくわなかった)
 そして、公式がおすすめしているbalenaEtcherというソフトでSDカードにOSを入れました。むちゃくちゃ簡単だった。

SDカードの罠

 SDカードは、容量によってフォーマット方法が違い、64GB以上のものがされているフォーマット方法はラズパイは使えません。SD Card Formatterを使ってFTA32にフォーマットする必要があります。

イメージの罠

 どこかのサイトに.zipのままOSイメージを移した方がいいと書いてあった気がしますが、失敗しました。ちゃんと解凍してからSDカードに移しましょう。

鍵を開けるプログラム

 正直、ここに書くほどの内容はなく、参考資料のもので十分なのですが、ややトリッキーなことをした気がするのでそこだけ書きます。仕様は以下。

  • 鍵を開けたら30秒後に閉める
  • 開けている途中でまた鍵を開けるのなら、そこから30秒後に閉まる

 これを以下のコードで実現しました。

#MQTTでメッセージが来たときに実行する関数
def on_message(cliant,userdata,msg):
    openrequest.append("Open")
    time.sleep(30)
    openrequest.pop()

#常にスレッドでループしている関数
def state_check_roop(gp_out):
    global state
    while True:
        if len(openrequest) != 0 and state == False :
            door_open(gp_out)
            state = True
        elif len(openrequest) == 0 and state == True :
            door_close(gp_out)
            state = False

        time.sleep(1)

 解説をすると、上の関数でメッセージを受け取ったら30秒間openrequestという配列に要素を追加して、リクエストを貯めます。
 下の関数は、鍵を開けるべきか、閉めるべきか判断しています。stateは今、鍵が開いているかです。

起動時に自動実行するようにする

 不測の事態が起きて落ちたときに、自動起動するようにしていないと、私以外の人しか中に居なかったら閉じ込められてしまい、かなりまずいです。ということでラズパイの起動時に自動的に起動するようにしました。

 いくつか起動時に自動実行する方法があるのですが、私はスマートロックのプログラムをサービス化し、自動実行するように登録するという方法をとりました。その際、参考になった資料は以下です。

サービスを作成する

 最初にスマートロックのプログラム(ここではmain.pyとしておきます)を/opt/以下に置き、また、main.pyを実行するシェルのファイルを同じところに置きます。この場所に置く理由は、RasPi のプログラムを自動起動に!その2 systemd 編より、

Python プログラムも単一プログラムもどこに作ろうとしてる?!
ここ /opt の下がいいよ!
なぜなら,Filesystem Hierarchy Standardで決まっているので,起動時にマウントされていることが保証されているからなんですって💛
ということで,システム固有のプログラムというかディストリビュータ以外のサードベンダープログラムは /opt の下に置くのがまぁ正しいのです ^^

 その際のシェルファイルは以下の通りです。pythonを実行するだけです。

AutoStart.sh
#!/bin/sh
/usr/bin/env python3 /opt/main.py

そして、スマートロックのプログラムをサービス化します。.serviceファイルを/etc/systemd/systemに作ります。今回は以下のように作りました。

SmartLock.service
[Unit]
Description=SmartLock
After=network-online.target sockets.target network.target

[Service]
ExecStart=/opt/AutoStart.sh
Restart=no
Type=simple

[Install]
WantedBy=multi-user.target

 それぞれの部分の解説です。

[Unit]

  • Description ・・・ このサービスの名前をどうするか
  • After ・・・ どのサービスよりに起動しなければならないか
  • Before ・・・ どのサービスよりに起動しなければならないか

なお、After、Before間違って紹介しているところがあったので注意です。

[Service]

  • ExecStart ・・・ 実行するコマンドライン
  • Restart ・・・ 実行に失敗した時、再起動はどうするか
  • Type ・・・ サービスの種類

[Install]

  • WantedBy ・・・ どのレベルで実行するか

 これはよくわからなかったのですが、これをつけないと自動実行できません。

正常に自動起動するようにする

 この作成したサービスを自動実行するようにします。以下のコマンドでサービスを自動実行するサービスとして登録されます。

$ sudo systemctl enable SmartLock

 以下のコマンドで登録したサービスを有効化できます。

$ sudo systemctl start SmartLock

 以下のコマンドでサービスの死活状況を確認できます。

$ sudo systemctl status SmartLock

 最後に以下のコマンドでサービスを止めれます。

$ sudo systemctl stop SmartLock

 では、実際に再起動して正常に動作をするか確かめましょう。なお、失敗した際のログのみかたは以下の通りです。

$ journalctl

しかし、これではログが大量に出すぎるのでgrepとかで必要なものだけに絞ります。

$ journalctl | grep SmartLock

なお、私の場合はどうやっても「ネットワークが接続されていません」というエラーが出たので、main.pyで開始を少々待つようにしたところうまくいきました。

ハードを(無理やり)組む

 qiitaなのであまりハード側を長々書くべきではないので手短に書きます。

材料

 やったことと言えば、鍵を回すサーボモーターを固定するものを製作。鍵を回すところと合うような部品を製作、サーボモーターに取り付けといった具合です。
 加工はサーボモーターのための穴は高温熱源(はんだごて)で溶かして開けて(危険なので真似しないでください)、その他はアクリルカッターで切りました。微調整は紙やすり。
 結果は以下のようになりました。

感想

 正直ハードのほうを作るのが大変だったけどむちゃくちゃ便利になったからすべてよし!

シリーズ一覧