学校のロッカーをオートロック化&スマホ開錠式にしてみた

# はじめに
こちらは「[身の回りの困りごとを楽しく解決！ by Works Human Intelligence Advent Calendar 2023](https://qiita.com/advent-calendar/2023/works-hi)」の24日目の記事になります。

学校のロッカーをオートロック&スマホ開錠に対応させてみました。

:::note warn
今回私が行った改造は、学校の先生に許可をもらった上で行っています。
この記事の内容を真似される際は、必ず施工前にロッカーの管理者の方に許可をもらってください。ただし筆者はどのような場合であっても責任は負いません。
:::

# とりあえず成果物
ロッカーを操作するためのWebアプリケーションの画面です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/fffc2d31-202d-1c41-cb01-0f4ab75af4ad.png)

動作している様子は以下の動画でご確認ください

https://twitter.com/kazu_iroiro_/status/1739200960373969332

# 解決したいこと
私は学校のロッカーに教科書を入れているのですが、教科書を取り出す/しまうため、毎授業ごとにロッカーの鍵を開けるのが面倒に感じていました。

ダイヤル式の南京錠は位置合わせがシビアで、急いでいる時に限って開かないことがあったため、鍵をオートロック化&スマホ開錠式にしようと考えました。

# 方法の検討
## 物理
ロッカーの鍵は以下のような構造をしています。

<img width="270" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/63a93977-bfcf-493a-f1f4-ba35189fbba6.jpeg">

<img width="270" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/1fdbca56-e21f-24a7-785b-7c5bba27e587.jpeg">

左が開錠状態、右が施錠状態です。
ロッカーの外側、前面のドア部にある部品を動かすことで、ロッカーの内側にある画像の金属板が動きます。

この金属板がロッカーの鍵の受け部に引っかかることで施錠されます。

この鍵を下から見てみましょう。

![nonpen.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/b00432ff-704e-07d8-f1bb-105dab87003a.jpeg)

金属板の左側の空間に棒状のもの、例えば鉛筆を差し込むと、金属板が下がらなくなるようです。

![pen.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/39292ba0-a149-8919-a763-5196ea93cb8b.jpeg)

つまりここに棒を差し込む状態、差し込まない状態を作り出すことで、ロッカーを施錠・開錠できるということです。

## 通信
通信が簡単にできるマイコンと言えばmicro:bit・M5 StickC(ESP32)・Raspberry Pi Zero W・Raspberry Pi Picoなどが挙げられるかと思いますが、たまたま手元にあったmicro:bitを使用しました。

消費電力の観点、容易にBluetoothを利用できるという点が良いと思います。

# 材料
逸般のご家庭には転がっているであろう以下のものを使用しました。

| 品名 | 金額(およそ) | 数量 |
|:-:|:-:|:-:|
| micro:bit  | 2200 | 1 |
| サーボ  | 550 | 1 |
| モーメンタリスイッチ  | 10 | 1 |
| 電源ボックス  | 30 | 1 |
| 電源スナップ  | 10 | 1 |
| 短くなった鉛筆  | 0 | 1 |
| M3ネジとナット  | 20 | 4 |
| ゼムクリップ  | 5 | 2 |
| ピンヘッダ  | 10  | 適量 |
| 導線 | 10 | 適量 |
| 厚紙 | 0 | 適量 |
| 両面テープ | 50 | 適量 |
| 合計 | 2495 |  |

micro:bitはv1を使用しましたが、同じブログラムを使用してv2でも動作するはずです。

https://www.switch-science.com/products/5263

サーボについては、micro:bitと電源を共通化したいため、3V動作のものを使用しました。

https://akizukidenshi.com/catalog/g/gM-14693/

# 回路図
以下のような形になるように配線しました。

![AutoLocker.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/01ef0e76-0e44-0a3a-bfd4-0a14394295e7.jpeg)

# 配電/接続基板の作成
電源・micro:bit・サーボ・スイッチの接続を容易にするため、配電/接続基盤を作成しました。ユニバーサル基盤にピンヘッダを立てただけの簡易的なものですが、検証や設置が簡単になりました。

![kiban.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/cb357055-e2d0-39ec-2026-1b43448cf0c4.jpeg)
画質悪くてすみません…


# コードの作成
## micro:bit
MakeCodeで作成しました。
以下のリンクからアクセスすることができます。

https://makecode.microbit.org/_PY1CyMKrwA9o

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/842af993-173f-2363-163c-8c0d2c2d8949.png)

<details><summary>コードの詳細と説明はこちら！</summary>

初期化処理・起動完了表示とBluetooth接続完了表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/f33fe989-49a0-02f9-ff57-137c991061a7.png)

micro:bit本体のボタンを使用して開閉操作を行えるようにするコード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/8a9c4eeb-a2be-0e0d-7cf7-bd15abd8d867.png)

オートロックを実現するために扉の開閉検知を行うコード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/34886183-7288-db09-f8d6-a829dba59a82.png)

Bluetooth Low Energyを使用したロック・ロック解除を行うコード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/c051dd5a-7e7a-43ab-ff2f-8451d135b60f.png)

</details>

実行前にエディター画面の右上にある「**プロジェクトの設定**」から、ペアリングの方法を「**No Pairing Required**」に変更しておく必要があります。

## Webアプリ(HTML&JavaScript)
AndroidやWindowsのChromeなど、[WebBluetooth API](https://developer.mozilla.org/ja/docs/Web/API/Web_Bluetooth_API#ブラウザーの互換性)に対応したブラウザでのみ動作します。ご注意ください。

[参考にさせていただいたサイト](https://gunmagisgeek.com/blog/microbit/5456)に掲載されていたコードをほぼそのまま使用しています。

``` html:index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>AutoLocker</title>
    <style>
        /* https://coco-factory.jp/ugokuweb/move01/7-1-14/ のコードを使用,一部改変*/
        /*== 押し込む円 */

        .pushcircle {
            /*ボタンを横並びに配置するためにコードを追加*/
            display: flex;
            font-size: 3vh;

            /*周囲の線の起点とするためrelativeを指定*/
            position: relative;
            /*円の形状*/
            width: 25vw;
            height: 25vw;
            box-sizing: border-box;
            padding: 0 10px;
            margin-top: 3vh;
            margin-left: 37vw;
            text-align: center;
            background: #333;
            border-radius: 50%;
            color: #fff;
            text-decoration: none;
            outline: none;
            /*天地中央にテキストを配置*/
            display: flex;
            align-items: center;
            justify-content: center;
        }

        /*内側の線*/
        .pushcircle:after {
            content: "";
            /*絶対配置で線の位置を決める*/
            position: absolute;
            top: 50%;
            left: 50%;
            /*線の形状*/
            width: 85%;
            height: 85%;
            border: 2px solid #333;
            border-radius: 50%;
            transform: translate(-50%, -50%) scale(1.1);
            /*アニメーションの指定*/
            transition: .3s ease;
        }

        /*hoverをしたら枠線が小さくなる*/
        .pushcircle:hover:after {
            transform: translate(-50%, -50%) scale(1);
            border-color: #fff;
        }

        body {
            text-align: center;
            background-color: rgb(227, 249, 249);
        }

        .command {
            width: 50vw;
            height: 5vh;
            font-size: 3vh;
            margin-top: 3vh;
        }
    </style>
</head>

<body>
    <div>
        <button href="#" class="pushcircle" id="connect">接続</button>
        <button href="#" class="pushcircle" id="disconnect">切断</button>

        <input href="#" class="command" id="message" />

        <button href="#" class="pushcircle" id="send">送信</button>
    </div>

    <script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>
    <script>
        var bluetoothDevice;
        var characteristic;

        //chibi:bit BLE UUID
        var UART_SERVICE_UUID = '6e400001-b5a3-f393-e0a9-e50e24dcca9e';
        var UART_RX_CHARACTERISTIC_UUID = '6e400003-b5a3-f393-e0a9-e50e24dcca9e';

        //ボタンイベントリスナー
        d3.select("#connect").on("click", connect);
        d3.select("#disconnect").on("click", disconnect);
        d3.select("#send").on("click", sendMessage);


        //chibi:bitに接続する
        function connect() {
            let options = {};


            //options.acceptAllDevices = true;

            options.filters = [
                { services: [LED_SERVICE_UUID] }, // <- 重要
                { name: "BBC micro:bit [vaget]" }
            ];

            navigator.bluetooth.requestDevice(options)
                .then(device => {
                    bluetoothDevice = device;
                    console.log("device", device);
                    return device.gatt.connect();
                })
                .then(server => {
                    console.log("server", server)
                    return server.getPrimaryService(LED_SERVICE_UUID);
                })
                .then(service => {
                    console.log("service", service)
                    return service.getCharacteristic(LED_TEXT_CHARACTERISTIC_UUID)
                })
                .then(chara => {
                    console.log("characteristic", chara)
                    alert("BLE接続が完了しました。");
                    characteristic = chara;
                })
                .catch(error => {
                    console.log(error);
                });
        }

        //LEDに表示するメッセージを送信
        function sendMessage() {
            if (!bluetoothDevice || !bluetoothDevice.gatt.connected || !characteristic) return;
            var text = document.querySelector("#message").value;
            var arrayBuffe = new TextEncoder().encode(text);
            characteristic.writeValue(arrayBuffe);
        }


        //BEL切断処理
        function disconnect() {
            if (!bluetoothDevice || !bluetoothDevice.gatt.connected) return;
            bluetoothDevice.gatt.disconnect();
            alert("BLE接続を切断しました。")
        }

    </script>
</body>
</html>
```

コード内に記載してあるUUIDは、もともとLED表示サービス用のものでしたが、こちらをUART通信サービス用のものへと変更しています。UUIDは[こちらのページ](https://lancaster-university.github.io/microbit-docs/resources/bluetooth/bluetooth_profile.html)を参考にしました。

# 取り付け
ロッカーの扉にはマスキングテープと両面テープで固定しました。

![locker.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921137/07083933-ceb6-53af-f9d3-a1cf870e16cd.jpeg)

micro:bitは導線を端子に通した後、M3ネジとナットで固定し、接続基盤に接続させています。

鍵の部分に突っ込む鉛筆は、下部にクリップを取り付け、サーボから延ばしたクリップを引っ掛けています。

# 結論
オートロックはロマンの塊
スマホ開錠はみんな食いつく

クラスの中で話題になりました。

# 最後に
電池が切れるとロッカーが開かなくなります！
実用するためには補助電源の設置などの改良が必要です。

最後まで読んでいただきありがとうございました。

# 参考文献
micro:bitでのサーボモーターの動かし方

https://sanuki-tech.net/micro-bit/make/servomotor/

---
WebBluetoothを使ってmicro:bitとBLE通信

https://qiita.com/youtoy/items/cd2c3d4770d4ad75a321

https://gunmagisgeek.com/blog/microbit/5456

---
micro:bitのBLE ServiceのUUID一覧

https://lancaster-university.github.io/microbit-docs/resources/bluetooth/bluetooth_profile.html

---
WebBluetooth APIについて

https://developer.mozilla.org/ja/docs/Web/API/Web_Bluetooth_API#ブラウザーの互換性

---
htmlのボタン用CSS

https://coco-factory.jp/ugokuweb/move01/7-1-14/