エアコン嫌いの家族を熱中症から守りたい

# どうしてクーラーつけないの？！
ある夏の日に実家に帰った時のこと。
うだるような暑さの中、リビングでクーラーもつけずにテレビを見る父がいた。
かろうじてシーリングファンは回っていたものの、父の隣で寝そべっている猫もぐったりしている。驚いて「どうしてクーラーつけないの？！」と聞いたら、「窓開けてれば、涼しいよ」と、ニコニコしながら父は言った。

# 人は老化が進むにつれ、温度に対する感覚が弱くなる
人は老化が進むと熱放射能力が低くなり、深部体温が上昇しやすい。また、温度に対する感覚も弱くなり「暑い」と感じにくくなったり、喉の渇きを感じにくくなったりすることで、熱中症にかかりやすいと言われている。
【参考文献】
・熱中症ゼロへ
　[熱中症、こんな人は特に注意！](https://www.netsuzero.jp/learning/le05)

# 熱中症の約4割は室内で発生している
消防庁の統計によると、熱中症の約4割が室内で発生しており、熱中症死亡者数で見ると65歳以上の高齢者が8割を占めている。
屋内で熱中症により亡くなった高齢者の約9割は、エアコンがあるのに使用していなかったとのことだ。
【参考文献】
・weathernews
　[15年で3倍以上　死者数の8割を占める高齢者の熱中症対策](https://weathernews.jp/s/topics/202207/110165/)
・消防庁
　[全国の熱中症による救急搬送状況 令和5年7月24日~7月30日(速報値)](https://www.fdma.go.jp/disaster/heatstroke/items/r5/heatstroke_sokuhouti_20230724.pdf)

# LINE Botを活用して家族を守る仕組みを考える
どうしたら離れて暮らす家族を守ることができるのか考えてみた。
考えた仕組みは以下2点である。
LINEのあて先 : 両親、離れて暮らしている家族を想定

**・温度センサー**
　一定の時間ごとに自動で室内の温度を測り、LINE Botでお知らせして注意喚起する
**・超音波距離センサー**
　一定の時間ごとに室内で人の動きがあるか検知し、LINE Botでお知らせする
 　人の動きがない場合は家族に安否確認するよう促す

 # 活用ツール
・obniz(OSのひとつで、瞬時に動作が始まるIoTを実現)
　・温度センサー（LM60）
　・超音波距離センサー（HCSR04）
 <blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">望むものができた。温度を測って、超音波センサーで動きを検知し、LINE Botでお知らせする。ただ、obnizひとつで実行しようとすると、動作のタイミングが一緒になってしまう。<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/obniz?src=hash&amp;ref_src=twsrc%5Etfw">#obniz</a> <a href="https://twitter.com/hashtag/%E5%AE%89%E5%90%A6%E7%A2%BA%E8%AA%8D?src=hash&amp;ref_src=twsrc%5Etfw">#安否確認</a> <a href="https://twitter.com/hashtag/NodeRED?src=hash&amp;ref_src=twsrc%5Etfw">#NodeRED</a> <a href="https://twitter.com/hashtag/JavaScript?src=hash&amp;ref_src=twsrc%5Etfw">#JavaScript</a> <a href="https://twitter.com/hashtag/%E6%B8%A9%E5%BA%A6%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC?src=hash&amp;ref_src=twsrc%5Etfw">#温度センサー</a> <a href="https://twitter.com/hashtag/%E8%B6%85%E9%9F%B3%E6%B3%A2%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC?src=hash&amp;ref_src=twsrc%5Etfw">#超音波センサー</a> <a href="https://t.co/XJ307aMjqA">https://t.co/XJ307aMjqA</a> <a href="https://t.co/Si70T9n3sP">pic.twitter.com/Si70T9n3sP</a></p>&mdash; chihirot134 (@chihirot_kate) <a href="https://twitter.com/chihirot_kate/status/1797871362826289377?ref_src=twsrc%5Etfw">June 4, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

・Node-RED
・JavaScript
・LINEmessagingAPI

# フロー
・上段・・処理停止用ノード（説明は省略）
・下段・・処理実行用ノード
![スクリーンショット 2024-06-04 18.17.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772350/d707114d-7250-6312-ac2f-cd965d07bde5.png)

# ソースコード（処理実行用ノード）
```json
[{"id":"c61534fcfc6e08b2","type":"obniz-repeat","z":"19f26d722b829ed2","obniz":"2a612d9a43b88fcd","name":"センサーデータ取得","interval":"3600000","code":"const LM60Value = await obnizParts.LM60.getWait();\nconst HCSR04Value = await obnizParts.HCSR04.measureWait();\nmsg.payload = { temperature: LM60Value, distance: HCSR04Value };\nreturn msg;","x":270,"y":200,"wires":[["c7e273cea974653f"]]},{"id":"c7e273cea974653f","type":"function","z":"19f26d722b829ed2","name":"メッセージ生成","func":"let temperature = msg.payload.temperature;\nlet distance = msg.payload.distance;\n\nif (temperature < 28) {\n    msg.payload = '【熱中症注意！窓を開けて！】現在の気温は' + temperature + '度です。';\n} else {\n    msg.payload = '【熱中症警告！エアコンをつけて！】現在の気温は' + temperature + '度です。';\n}\n\nif (distance >= 1000) {\n    msg.payload += '\\n【安否確認】動きが検出されませんでした。確認してください。';\n} else {\n    msg.payload += '\\n動きが検出されました。';\n}\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":200,"wires":[["be193680201d4aae"]]},{"id":"be193680201d4aae","type":"BloadcastMessage","z":"19f26d722b829ed2","name":"LINEメッセージ送信","x":660,"y":200,"wires":[[]]},{"id":"2a612d9a43b88fcd","type":"obniz","obnizId":"****-****","deviceType":"obnizboard1y","name":"","accessToken":"","autoConnectOnDeploy":true,"code":"// 画面を消去\r\nobniz.display.clear();\r\n\r\n// LM60温度センサーの設定\r\nobnizParts.LM60 = obniz.wired(\"LM60\", {\r\n    gnd: 0,      // GNDピンの接続\r\n    output: 1,   // アナログ出力ピンの接続\r\n    vcc: 2       // VCCピンの接続\r\n});\r\n\r\n// HC-SR04超音波センサーの設定\r\nobnizParts.HCSR04 = obniz.wired(\"HC-SR04\", {\r\n    gnd: 3,      // GNDピンの接続\r\n    echo: 4,     // Echoピンの接続\r\n    trigger: 5,  // Triggerピンの接続\r\n    vcc: 6       // VCCピンの接続\r\n});\r\n"}]
```
## ①センサーデータ取得
 ・温度センサー（LM60）と、超音波距離センサー（HCSR04）のデータを取得し、msg.payloadに"temperature"と"distance"を代入する
 ・"interval":"3600000"＝1時間ごとに稼働するよう設定

## ②メッセージ生成
 msg.payloadに代入されたそれぞれのデータを呼び出し、メッセージを生成する
　**・温度（temperature）**
　　28℃未満だった場合
  　　・・【熱中症注意！窓を開けて！】現在の気温は⚫︎度です。
　　その他（28℃以上）だった場合
  　　・・【熱中症警告！エアコンをつけて！】現在の気温は⚫︎度です。

　**・距離（distance）**
　　1m以内で動きがあるか確認
　　動きなし・・【安否確認】動きが検出されませんでした。確認してください。
　　動きあり・・動きが検出されました。

## ③Broadcastノード
 LINE Botにメッセージを送信する

# 結果
　警告バージョンと注意喚起バージョンが無事送信された。
![IMG_8953.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772350/bdadc8a0-7728-158e-2d48-e914c4cca492.jpeg)

# 考察
今回はobniz１台で粘ったので、稼働時間を分けることが出来なかった。
できれば動きの検出については、6時間に1回などに回数を減らしたい。
メッセージを受け取る対象を誰にするかによっても、稼働のタイミングは変えた方が良さそうだ。
取得したデータを活かして、自動でエアコンをON、OFFする仕組みも作ることができそう。
家族が離れて暮らしていても、見守り・フォローする体制ができていれば、安心して過ごせるのではないだろうか。親世代はとにかくクーラーをつけたがらない。それを認識しておくだけでも防げる事故があるはずだ。

# おまけ
前回作成したLINE Botに部屋の温度を測る機能をプラスした。
これでいつでも温度を確認することができる。
**全体フローを紹介**
![スクリーンショット 2024-06-05 2.48.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772350/59fd0806-58fc-1aa5-9567-16f750e2719a.png)

```json
[{"id":"97811561ee3a6b19","type":"Webhook","z":"9ef9e62fc4a4dae4","name":"","url":"/webhook","x":120,"y":340,"wires":[["bc574decf74c8274"]]},{"id":"2fb4f5b04158148f","type":"ReplyMessage","z":"9ef9e62fc4a4dae4","name":"","replyMessage":"","x":800,"y":340,"wires":[]},{"id":"bc574decf74c8274","type":"switch","z":"9ef9e62fc4a4dae4","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"朝食","vt":"str"},{"t":"eq","v":"朝ごはん","vt":"str"},{"t":"eq","v":"昼食","vt":"str"},{"t":"eq","v":"ランチ","vt":"str"},{"t":"eq","v":"昼ごはん","vt":"str"},{"t":"eq","v":"気温教えて","vt":"str"},{"t":"eq","v":"温度教えて","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":8,"x":290,"y":340,"wires":[["2a93e82fe561e35d"],["2a93e82fe561e35d"],["9f0c3636c6dc4d9a"],["9f0c3636c6dc4d9a"],["9f0c3636c6dc4d9a"],["be0cd555c1d96a7e"],["be0cd555c1d96a7e"],["117eda19e0f3da20"]]},{"id":"2a93e82fe561e35d","type":"function","z":"9ef9e62fc4a4dae4","name":"朝食","func":"function getRandomElement(array) {\n    return array[Math.floor(Math.random() * array.length)];\n}\n\nconst categories = {\n    onigiri: [\"鮭おにぎり\", \"梅おにぎり\", \"昆布おにぎり\"],\n    sandwich: [\"ハムサンド\", \"卵サンド\", \"ツナサンド\"],\n    salad: [\"チキンサラダ\", \"ツナサラダ\", \"シーザーサラダ\"],\n    yogurt: [\"プレーンヨーグルト\", \"フルーツ入りヨーグルト\", \"ギリシャヨーグルト\"],\n    fruit: [\"カットフルーツ（メロン、パイナップルなど）\", \"バナナ\", \"りんご\"],\n    smoothie: [\"野菜スムージー\", \"フルーツスムージー\", \"プロテインスムージー\"],\n    cerealBar: [\"グラノーラバー\", \"ナッツ＆シードバー\", \"フルーツバー\"],\n    hotMenu: [\"おでん\", \"中華まん\", \"焼き芋\"],\n    bread: [\"クロワッサン\", \"ベーグル\", \"ブランパン\"],\n    others: [\"サバの塩焼き\", \"枝豆\", \"ゆで卵\"],\n    drink: [\"豆乳\", \"プロテインドリンク\", \"ミルク\"]\n};\n\nconst randomSelection = {\n    onigiri: getRandomElement(categories.onigiri),\n    sandwich: getRandomElement(categories.sandwich),\n    salad: getRandomElement(categories.salad),\n    yogurt: getRandomElement(categories.yogurt),\n    fruit: getRandomElement(categories.fruit),\n    smoothie: getRandomElement(categories.smoothie),\n    cerealBar: getRandomElement(categories.cerealBar),\n    hotMenu: getRandomElement(categories.hotMenu),\n    bread: getRandomElement(categories.bread),\n    others: getRandomElement(categories.others),\n    drink: getRandomElement(categories.drink)\n};\n\n// 結果を整形してメッセージとして設定\nmsg.payload = `\n今日のおすすめ朝食メニュー:\nおにぎり: ${randomSelection.onigiri}\nサンドイッチ: ${randomSelection.sandwich}\nサラダ: ${randomSelection.salad}\nヨーグルト: ${randomSelection.yogurt}\nフルーツ: ${randomSelection.fruit}\nスムージー: ${randomSelection.smoothie}\nシリアルバー: ${randomSelection.cerealBar}\nホットメニュー: ${randomSelection.hotMenu}\nパン: ${randomSelection.bread}\nその他: ${randomSelection.others}\n飲み物: ${randomSelection.drink}\n`;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":300,"wires":[["2fb4f5b04158148f"]]},{"id":"9f0c3636c6dc4d9a","type":"function","z":"9ef9e62fc4a4dae4","name":"昼食","func":"function getRandomElement(array) {\n    return array[Math.floor(Math.random() * array.length)];\n}\n\nconst categories = {\n    bento: [\"チキン南蛮弁当\", \"焼肉弁当\", \"鮭弁当\", \"鯖の塩焼き弁当\", \"牛丼弁当\"],\n    sandwich: [\"ローストビーフサンドイッチ\", \"クラブハウスサンドイッチ\", \"カツサンド\", \"エッグサラダサンドイッチ\", \"ツナサラダサンドイッチ\"],\n    salad: [\"シーザーサラダ\", \"チキンサラダ\", \"豆腐サラダ\", \"海藻サラダ\", \"ミックスサラダ（チーズ、ナッツ入り）\"],\n    pasta: [\"ペペロンチーノ\", \"カルボナーラ\", \"ミートソーススパゲッティ\", \"バジルソースパスタ\", \"シーフードパスタ\"],\n    donburi: [\"親子丼\", \"牛丼\", \"海鮮丼\", \"豚丼\", \"天丼\"],\n    soup: [\"ミネストローネ\", \"コーンスープ\", \"わかめスープ\", \"チキンスープ\", \"野菜たっぷりスープ\"]\n};\n\nconst randomSelection = {\n    bento: getRandomElement(categories.bento),\n    sandwich: getRandomElement(categories.sandwich),\n    salad: getRandomElement(categories.salad),\n    pasta: getRandomElement(categories.pasta),\n    donburi: getRandomElement(categories.donburi),\n    soup: getRandomElement(categories.soup)\n};\n\n// 結果を整形してメッセージとして設定\nmsg.payload = `\n今日のおすすめ昼食メニュー:\nお弁当: ${randomSelection.bento}\nサンドイッチ: ${randomSelection.sandwich}\nサラダ: ${randomSelection.salad}\nパスタ: ${randomSelection.pasta}\n丼もの: ${randomSelection.donburi}\nスープ: ${randomSelection.soup}\n`;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":340,"wires":[["2fb4f5b04158148f"]]},{"id":"117eda19e0f3da20","type":"template","z":"9ef9e62fc4a4dae4","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"朝食・朝ごはん\n昼食・昼ごはん・ランチ\nと入力してね！\n\n栄養バランスのポイント\n【たんぱく質】 肉、魚、豆腐、卵などのたんぱく質が豊富な食材を選びましょう。\n【野菜】 サラダやスープに野菜を取り入れて、ビタミンやミネラルを摂取しましょう。\n【炭水化物】 主食としてご飯やパン、パスタなどをバランスよく摂取します。\n【健康的な脂肪】 ドレッシングやナッツ、魚の脂など、健康的な脂肪を適量取り入れます。\n\nおすすめメニューは、栄養バランスを考慮して選んでおり、コンビニや食堂で手軽に手に入るものを中心にしています。","output":"str","x":480,"y":420,"wires":[["2fb4f5b04158148f"]]},{"id":"16f127f2c22e4a7b","type":"template","z":"9ef9e62fc4a4dae4","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"今の温度は {{payload}} 度です！","output":"str","x":680,"y":420,"wires":[["2fb4f5b04158148f"]]},{"id":"be0cd555c1d96a7e","type":"obniz-function","z":"9ef9e62fc4a4dae4","obniz":"2a612d9a43b88fcd","name":"","code":"msg.payload = await obnizParts.LM60.getWait();\nreturn msg;","x":500,"y":380,"wires":[["16f127f2c22e4a7b"]]},{"id":"2a612d9a43b88fcd","type":"obniz","obnizId":"****-****","deviceType":"obnizboard1y","name":"","accessToken":"","autoConnectOnDeploy":true,"code":"// 画面を消去\r\nobniz.display.clear();\r\n\r\n// LM60温度センサーの設定\r\nobnizParts.LM60 = obniz.wired(\"LM60\", {\r\n    gnd: 0,      // GNDピンの接続\r\n    output: 1,   // アナログ出力ピンの接続\r\n    vcc: 2       // VCCピンの接続\r\n});\r\n\r\n// HC-SR04超音波センサーの設定\r\nobnizParts.HCSR04 = obniz.wired(\"HC-SR04\", {\r\n    gnd: 3,      // GNDピンの接続\r\n    echo: 4,     // Echoピンの接続\r\n    trigger: 5,  // Triggerピンの接続\r\n    vcc: 6       // VCCピンの接続\r\n});\r\n"}]
```
![IMG_8968.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772350/f68c53ea-4596-d9a2-ca43-07036c53640d.jpeg)

・参考（過去の記事）
　[栄養を気にしてくれる人(Bot)を作りました！](https://qiita.com/chihirot134/items/33ee1c06e1d31cc9bc41)