Qrioスマートロックがサービス終了したのでESP32で乗っ取る

# おおQrio! サ終してしまうとは何事だ

それはある春の日のこと。

> ※本メールはQrio Smart Lockのオーナー及び、ゲストアカウントへの登録情報に基づき配信しております。
> 重要なお知らせのため、メール配信をご希望されていない方へもお送りしています。
> 
> 
> ------------------------------------------------------------ 
> お客様各位 
> 
> 平素は格別のご高配を賜り、厚く御礼申し上げます。
> 
> 弊社にて販売しておりました『Qrio Smart Lock（Q-SL1）』のサービス終了について、ご連絡させていただきます。
> 
> 2015年の発売開始以降、多くのユーザー様にご愛顧いただいておりましたが、最終出荷より5年が経過し、買い切り型商品のためサービスの維持が難しくなってきております。
> つきましては、誠に勝手ながら、旧製品である『Qrio Smart Lock（Q-SL1）』のサービスを終了させていただくことになりました。
> 
> ご利用中のお客様には心より感謝申し上げますとともに、何とぞご理解いただけますようお願い申し上げます。


よろしい、ならば乗っ取りだ。

さぁ諸君、Key[^1]を作るぞ。

[^1]: 正しくは「錠」。

https://www.itmedia.co.jp/news/articles/2305/17/news113.html

# 警察: お前の要求はなんだ！？

- Qrioのファームウェアを[bakueikozo/qriohack](https://github.com/bakueikozo/qriohack)を元に書き換える
- 書き換えたQrioをESP32で制御
- Qrio本体は開腹しない
- QrioとESP32の間は、有線シリアルで通信（BLEは使わない）
- ドアが開いているか閉まっているかをリードスイッチで検出
- ドアの外側にNFCリーダを設置、Suicaにより解錠
- homebridgeと連携し、iPhoneの「ホーム」アプリからも操作
- ドア内側にスイッチを設置し、スイッチに触れることでの解錠・施錠もする
- ドア閉鎖時は自動で施錠
- Qrioは外部から電源供給（お高いカメラ用電池は使わない）

![ponchi.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204320/bc42bdf1-40af-75d0-3bdb-da2a816fe9b7.jpeg)

# ITの人: それは要件だ！要求を言え！

AppleWatchだけ持って外出したい。
Keyのこと、忘れて下さい。
（でも泥棒怖い）

https://togetter.com/li/1817075

# レシピ

## 材料

| 品名  | 調達方法例 | 参考価格(1台あたり) |
| :---: | :--- | ---: |
| Qrio SmartLock Q-SL1 | ゴミ箱から拾う | 0   |
| ESP32 DevKit | [Amazon.co.jp: ESP32 DEVKIT V1 開発ボード 4M Flash デュアルコアCPU ESP-WROOM-32 NodeMCU (開発ボード) : パソコン・周辺機器](https://www.amazon.co.jp/dp/B0BZK2JJ94) | 800 |
| FPC変換基盤 | [Amazon.co.jp: Moechando 0.5mmピッチシリーズFFC変換基板 適合FPC/FFCフラットケーブル（入荷予定あり） (0.5mmピッチ12ピン) : 産業・研究開発用品](https://www.amazon.co.jp/gp/product/B08YRWTBRR?th=1) | 100 |
| NFCリーダ PN532 | [Amazon.co.jp: Rasbee PN532 NFC RFID V3モジュール フィールド通信近くユーザーキット Androidの携帯電話の通信をサポートしています 並行輸入品 : パソコン・周辺機器](https://www.amazon.co.jp/dp/B01GEZKF22) | 700 |
| リードスイッチ | [ドアセンサースイッチ（リードスイッチ）　ＳＰＳ－３２０: センサ一般 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gP-13371/) | 250 |
| タッチスイッチ | [Amazon.co.jp: オーディオファン 静電容量式タッチスイッチ TTP223 6ケセット 14.5mm×10.5mm×2mm ボタンセルフ ロックモジュール Arduino対応 : 産業・研究開発用品](https://www.amazon.co.jp/dp/B08CZMPDSY) | 100 |
| LED, ブザー, 基板, 配線材料, 箱など | 冷蔵庫の中に余っていますよね？ | 0   |
| **合計** |     | 約2000円 |

上記のamazonのリンクは適当に検索しただけですので、その動作や品質を保証するものではありません。
例によってaliexpressで買えばもっと安くなります。

TTP223タッチスイッチをわざわざ使用している理由は以下です。
- プラケースの中に設置しても指を検出できる（後述の設置写真参照）
- プラケース越しであれば、指が濡れていても安全に操作できる（スマホ対応手袋も可）
- タッチ時に赤く光る
- HかLが出てくるので、プルアップ・プルダウンを自分でしなくていい
- チャタリング対策を自分でしなくていい
- 安価（プッシュスイッチを秋葉原で買うのと金額的に大差がない、大きくて操作しやすいパネル用ボタンスイッチより安い）


## 道具

- Windows PC (Qrioファームウェアの書き換えに使用。macやlinuxでも可能そうだが未検証）
- USB-シリアル (3.3V)

# ハードウェア

![esp32.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204320/34f63b0b-d33e-2cdc-fa60-3314dce741be.jpeg)

## 本体

ESP32に以下を繋げます。

- Qrio通信用UARTケーブル
- リードスイッチ
- タッチスイッチ
- 状態表示LED
- ブザー
- その他お好みで適当なセンサ

Qrio本体には1,2番ピンに5Vを供給してあげます（3番ピンへの3.3Vは不要）。

## 外センサー

PN532はちょうどミンティアケースに収まるサイズですので、ミンティアの空容器にいれてドアの外に貼り付けます。

今回はお好みで温度湿度センサを追加しています。

# ソフトウェア

## Qrio書き換え

こちらで書き換えます。

https://github.com/bakueikozo/qriohack


今回は以下の改造もしました。

- BLE操作の削除
- 状態ポーリング用コマンドを追加
- 入店音は省略（笑）
- UARTを9600bpsに減速

SDKをダウンロードしてきたら、zipを展開し指定の場所にobaqの中身をおきます。
zipを展開したトップディレクトリに戻って、makeを試します。

無事makeが通るようでしたら、Qrioと繋げて9ピンを3.3Vに吊った状態で3.3Vの電源を接続。
通常のQrioは電源を接続して数秒でLEDが緑点灯して音が鳴りますが、プログラミングモードではなにも起きません。
9ピンの3.3Vを外し、make downloadで書き込みます。
書き込みに失敗するとQrioの開腹手術が必要になるとのことで、ドキドキしつつ待ちます。

無事書き込みが成功し起動すると「お気の毒ですが冒険の書は消えてしまいました」の音が鳴ります。
この音で喜びましょう（笑）。

## ESP32

### WebServer

homebridgeからhttpで施錠・解錠、状態問い合わせのリクエストが来ますのでWebServerでその命令を受け取るようにします。

### MQTT

httpだけでもいいのですが、mqttでも施錠・解錠、操作結果を通知するようにしておきます。

また、施錠・開錠位置の設定にシリアルコマンドを使いますので、その命令をmqttで受け取って書き込むようにしておきます。

### NFC読み取り

ESP32とPN532を繋げる場合、i2cのクロックを落とします。

http://gijin77.blog.jp/archives/31488050.html

今回はAppleWatchのSuicaで解錠します。
ところがIDmは偽装できるため信用ならないわけでして、IDm以外の信用できるものが欲しいとなるとライセンス契約を結ぶ必要が出てきます。
個人でライセンス契約というのは非現実的ですので、今回はSuicaの履歴を使うことにします。
IDmをコピーするだけならこっそりできますが履歴まで読むとAppleWatchの通知が来ますので、気づかずに読まれるということは無いであろう、ということにします。

https://qiita.com/odetarou/items/bcd65dbfd1f68735ac30

PN532でSuicaを読む場合、以下のようにします。

- systemcode 0x03
- requestcode 0x03
- servicecode 0x090f
- Suica履歴のブロック 0x8000〜

この状態のPN532に、エクスプレスカードをSuicaに設定してあるAppleWatchを近づけると履歴が読み込まれると同時に改札を通ったときと同じような通知を出してきます。

https://qiita.com/bellx2/items/fb081c4bdd822c8d36fd

Suica履歴のフォーマットは以下のようになります。

[suica - FeliCa Library Wiki - FeliCa Library - OSDN](https://ja.osdn.net/projects/felicalib/wiki/suica)

あとは自分の生活習慣にあわせて「最新のnエントリー以内にhoge駅をm回以上利用している」「残高はxx円以上ある」といった条件をIDmと組み合わせておきましょう。
まぁストーキングされたら駅もオートチャージもバレバレですし、レジで抜かれる可能性もなきにしもあらず[^2]ですから、公安や変質者に追われている場合は諦めてNFCタグを買いましょう。

[^2]: 商業施設で「suicaをかざして抽選」といったキャンペーンをしいてることがあります。来店者の駅履歴を集めて、集客範囲や属性を調べたいのでしょうね。テナントのPOS情報と突合すれば個人特定も可能でしょう...
例: 
・[小田急百貨店でSuicaやPASMOなどを使った抽選会を実施中 | 新宿ニュースBlog](https://shinjukunews.com/1676)
・[ICカード タッチDeクーポン](https://otemachi-place.jp/wp/wp-content/uploads/2020/09/Touch-De.pdf)
・[【終了いたしました】タッチでチャンスキャンペーン｜イベント＆お知らせ｜東京オペラシティ | 京王新線 初台駅に地下直結の複合文化施設](https://www.tokyooperacity.co.jp/event/item_eventnews.jsp?id=11)

### 制御スレッド

あとは状態遷移図を描いて命令がきたら施錠・解錠する、タイマーで自動閉鎖など作っていきます。
スレッド間の通信はxQueueを使います。

```mermaid
stateDiagram
    direction LR	
    state 正常 {
    施錠 --> 解錠: 開錠cmd, 解錠検出
    施錠 --> 施錠: 解錠失敗

    解錠 --> 施錠: Timeout施錠, 施錠cmd, 施錠検出
    解錠 --> 開放: 開放検出
    
    state 開放 {
        短時間開放 --> 長時間開放: Timeout(警告表示)
        長時間開放 --> 長時間許可: 確認操作(警告消去)
    }

    開放 --> 解錠: 閉鎖検出

    }

    state 異常 {
      エラー
      Jam
    }
    
    開放 --> エラー: 施錠検出
    施錠 --> エラー: 開放検出

    正常 --> Jam: 施錠失敗

    異常 --> 正常: 確認操作
    異常 --> 解錠: 解錠cmd(誤検出による締め出し対策)

```

「エラー」は、ドアが開いているにもかかわらずロックを施錠している、という状態を示します。

厳密には「施錠コマンドを発行したつもりだがまだ施錠成功を検出していない」といったSYN_SENTのような状態もあります。
delayで誤魔化してもなんとかなりますが、待機時間の試行錯誤が必要です。

## サーバ側: homebridge

homebridgeではhttp-advanced-accessory pluginを使います。

https://github.com/staromeste/homebridge-http-advanced-accessory

ドアに関連するサービスとしては LockManagement, LockMechanism, ContactSensor の3つがありますが、今回は LockMechanism と ContactSensor を使います。
LockManagement はiOS/macOSのホームアプリが対応しておらず、「非対応」とだけ表示されるためです。仕様上は、自動施錠のタイマー設定やログ取得ができるようですが、残念。

homebridgeを使わずesp32がMatterを話すという構成もありでしょう。今回は付加的な機能やセンサー観測値報告のために外部依存しますので、頑張って独立する必要はありません。

### LockMechanism

施錠・解錠の操作を行うことができます。

```config.json
{
  "accessory" : "HttpAdvancedAccessory",
  "service"   : "LockMechanism",
  "name"      : "ロック",
  "urls" : {
    "getLockCurrentState": {
      "url" : "http://shota/state",
      "mappers" : [
        {
          "type": "jpath",
          "parameters": {
            "jpath": "$.current",
            "index": 0
          }
        }
      ]
    },
    "getLockTargetState": {
      "url" : "http://shota/state",
      "mappers" : [
        {
          "type": "jpath",
          "parameters": {
            "jpath": "$.target",
            "index": 0
          }
        }
      ]
    },
    "setLockTargetState" : {
      "url" : "http://shota/setLock?target=${value}",
      "httpMethod": "GET",
      "body" : "{value}",
      "mappers" : []
    }
  }
}
```

### ContactSensor

ドアの開閉状態（リードスイッチで検出）を表示します。

```config.json
{
  "accessory" : "HttpAdvancedAccessory",
  "service"   : "ContactSensor",
  "name"      : "ドア",
  "props" : {
    "ContactSensorState" : {
      "validValues": [
        0,
        1
      ]
    }
  },
  "urls" : {
    "getContactSensorState" : {
      "url" : "http://shota/door",
      "mappers" : [
        {
          "type": "jpath",
          "parameters": {
            "jpath": "$.state",
            "index": 0
          }
        }
      ]
    }
  }
}
```

## サーバ側: MQTT操作プロセス

人感センサなどを搭載した他のデバイスや自動化の連携をします。
施錠・開錠位置の書き込みや、自動施錠タイマーの秒数設定もできるようにします。

人が帰宅してきた時にあらかじめ解錠しておく、天気予報で雨が出ている時は傘を忘れない様にLEDを青くする、開錠中はhueに警告を表示する、外センサーの観測値を受け取る、等の付加的機能をつけます。

# 設置

従来通りドアに貼り付け、従来とは違って電源等を配線し、施錠・開錠位置を手であわせてMQTTからコマンドを叩いて記憶させます。

![door1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204320/27c7c823-dfa6-a499-c7eb-ee71d721f6c0.jpeg)

このあと配線をもうすこし綺麗に...

![door2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204320/7fb01cb9-dbe5-9823-c58f-8fe1f275b25e.jpeg)


# 完成

物好き以外は素直にSesameやSwitchBotを買った方が幸せだと思います。
まぁ、いつかはそれらもサービス終了するのでしょうが、Qrio社と異なりBLE APIを公開している（らしい）のでなんとかなるでしょう。

**バグや動作不良で自分が締め出されたり、泥棒がハックして入らないよう注意しましょう！**

# 謝辞

[bakueikozo/qriohack](https://github.com/bakueikozo/qriohack) を作成、公開された[ひろみつ (@bakueikozo) / X](https://twitter.com/bakueikozo) さま、ありがとうございます。

APIも何も公開せずサービスを終了させたQrio社さま、ありがうとございました。おかげで面白い玩具を作ることができました。[^3]

[^3]: もう二度と貴社とその親会社の製品を買うことはないでしょう。大変なようですが頑張ってくださいませ...
[Qrio株式会社 第9期決算公告 | 官報決算データベース](https://catr.jp/settlements/0a9cf/325375)

# 補遺: 「IoTのサービス終了」のポエム

地球の時間ですら有限であり、人もまた有限の時を生きる以上、「サービス終了」自体は必然です。
法人とはいえ、その存在が永続するわけではありません。
このqiitaの記事にしても、いつまでもこのURLで公開されているとは限りません。
問題は終了の仕方です。
せめて、

- 弊社のクラウドサービスは終了しますが、コチラのソースコード（LGPL）をつかって互換サーバを立ち上げ、 api.hoge.com のAレコードをそこに向けていただければ継続して使用できます。
- Web経由の機能はつかえなくなりますが、BLE APIの仕様を公開いたしますので各自で制御してください。サポートはありません。
- 弊社でのサービスは終わりますが、掲載していた情報については国会図書館で閲覧できます。
- サービス終了に伴い、DRMなしのPDFをダウンロード可能にします。なお、PDFには購入者名の透かしがはいります。

くらいの消費者保護はしてほしいところです。
販売時に「この製品のクラウドサービスは202x年までは継続して提供できるよう最善の努力をいたします」といった表示をすることも必要でしょう。

「IoTのサービス終了」に関して消費者庁が動く日まで改善されないのか、その日が来る前に界隈が衰退するのか...

# 追記 (2024新春)

海の向こうにも似たようなことをしている人はいますね。

[サードパーティーのサーバーやアプリに頼らない完全オフラインのスマートホームを構築した方法とは？ - GIGAZINE](https://gigazine.net/news/20240127-offline-smart-home/)

上記に私から一言追加するとしたら、この一行でしょうか。

* IoTデバイスは専用のSSIDを使ってVLANを分離し、閉じ込めましょう。localnetで動作するにも関わらず、勝手に親元と通信したがるデバイスは結構あります。