ラズパイでスマートロック【改善版】

[Raspberry Piで自宅の鍵をオートロック化してみた](https://qiita.com/12405/items/be2886618b7417e64a02)の続編です。ハード的にはほぼ変わりませんが、HTTP通信はオーバーヘッドが大きくて無駄が多いので、D-busで作り直しました。
D-busはLinuxのプロセス間通信の1つで、初めて使ったのですが、非常に便利で、パフォーマンスも大幅に改善されました。

# 前回までの反省
* 距離センサーの測定を高速(0.5秒おき)で行うと、たまに測定が狂う。(TRIGが一瞬で立って、短距離と誤測定する)。SR04上のICがついて来れないのかなと思いました。
* HTTP通信のオーバーヘッドが無駄。TCPコネクションが無駄。FastAPIが無駄。
* RFIDセンサーを0.1秒ごとに初期化して読み取るため、計算が重い


また、鍵を自室に忘れて部屋を出ると、閉め出されるので、ポカヨケとして、鍵を取ったら鍵が開くようにしました。

<iframe width="560" height="315" src="https://www.youtube.com/embed/3ktdjnTYWoE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# パフォーマンスの変化
アクチュエータやセンサーをマイクロサービスとして、設計するという発想は非常に気に入っているため、HTTP通信をD-busに変更して、再設計しました。

今回の変更による使用リソースの変化です。もともと、前回のシステムでは、RFIDの読み取り(PID=2087)が、26%も食っていたのですが、2%まで落ちました(PID=836)。
**%Cpuもload averageもMemもすべて改善しています！！**
##Before
![Screen Shot 2021-08-07 at 22.19.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101736/faa22932-3dc1-614a-948d-c9f99811d69c.png)

##After
![Screen Shot 2021-08-07 at 22.27.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101736/33ce481d-cf18-1a88-499f-af9d6f48d0b8.png)

# 方式設計
それでは具体的な設計についてお話しましょう。
## 状態遷移
前回とほぼ同じです。ポカヨケで、鍵を外したら、鍵が開くようにします。
![State.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101736/a28dcfcf-127f-63d7-b46f-8ab6ff7165c4.png)
## クラス設計
各モジュールをD-busサーバーとして立て、オートロックシステム本体は、D-busクライアントとして、制御します。
前回と同様にStateパターンで書いていますが、前回と異なるのは、定期的に状態を更新する関数を呼び出すのではなく、wait_for_next_state関数にて、イベントループを回すことで、処理のオーバーヘッドを減らしています。
![auto_lock.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101736/d76289c9-9c77-1292-cc65-66e638db8700.png)

# コーディング
サーバーは[こちら](https://github.com/kim-tom/dbus_server)にあります。
オートロックシステムは[こちら](https://github.com/kim-tom/auto_lock_dbus)にあります。

# デプロイメント
Sessionバスを使用するため、`loginctl enable linger`コマンドによってブート時やログアウトした後でも、daemonとして動作するようにします。[Starting systemd services sharing a session D-Bus on headless system](https://serverfault.com/questions/892465/starting-systemd-services-sharing-a-session-d-bus-on-headless-system)が非常に参考になりました。

上のリンクを参考にして、以下のように.serviceファイルを作成し、`systemctl --user enable auto_lock_dbus`でデプロイ完了です。

```systemd:/usr/lib/systemd/user/rc522_dbus.service
[Unit]
Description = RC522
Requires=dbus.socket

[Service]
WorkingDirectory = /home/baki/development/dbus_server
ExecStart=/home/baki/.pyenv/shims/python3 -u rc522_server.py
Restart=always
Type=simple
EnvironmentFile=/etc/sysconfig/dbus_env

[Install]
WantedBy=default.target
```
```systemd:/usr/lib/systemd/user/ds3225_dbus.service
[Unit]
Description = DS3225
Requires=dbus.socket

[Service]
WorkingDirectory = /home/baki/development/dbus_server
ExecStart=/home/baki/.pyenv/shims/python3 -u ds3225_server.py
Restart=always
Type=simple
EnvironmentFile=/etc/sysconfig/dbus_env

[Install]
WantedBy=default.target
```

```systemd:/usr/lib/systemd/user/switch_dbus.service
[Unit]
Description = SWITCH
Requires=dbus.socket

[Service]
WorkingDirectory = /home/baki/development/dbus_server
ExecStart=/home/baki/.pyenv/shims/python3 -u switch_server.py
Restart=always
Type=simple
EnvironmentFile=/etc/sysconfig/dbus_env

[Install]
WantedBy=default.target
```

```systemd:/usr/lib/systemd/user/line_dbus.service
[Unit]
Description = LINE
Requires=dbus.socket

[Service]
WorkingDirectory = /home/baki/development/dbus_server
ExecStart=/home/baki/.pyenv/shims/python3 -u LINE_server.py
Restart=always
Type=simple
EnvironmentFile=/etc/sysconfig/dbus_env

[Install]
WantedBy=default.target
```

```systemd:/usr/lib/systemd/user/auto_lock_dbus.service
[Unit]
Description = AUTO_LOCK
After=ds3225_dbus.service rc522_dbus.service switch_dbus.service line_dbus.service
Requires=dbus.socket ds3225_dbus.service rc522_dbus.service switch_dbus.service line_dbus.service

[Service]
WorkingDirectory = /home/baki/development/auto_lock_dbus
ExecStart=/home/baki/.pyenv/shims/python3 -u auto_lock.py
Restart=always
Type=simple
EnvironmentFile=/etc/sysconfig/dbus_env

[Install]
WantedBy=default.target
```

# テスト
dbus-monitorというコマンドがあって、D-busの通信を覗き見る事ができます。RC522ServerはRFIDを検知すると、シグナルを発生するので、RC522Server実行中に、以下のコマンドを実行すると、D-busにRFIDが流れていることが確認できます。

```
dbus-monitor "type='signal',sender='jp.kimura.RC522Service',interface='jp.kimura.RC522'"
```
# 反省
今回、dbus-pythonというライブラリを使用したのですが、このライブラリはイベントループにGLibを使用します。GLibはPyPyでインストールすると依存関係を解決できず自前でビルドする必要があり、非常に面倒だったので、aptでインストールして、システムのPythonで動かすハメになりました。
しかし、後から気がついたのですが、DBus-Nextというライブラリは、asyncioに対応しているみたいなので、そっちのほうが良かったかもしれません。

# 参考文献
[DBus ことはじめ](https://qiita.com/byuu/items/c600366b9c138f639863)
[D-Bus のはなし](https://www.silex.jp/blog/wireless/2017/01/d-bus.html)
[GitHub dbus-python/examples/](https://github.com/freedesktop/dbus-python/tree/master/examples)
[Starting systemd services sharing a session D-Bus on headless system
](https://serverfault.com/questions/892465/starting-systemd-services-sharing-a-session-d-bus-on-headless-system)