IoTなスマートロックシステムをreact-native、アリババクラウド、3Dプリンターで作った

3年くらい前少し流行ったスマートロックシステムを自作しました。結構前に作ったやつをようやく記事にします。

## 作ったもの
**スマホアプリ**と**鍵開けデバイス**を作成しました。アプリ名は**Genkan**です。**ダサい。**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131581/dfa452c9-6f51-0554-94f2-693e6570228e.png)

以下のリンクはデモ動画です。Qiitaに動画直接埋め込みたい。
<blockquote class="twitter-tweet" data-lang="en"><p lang="und" dir="ltr"><a href="https://t.co/StGqUugCIa">pic.twitter.com/StGqUugCIa</a></p>&mdash; asmsuechan (@suenaga_ryota) <a href="https://twitter.com/suenaga_ryota/status/1066274456534888448?ref_src=twsrc%5Etfw">November 24, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


## 実現したかったこと
最近入居したアパートの鍵がちょっと大きめで扱いにくさを感じていたので**スマホからドアを開けられたら良さそう**だなと思っていたのが始まりです。

## 諸々のコスト
期間: 2週間くらい
費用: **20000円**程度

|項目|値段(円)|
|:-:|:-:|
|RPi Zero wh|4000|
|サーボモーター|500|
|3Dプリント料金|**15000**|
|合計|19500|

パーツはだいたいアキバの秋月か千石電商で揃えました。

## 既製品
これらを実現するために、まずどんなものが売っているのかを調べました。

[Akerun](https://akerun.com/)
[Qrio](https://qrio.me/)
[gogogate2](https://www.gogogate.com/)

概ね以下のように鍵のツマミ(**サムターン**)を物理的に回す装置を扉に貼り付けてスマホで操作するタイプです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131581/16f0d1ea-1af3-83c8-ee3d-27d70f5f0bd6.png)

こんな感じをイメージしながら作りました。

## 先人の知恵
2015年の記事です。ｶｯｹｴ。別記事のコメント欄で大阪の商社さんから声がかかっていて夢がありますね。
https://qiita.com/toshi-saito/items/ef7fd9a2154f7db92831

2017年末の記事です。しっかり作っていてめちゃくちゃすごい。
https://ehbtj.com/electronics/diy-smart-lock/

2017年5月の記事です。スマホでsshしてRPiにログインする方法なんてのもあるんですね。
https://www.indetail.co.jp/blog/170519/

## 技術
以下の技術等を使ってシステムを設計/製作しました。

* MQTT
* RPi zero
* react-native
* golang
* CI
* 3Dプリンター

### 構成
なるべく管理する対象を減らしたいので、シンプルにデバイスとスマホの間でMQTTのやりとりをするだけのものにしました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131581/ee8bf081-2de8-3b87-d743-fcafff1fa376.png)

最初の設計はこんな感じにノートに書いていました。
![IMG_20181124_193649.jpg](https://qiita-image-store.s3.amazonaws.com/0/131581/44059be7-c867-e7a3-65ba-392f30651663.jpeg)

玄関にコンセントがあるので**電源はケーブル這わせてコンセントから取る**ことにしました。

### MQTT
MQTTとは、ソケット通信を開きっぱなしにして**双方向の通信**を行うためのプロトコルです。通信の中間に**MQTTブローカー**というサーバーを置いて双方向の通信を実現します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131581/d87c8e82-10a9-c370-3cf0-dc0d446ef9b9.png)

そしてこの　MQTTによりデバイスへの**push型の通信**が可能になります。
詳しくは時雨堂さんの https://gist.github.com/voluntas/89000a06a7b79f1230ab が非常に分かりやすいです。

### Alibaba Cloud IoT Platform
MQTTブローカーには**Alibaba Cloud IoT Platform**を使用しました。

IoT Platformでは**(1) デバイス管理**や**(2)MQTTでpublish/subscribe**などが可能です。

MQTTをsubscribe/publishしてる様子はこんな感じで見ることができます。
![20180721154433.png](https://qiita-image-store.s3.amazonaws.com/0/131581/582e86c6-695a-44f3-c304-d62294741b15.png)


もう少し詳しい使い方については[IoT Platformを日本版Alibaba Cloudで使う](https://asmsuechan.hatenablog.com/entry/2018/07/23/130822)をご覧ください。

### react-native
最初のアプリUIです。最終版は上の画像です。コンポーネントキットは[native-base](https://nativebase.io/)を使用しました。
![Screenshot_20180322-163402.png](https://qiita-image-store.s3.amazonaws.com/0/131581/73235a0c-dc42-7e26-414d-0863e0a43687.png)

アプリからデバイスを操作するという要件なので、サクッとreact-nativeでスマホアプリを作りました。**ただMQTTでイベントを発生させるだけのアプリ**です。

一番有名そうな[eclipseのjsライブラリ](https://github.com/eclipse/paho.mqtt.javascript)が**localStorageに依存**していてそのまま使うことができないので別のものを使う必要があって、探した結果[react-native-mqtt](https://github.com/Introvertuous/react_native_mqtt)を見つけたのでこれを使いました。

使用したreact-native-mqttはpaho.mqtt.javascriptをラップしているので基本的な使い方は同じです。

ちょっとハマったところ

* MQTTブローカーのポートは**websocket**のものを使う(https://github.com/eclipse/paho.mqtt.javascript/issues/99#issuecomment-268972273)
* client.connectのオプションに`useTTL: true`を指定する

`client.connect({ onSuccess: this.onConnect, userName: userName, password: password, useSSL: true })`

### golang
**クロスコンパイル**環境が優秀だしリリースもGitHub Releasesにバイナリ投げるだけで済むのでgolangを使いました。

MQTT環境だと**Erlang**がよく使われるらしいのですが、そんなにデバイスが増える予定もないのでやめました。

まず、golangでサーボモーターを回します。golangからRPiのGPIOを操作するために[この記事](https://qiita.com/hogesuke_1/items/3a5f17a0854f67b2b3b8)を参考にして[gobot](https://github.com/hybridgroup/gobot) を使いました。

このgobotは[標準](https://gobot.io/documentation/platforms/mqtt/)でMQTTをサポートしています。サイコー。

公式ドキュメントの通りにやれば簡単にsubscribeできます。

### TravisCI
リリースは**自動**でやって欲しいので**TravisCI**に任せます。

作るデバイスは扉に固定するものなので**インターネット越しにデプロイ**できるようになりたいです。ですので**TravisCI**から自動でGitHubReleasesにリリースするようにします。

![](https://d2mxuefqeaa7sj.cloudfront.net/s_2CD15232B26FA49E71BC037274B2288957E34458216CEE5CA30C845C1C7EB08D_1521619398293_image.png)

以下のようなフローでリリースできるようにしました。

    $ git tag v_1.0.0
    $ git commit -m "Bump v1.0.0"
    $ git push origin v_1.0.0

GitHub Releasesへのリリースは[この記事](https://astj.hatenablog.com/entry/2016/11/03/202101)を参考にしました。

RPiの上には`updateManager`というプロセスを立てて、`genkan/update`をsubscribeします。TravisCIからリリースされたバージョンをpayloadに包んで`genkan/update`に投げます。

このTravisCIからpublishするプログラムが[pushNewVersion.go](https://github.com/asmsuechan/genkan_device/blob/master/deployment/pushNewVersion.go)です。TravisCIのジョブ上でgo buildして実行します。

新しいバージョンを受け取ったら、`exec.Command().Run()`で`./updater.sh`を実行します。このupdater.shは新しいバージョンの.tar.gzをダウンロード、解凍して既存のプロセスをkillして新しいバイナリを起動します。

### ケースを3Dプリント
一番最初、**市販のタッパーに無理くり穴開けて**プロトタイプを作ったのですがさすがにしんどかったので、イケるんちゃうかと思ってモデリングから3Dプリントまでやってみました。

![IMG_20180318_144545.jpg](https://qiita-image-store.s3.amazonaws.com/0/131581/bd8444b4-ab0c-06da-a9ee-f577f8ca095c.jpeg)

DMM.AKIBAでイカしたケースを3Dプリントしました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131581/5acc4e5c-caef-b06e-b0ad-a9bef318d8c5.png)

一番下の直方体がサムターンを回すツマミ部分です。印刷には1セット3時間くらいかかったような気がします。
![IMG_20180322_204956.jpg](https://qiita-image-store.s3.amazonaws.com/0/131581/8caaed92-bb3e-a55c-d607-d99099bc24c0.jpeg)

### BLE
インターネット経由のMQTTが動いたので**BLE**で動くようにもしたのですが、**サーボモーターとBLEの同時使用にRPiが耐えられなくてraspbianが再起動してしまう**ので結局インターネット経由でしか使えませんでした。でもさほど遅延はなかったです。

## まとめ
3Dプリント代が高すぎた・・・20000円はしんどい。

自作はめちゃくちゃ楽しかったのですが、鍵持たずに外に出てデバイスが死ぬと締め出されて大変(**一回やった**)なので、**本当にスマートロックシステムが欲しかったら大人しく買いましょう！**私は結局Qrioを使っています。