照度を利用して研究室の施錠通知botを作った話

この記事は[TDU CPSLab Advent Calendar 2022 - Adventar](https://adventar.org/calendars/7417)の4日目の記事です

ヘマにより遅刻です（申し訳ない）。

前の記事は[こちら](https://narumincho.notion.site/definy-f192457931b44721a2759519c0bde4df)。
次の記事は[こちら](https://i-icc.hatenablog.com/entry/2022/12/06/191615?_ga=2.108321474.1750266001.1670315167-307858130.1639364229)。

# はじめに

鍵を閉めたか不安になる現象を解決したい。

研究室を無意識に施錠したとき、記憶がないので大学を出たあたりでふと思い出して不安になることがあります。
まさか研究室の鍵を閉め忘れるなんてことはめったにないはずですが、頭がバグっている時にはよく不安になってしまうので、手元で確認できるよう Slack bot を作ってみました。

# 目次

1. できたもの
1. やったこと<!--1. 実装-->
1. まとめ
1. 余談

# 環境

- M5Stack Core2
- M5Stack用環境光センサユニット（BH1750FVI-TR） 
- Node-RED
- Slack Webhook

# できたもの

![C43B11BC-D8EC-4FE3-8EF7-AE506B7ABFE2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409492/faa84a4e-5dea-a327-d6ba-286dad5fdd92.jpeg)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409492/9032d95d-2522-27f6-6ccf-278bf23977e9.png)

弊研究室の Slack で、特定チャンネルで bot として垂れ流しています。

# やったこと

構成的にはこのような感じです。
前提条件として弊研究室は施錠をしたタイミングで照明がオフになります。このことを利用して、照明が落ちた時間を施錠タイミングとみなしています。
また、常時給電可能な環境なため、今回は電源周りはあまり考慮していません。

![構成図](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409492/e2b3c271-007e-605b-2f4c-0f51ce562d58.png)

## 事前調査

照度を利用するため、事前に使用する環境の調査を行いました。
昼間・夜間の時間帯で、それぞれの点灯時と消灯時の照度を計測し、おおまかな値を閾値と設定します。

今回使用するセンサは、照度を`1-65535`の値で出力します。
計測した結果、以下の値を設定しました。
（より正確にタイミングを検知するため、値に少し段階を設けました）
```md
- 点灯：70
- 消灯：10
```

## 実装

- 照度を計測する

`readLightLevel()`で5秒ごとに計測を行います。

```c++
#include <M5Core2.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <BH1750.h>

BH1750 lightMeter;

bool isOn = false;
void setup(){
  Serial.begin(9600);
  M5.begin();
  Wire.begin();
  Serial.println("Sensor begin.....");

  lightMeter.begin();

  //Wifiに接続
  //mqttサーバに接続

  delay(5000);

}
void loop() {
  float lux = lightMeter.readLightLevel();

  measureLight(lux);
~~~

  delay(5000);
}
```


- 閾値の超過でサーバへ値の発行を行う
```c++
void measureLight(){
    if (isOn && lux < 20) {
    isOn = false;
    post(lux);
  } else if (!isOn && lux >= 70) {
    isOn = true;
    post(lux);
  }
}
```

計測時、その値が事前に設定した値を超過していた場合に、MQTTでサーバへ値を発行します。
```c++
void post(float lux) {
  char json[200];
  const size_t capacity = JSON_OBJECT_SIZE(2);
  StaticJsonDocument<capacity> doc;
  doc["isOn"] = isOn;
  doc["lux"] = lux;
  serializeJson(doc, json);
  mqttClient.publish(topic, json);
  delay(1000);
}
```

- 値に応じた文字列をSlackへポストする
![スクリーンショット 2022-12-06 12.16.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409492/99d5bd53-ddf1-cbdf-b6ac-63d4d66e0fcc.png)
```value.js
const val = msg.payload.isOn;

msg.topic = val;

return msg;
```

```alllight_logic.js
const m = msg.payload;

let state = "電気";

if(m.isOn){
    state = "点灯 :sunny:"
}else{
    state = "消灯 :new_moon_with_face:"
}


msg.payload = {
    "text": state,
}

return msg;
```

<!--フローの画像-->

これらの処理で、照明が点灯（＝解錠）時と消灯（＝施錠）時に通知を送ることに成功しました。


# まとめ

M5StackCore2と照度センサを使って、簡易な施錠通知 bot を作成しました。
これで、疲れた状態でさらに追い打ちをかけられることがなくなりました。めでたし。

また、スキマ開発でそんなに工数かからなくて良かったです（友人の知識サポートに感謝！）。

ただ、実際に運用してみて、閾値の設定や機材の配置が微妙で日光の影響を受けてしまい、日中に誤作動してしまうことがありました。

より深く環境調査を行うことや、日光の影響を受けすぎないような工夫が必要だと感じました。

# 参考

- [使用したライブラリ](https://github.com/claws/BH1750)

---

### 余談
文中に出てきた bot の名前は「ALLLight」となっていました。
その由来ですが、安心させる文句を光にちなんだワードでもじったものにしたかったので、割とそのままですが


- （施錠が）大丈夫！→All right
- 光→light

を組み合わせたものになっています。