Raspberry Piでスマートロック作ってみた

# はじめに
大学の授業の最終課題でRaspberry Pi3 modelAを使ったスマートロックを作ったのでまとめていきます。作った理由としては鞄からいちいち鍵を出すのが面倒というのと、家族友人が泊まりに来た際に鍵を共有したかったからです。
初学者のため拙い説明が多くなるかと思いますがご了承ください。
# 使ったもの
1. ハード
    - Raspberry Pi3 modelA
    - サーボモータ（SG92R）
    - タミヤ　ユニバーサルアームセット
    - 結束バンド
    - その他テープ等
1. ソフト
    - Python3
    - Bolt for Python
    - iOS　Shortcut
1. 外部サービス
    - Slack
# Slack APIの設定
今回はSlackに入力された文章をトリガーにラズパイが鍵を操作するようにしています。そのため、まずはラズパイでSlackを監視できるようにSlackアプリを作ります。
[Bolt for Pythonの入門ガイド](https://slack.dev/bolt-python/ja-jp/tutorial/getting-started)が日本語でアップされているのでそれに沿って進めて行きます。メッセージをリッスンして応答するの項目まで進めてください。

# ラズパイに実装していく
次はラズパイを使っていきます。適当なディレクトリを作成し下記のプログラムを書きます。１つ目はBolt for Pythonを使ったSlackbotのコードです。
```:app.py
import os
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
from servo_config import unlock,lock

# ボットトークンとソケットモードハンドラーを使ってアプリを初期化します
app = App(token=os.environ.get("SLACK_BOT_TOKEN"))


# メンションされたとき
@app.event("app_mention")
def message_mention(say):
    say(f"メンションしても何も出えへんで")


@app.message("鍵開けて")
def order_Key_Open(say):
    say(f"家の鍵開けるで")
    unlock()

@app.message("鍵閉めて")
def order_Key_Lock(say):
    say(f"家の鍵閉めるで")
    lock()


# アプリを起動します
if __name__ == "__main__":
    SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
```
「鍵開けて」と「鍵閉めて」というメッセージに反応します。
次にサーボ制御用のコードです。
```:servo_config.py
import RPi.GPIO as GPIO
import time

# BOARDでpin指定
GPIO.setmode(GPIO.BOARD)

# 制御パルスの出力
gp_out = 33
GPIO.setup(gp_out, GPIO.OUT)

servo = GPIO.PWM(gp_out, 50)
servo.start(0)

def unlock():  # 解錠

    print("open")
    
    GPIO.setup(gp_out, GPIO.OUT)
    time.sleep(0.5)

    servo.ChangeDutyCycle(7.25)
    time.sleep(0.5)

    servo.ChangeDutyCycle(12)
    time.sleep(0.5)

    servo.ChangeDutyCycle(7.25)
    time.sleep(0.5)

    GPIO.cleanup(gp_out)


def lock():  # 施錠

    print("close")

    GPIO.setup(gp_out, GPIO.OUT)
    time.sleep(0.5)

    servo.ChangeDutyCycle(7.25)
    time.sleep(0.5)

    servo.ChangeDutyCycle(2.5)
    time.sleep(0.5)

    servo.ChangeDutyCycle(7.25)
    time.sleep(0.5)

    GPIO.cleanup(gp_out)
```

これでテストしてみましょう。GPIOにサーボを繋ぎます。
サーボの信号線は33番に繋ぐようにしています。
```
python3 app.py
```
Slackでどちらもメッセージを打って90度回転し戻ればOKです。サーボが思うように動かないときはraspi-configでremote-gpioを一度オンオフ切り替えるとうまくいくかもしれません。筆者環境はこれで動きます。
# 設置
サーボを一度ラズパイから外してドアに設置しましょう。
まずはサムターンを回す機構です。写真のような形になるようアームセットを加工し、結束バンドで止めます。この形であれば本来の鍵での操作を邪魔しません。
![IMG_5032 (1).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680953/c7762f3b-58a2-95da-79d2-725307675d93.jpeg)

そしてサーボをドアに固定できるようにアームセット等をくっつけていきます。サムターン周りの形状は人それぞれなので各々合うように工夫してください。I字型のサムターンの場合なんの心配も無いのですが筆者宅はなんと半月型になっており、なんの加工もしないと回すことができません。なので余っているアームセットを切ってテープで巻き付けました。
![IMG_5129.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680953/a0d11ffc-b684-26ee-3e1b-d2d3497ed0f8.png)


ラズパイも固定しましょう。筆者はハンズで適当なツールボックスを買い、給電用USBケーブルの穴を開けて中にすべてを入れ、フックに掛けています。
![IMG_0293 (1).jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680953/e4e96d77-3f19-1d3c-14a3-aca894877e34.jpeg)

```
nohup python3 app.py
```
で起動するとSSHを終了してもプログラムが動き続けるので、常時稼働させる際には**nohup**を付けましょう。
# iOS Shortcutで動かせるようにしよう
このままではSlackにいちいちメッセージを送らなければないため面倒です。少なくともスマホからすぐ操作できるようにしたいです。なので筆者はiPhoneユーザーなのでiOS Shortcutで簡単に操作できるようにします。
SlackAPIを開いてもう一つ新しいアプリを作ります。最初同様に作り、OAuth & Permissionsでchat:writeのスコープを追加してインストールします。
次にiOS Shortcutの設定です。ショートカットアプリを開いて＋をタップ。アクションを追加でURLを検索し追加。
```
https://slack.com/api/chat.postMessage
```
を入力。次にURLの内容を取得を追加する。
- 方法：POST
ヘッダに
- Authorization：Bearer xoxb-（先程作ったボットトークン）
- Content-Type：application/json
- 本文を要求：JSON
- as_user：true
- channel：test
- text：（鍵閉めてor開けて）
textの欄に入力した内容がSlackに送信される内容になります。
解錠用と施錠用ができたらテストしてみましょう。無事にできたら完成です。

# 終わりに
改善点は
- 今のステータスがわからない
- 給電ケーブルが見窄らしい
- 小型化
- 鍵の共有を考えるとユーザー認証機能を付けたい
- 再起動したら自動起動させたい
etc

また制作中の失敗も多くあり
- amazonで買った互換サーボが不良品
- サーボ用の外部電源が結果として不要だった
- 磁石で固定しようとしたが動いてしまって無理だった。
- 見切り発車で買った固定用の金具が使えなかった。
etc

そんなところでしょうか。近いうちに改善点を直したものを作りたいと思います。お付き合いいただきありがとうございました。質問アドバイス等あればお願いいたします。

# 参考資料
https://qiita.com/dainbe/items/1b3a08b59d81afbefc4d

https://qiita.com/undo0530/items/669b6ee6b2277ea64b33