LEGOで作るスマートロック　〜「Hey Siri 鍵開けて」を実現する方法 〜

# はじめに

これはLEGOとRaspberry Piで実用的なスマートロックを作り上げる物語です。

スマートロック・システムの全体構成は下図のようになります。図中右上にある塊が、全部LEGOで作られたスマートロックです。

![LEGOスマートロック.005.jpeg](https://qiita-image-store.s3.amazonaws.com/0/26062/bcfc06d3-7c66-749b-494b-c91029c3f376.jpeg)

特徴は、3Dプリンタ不要で、LEGOという比較的誰でも扱えるもので作られたハードウェアであるところ、見た目の野暮ったさと機能のスマートさを兼ね備え、エンジニア心をくすぐるポイント満載なところです。

なお、LEGO (レゴ)、LEGO Boost (ブースト) は LEGO Group (レゴグループ) の登録商標であり、この文書はレゴグループやその日本法人と一切関係はありません。


# コンセプト・機能

次のようなシチュエーションを経験したことはありませんか？

1. 外出先にて、「そういや、鍵、閉めてきたかな？記憶がない…（ソワソワ）」  
2. 朝の通勤にて、駅に到着してみたら「あ、鍵閉め忘れた。戻るか…」   
3. 料理中に「あ、鍵閉め忘れた！でも、いま手が離せない。」   
玄関先で「手は買い物で一杯。ポケットから鍵を出すのが大変。」   
4. 職場にて、夕方「そろそろ子供は家に帰ってきたかな？」   
5. 玄関にて「今日は傘いるかな？」   

今回作るスマートロックは、次の機能でこれらを解決に導きます。

1. **鍵の閉め忘れをSlackに通知してくれる**。**iPhoneで施錠状態を確認できる**。
2. **何処ででもiPhoneから施錠できる**。
3. **「Hey Siri 鍵閉めて（鍵開けて）」で施錠/開錠できる**。
4. **鍵の開閉イベントがiPhoneに通知され、帰宅が分かる**。
5. **LEDの色で天気予報（傘の必要性）を教えてくれる**（ただし、時間の都合で今回は説明省略）。

欲しくなりましたでしょうか？
以下、ムービー多めで機能の詳細と作り方について解説していきます。ハードウェアもソフトウェアもオープンソースとして公開します。


# 免責事項
著者は本記事を掲載するにあたって、その内容、機能等について細心の注意を払っておりますが、内容が正確であるかどうか、安全なものであるか等について保証をするものではなく、何らの責任を負うものではありません。
本記事内容のご利用により、万一、ご利用者様に何らかの不都合や損害が発生したとしても、著者や著者の所属組織（略）は何らの責任を負うものではありません。


# 動作イメージ（静止画・動画）

## Siriにお願いして鍵を開閉

「Hey Siri 鍵開けて」で解錠、「Hey Siri 鍵閉めて」で施錠できます。
（完成して初めてSiriさんにお願いを聞いてもらえたときは少し惚れました。自分に）

![LEGOスマートロック.011.jpeg](https://qiita-image-store.s3.amazonaws.com/0/26062/dd749af2-b0a5-e4f8-6069-63149361e1a1.jpeg)


## HomeKitのボタンで鍵を開閉

HomeKitの鍵ボタンを押すと鍵が開閉します。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">LEGO Smart Lock (HomeKitによる開閉) <a href="https://t.co/KAZW57UawG">https://t.co/KAZW57UawG</a></p>&mdash; gajumarine (@gajumarine) <a href="https://twitter.com/gajumarine/status/1010789700905328640?ref_src=twsrc%5Etfw">2018年6月24日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 


## 屋内側からの開閉

レゴの右下のバーを上げると解錠、下げると施錠します。
実際やってみると、LEGOのアナログな感触と機能性のギャップが楽しいです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">LEGO Smart Lock (バーによる開閉) <a href="https://t.co/uvVdVA4xUC">https://t.co/uvVdVA4xUC</a></p>&mdash; gajumarine (@gajumarine) <a href="https://twitter.com/gajumarine/status/1010789826721824768?ref_src=twsrc%5Etfw">2018年6月24日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

## 屋外側からの開閉

既存の鍵による開閉に干渉しないこともポイントの一つです。
既存の鍵で開閉すると、それに連動してレゴの右下のバーが上下します。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">LEGO Smart Lock (既存の鍵による開閉) <a href="https://t.co/U4uQfJQuPU">https://t.co/U4uQfJQuPU</a></p>&mdash; gajumarine (@gajumarine) <a href="https://twitter.com/gajumarine/status/1010789924809797632?ref_src=twsrc%5Etfw">2018年6月24日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 


# システム構成

本記事の最初にお見せした画像です。

![LEGOスマートロック.005.jpeg](https://qiita-image-store.s3.amazonaws.com/0/26062/bcfc06d3-7c66-749b-494b-c91029c3f376.jpeg)

主な登場人物は、下記です。

- 鍵を操作するためのiPhone（HomeKitやSiri）
- 鍵の閉め忘れの通知先となるSlack
- 主役のLEGOでできたスマートロックのハードウェア
- スマートロックのソフトウェアとhomebridgeが動作するRaspberry Pi
- 屋外からHomeKitを利用できるようにするための、家に置いたままのiOSデバイス（Apple TVやiPadなど）
- （OpenWeatherMapなどの天気予報API（時間の都合で今回は説明省略））

スマートロックのAPIを、Raspberry Pi上にあるhomebridgeがたたくことで、HomeKitの鍵デバイス（LockMechanism）として見えるようになっています。



## 前提条件
時間の都合で、下記のような比較的検索すれば分かる事項に関する説明は省略します。真面目に書くと、10本くらいの記事になってしまうので、前提条件が多めですがご勘弁ください。

- iOSの[HomeKit](https://www.apple.com/jp/ios/home/)の知識
- Raspberry Piのセットアップ（本記事ではStretch Liteを利用しました）
- Raspberry PiへのPython 3のインストール
- Raspberry Piでの[homebridge](https://github.com/nfarina/homebridge)（[HomeKit](https://www.apple.com/jp/ios/home/)デバイスを自作するためのソフトウェア）のインストール、設定、iOSとの連携設定等（参考: [インストール方法](https://qiita.com/sonoisa/items/707692cdb953454ddca7)）
- Slackのボット作成（APIトークンの取得方法。特定チャネルにメッセージを送リます）
- [LEGO Boost](https://www.lego.com/en-us/boost)の知識（一回は組み立てた経験があること。一回とは言わず、遊び倒しましょう。）
- Pythonのアクターモデル [pykka](https://github.com/jodal/pykka) の基礎知識（入門記事: [Python: Pykka でアクターモデルについて学ぶ](https://blog.amedama.jp/entry/2017/03/14/005610)）


# ハードウェア設計・組み立て
## ハードウェア設計

下図はスマートロックの完成写真です。
鍵の開閉状態をサムターンに貼り付けられたブロックの色で認識します。閉じている場合の色は青、開いている場合の色は赤にする必要があります。

![LEGOスマートロック.006.jpeg](https://qiita-image-store.s3.amazonaws.com/0/26062/a33c2408-dbc5-5ca8-7ca8-e923383fae20.jpeg)

無駄な部分がほとんどない作りになっています。あとはお好きなようにデコレーションしてください。


## ハードウェア部品一覧

![LEGOスマートロック.007.jpeg](https://qiita-image-store.s3.amazonaws.com/0/26062/3633f1fc-9d4c-862c-768c-86a0f9aef436.jpeg)

モーターと色センサー（左下のケーブルが付いた部品）と、右上の白い塊（Move Hub）は[LEGO Boost](https://www.lego.com/en-us/boost)の部品です。
他のLEGOブロックは、https://www.brickers.jp などのお店で注文することができます（在庫があれば）。
他にもいいお店があればぜひ教えてください。

スマートロックの実用には下記も必要ですが、特に目新しいことはないので説明は省略します。

- ドアにLEGOの基礎板を貼り付けるための磁石シート（私は https://www.amazon.co.jp/dp/B007TPF1WG を使いました）
- LEGO Boostを常時動かし続けるための9V電源（私は、秋月電子から購入した9V電源と、[単四ハイパーダミー電池](http://www.geocities.jp/moco7jp/JASOBI.HTM)を利用しました。）


## 組み立て映像（8倍速）

スマートロックの組み立て映像です。全てLEGOでできている証拠でもあります。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">LEGO Smart Lockの組み立て方法 <a href="https://t.co/nBo7NlSmQj">https://t.co/nBo7NlSmQj</a></p>&mdash; gajumarine (@gajumarine) <a href="https://twitter.com/gajumarine/status/1010785470131855360?ref_src=twsrc%5Etfw">2018年6月24日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

途中、間違ったり、手戻ったり、迷ったりしていますが、それはご愛嬌で。。


# ソフトウェア設計・実装
## ソフトウェア設計

下図にスマートロックのソフトウェア・コンポーネントの概略図を示します。
これは後述する legolocker.py の中身を表現したものになります。

![LEGOスマートロック.009.jpeg](https://qiita-image-store.s3.amazonaws.com/0/26062/0c95c30d-e984-5790-1261-98da4180cf37.jpeg)

ハードウェアは並列動作するため、ソフトウェアでも並列処理が必要ですが、今回は、[pykka](https://github.com/jodal/pykka)のアクターモデルを用いて並列処理を表現するようにしました（Scala好きなので）。アクターは簡単に言えばメッセージキュー付きスレッドです。この図の矢印が概ねメッセージです。

図中最上段のハードウェアのイベントやWeb APIからのリクエストをトリガーに、ソフトウェアの状態遷移が起こります。次に、ハードウェアの物理的変化やSlackへの通知が連鎖して起こるという仕組みになっています。

図中の実線は同期呼び出し、点線は非同期呼び出しを表しています（ハード部分は少し不正確かもしれません）。


## ソフトウェア実装

ソースコードはgithubに一式を置きました。

https://github.com/sonoisa/lego_smart_lock

### ソースコードの概要

- legolocker.py: スマートロックのメインプログラムです。
- env.sh: 環境変数の設定スクリプトの雛形です。ここに必須環境変数を定義するといいでしょう。
- start_locker.sh: プログラムを起動するスクリプトです。
- stop_locker.sh: プログラムを停止するスクリプトです。
- pyb00st: 改造版 [pyb00st](https://github.com/JorgePe/pyb00st) です。改造内容は次の通りです。
    - 周囲にあるLEGO Boostを検索できるようにした（MACアドレス引数を不要にした）。
    - モーター停止時に、モーターにかかる電圧がゼロになるようにした。
    - 状態変化イベントハンドラを差し込めるようにした。

### 注意点

実行の前に下記の環境変数が設定されている必要があります。例えば、env.shの中でexportするのがいいでしょう。

- SLACK_TOKEN: SlackボットのAPIトークン（例:"xoxb-..."）
- SLACK_BOT_NAME: Slackボットの名前（例:"keybot"）
- SLACK_REMINDER_CHANNEL: 鍵閉め忘れ通知先チャネル名（例:"#alert"）
- API_SECURE_KEY: スマートロックAPIのセキュアキー（例:セキュアなランダムURL文字列）
- API_PORT: スマートロックAPIのポート番号（例:"3000"）

なお、プログラムは、サムターンが縦長のとき（色は赤）解錠、右に回転して横長（色は青）のとき施錠となる鍵用に作ってあります。


# LEGOでできたスマートロックの利用方法

## LEGOでできたスマートロックの起動

起動前に、サムターンやLEGOが次の物理的状態になるようにします。

- サムターンの位置を横長（閉じている状態、青ブロックが右、赤ブロックが下）にする。
- スマートロックの右下にあるバーの位置を下端（閉じている状態）にする。
- サムターンを回すギアの位置を、ギアから垂直に出た棒が、サムターンの左上と右下に接する位置にする（力は加わらないようにする）。

上記の環境変数 `SLACK_TOKEN, SLACK_BOT_NAME, SLACK_REMINDER_CHANNEL, API_SECURE_KEY, API_PORT` が定義された状態で、`start_locker.sh` を実行し、10秒以内にLEGO BoostのMove Hubの電源ボタンを押します。
うまくRaspberry Piとペアリングされれば、Move HubのLEDが青に点灯します。


## homebridgeへのスマートロック登録方法

homebridgeの[homebridge-cmdaccessory](https://www.npmjs.com/package/homebridge-cmdaccessory)プラグインをインストールし、下記のように設定すると、スマートロックがHomeKitの鍵デバイス（LockMechanism）として認識されるようになります。
なお、{APIサーバ}はスマートロックのAPIが動作しているサーバのIP、{API_PORT}と{API_SECURE_KEY}はそれぞれ同名の環境変数の値に置き換えてください。

```json:config.json
{
    ...省略...

    "platforms": [{
        "platform": "cmdAccessory",
        "name": "CMD Switch",
        "switches": [{
            "name": "鍵（玄関）",
            "on_cmd": "curl -sS -X PUT http://{APIサーバ}:{API_PORT}/api/{API_SECURE_KEY}/key/CLOSED",
            "off_cmd": "curl -sS -X PUT http://{APIサーバ}:{API_PORT}/api/{API_SECURE_KEY}/key/OPEN",
            "state_cmd": "curl -sS http://{APIサーバ}:{API_PORT}/api/{API_SECURE_KEY}/key | grep 'CLOSED'",
            "polling": true,
            "interval": 3,
            "manufacturer": "Isao Sonobe",
            "type": "LockMechanism"
        }]
    }]
}
```

これでhomebridgeを起動し、iOSにhomebridgeを登録すれば、iPhone等からLEGOでできたスマートロックをコントロールできるようになります。


# 最後に

長い記事をお読みいただき、ありがとうございました。
もしご興味のある人が多そうであれば（いいねが多かったら）、もう少し詳細を書こうと思います。