obnizを使って良い姿勢を保とうとしてみた

腰が痛い。
原因はわかっている。在宅勤務の時の姿勢が良くないからだ。
姿勢が悪くなっていたら警告してくれる装置をobnizで作成したので、紹介する。
# 出来上がった装置を紹介
姿勢の悪さを目と画面の距離で測るようにした。
一般的に、目と画面の距離は40センチ以上離すのが良いらしい。
【参考】
https://www.eizo.co.jp/eizolibrary/other/itmedia08/#:~:text=%E4%B8%80%E8%88%AC%E7%9A%84%E3%81%AB%E3%80%8C%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%A8,%E3%82%82%E6%9D%A1%E4%BB%B6%E3%81%AF%E5%B0%91%E3%81%97%E7%95%B0%E3%81%AA%E3%82%8B%E3%80%82

そこで、目と画面の距離が30センチ未満なら、赤LEDが点灯してobnizディスプレイに「your posture is too bad!!」と表示、
目と画面の距離が30から40センチの場合は、黄LEDが点灯してobnizディスプレイに「your posture is bad!!」と表示、
目と画面の距離が40センチ以上の場合は、青LEDが点灯してobnizディスプレイに「your posture is greate!!」と表示するようにした。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">先日作成した姿勢矯正ツールの動画です！<br>※PCとobnizが直接触れないようにしています <a href="https://t.co/i9xF8SGL2l">pic.twitter.com/i9xF8SGL2l</a></p>&mdash; Masahiro Nishiguchi (@Masa_Xedge) <a href="https://twitter.com/Masa_Xedge/status/1587752385342214144?ref_src=twsrc%5Etfw">November 2, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

また、姿勢に応じてLINEに姿勢に関するメッセージが届く仕様とした。
姿勢が悪い場合は、ストレッチを促す文言と共に、いろいろなストレッチ方法が掲載されたWEBページのURLが届くおまけ付きにした。

◆姿勢が悪い時（LEDが赤）
<img width="500" alt="03B3D087-A602-4411-83FB-D883ADC5C98B_4_5005_c.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884816/70e6b72f-be7a-655f-dcd0-a64797d928a3.jpeg">
◆姿勢がまずまずのとき（LEDが黄）
<img width="500" alt="03B3D087-A602-4411-83FB-D883ADC5C98B_4_5005_c.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884816/cf6a31d0-e4d6-711f-1587-24f280d1c7c3.jpeg">
◆姿勢がよい時（LEDが青）
<img width="500" alt="412D4501-710E-4C52-9C26-35A3D4CDB3BD_4_5005_c.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884816/963db00b-bed2-86eb-2852-a1a9a5798871.jpeg">


# 環境等
【環境】
Heroku環境上でNode-REDを使用
【API】
LINEmessagingAPI
【ハード】
obniz Board 1Y
フルカラーLED
超音波距離センサ（HC-SR04）

# フロー紹介
<img width="1500" alt="スクリーンショット 2022-10-29 23.29.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884816/9385bcf4-fa14-a4ea-b27a-f5022b43a9bf.png">

jsonはこちら
```
[{"id":"e390e8213c12e7f5","type":"tab","label":"フロー 10","disabled":false,"info":"","env":[]},{"id":"e42d3d96.12046","type":"obniz-repeat","z":"e390e8213c12e7f5","obniz":"8c71456dbacf1732","name":"","interval":"5000","code":"msg.payload = await obnizParts.hcsr04.measureWait();\n\nreturn msg;","x":270,"y":240,"wires":[["3184cf38a35bfd6e"]]},{"id":"3184cf38a35bfd6e","type":"obniz-function","z":"e390e8213c12e7f5","obniz":"8c71456dbacf1732","name":"","code":"obniz.display.print('mesure your posture');\n\n// 距離を取得\nlet distance = msg.payload;\n// そのままだと小数点以下の桁数がやたら多いので整数に丸めてもよい\ndistance = Math.floor(distance);\n\n// 距離がある程度未満かどうかの判定\nif (distance < 300) { // 300mm = 30cm 以下の場合\n    // obnizディスプレイに姿勢が悪くなっていることを表示\n    obniz.display.clear();\n    obniz.display.print('your posture is too bad!!'); \n    obnizParts.WS2811.rgb(255, 0, 0); // 赤    \n} else if (distance < 400){ // 400mm = 40cm以下の場合\n    // obnizディスプレイに少し姿勢が悪いことを表示\n    obniz.display.clear();\n    obniz.display.print('your posture is bad')\n    obnizParts.WS2811.rgb(255, 255, 0); // 黄    \n} else {\n    //obnizディスプレイに姿勢がいいことを表示\n    obniz.display.clear();\n    obniz.display.print('your posutre is greate')\n    obnizParts.WS2811.rgb(0, 0, 255); // 青    \n}\nreturn msg;","x":440,"y":240,"wires":[["10162bdcd649cf93"]]},{"id":"10162bdcd649cf93","type":"switch","z":"e390e8213c12e7f5","name":"","property":"payload","propertyType":"msg","rules":[{"t":"lt","v":"300","vt":"str"},{"t":"btwn","v":"300","vt":"num","v2":"400","v2t":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":3,"x":350,"y":460,"wires":[["87960e60c26ba072","2f63cbc5e9482159"],["4c9e4307f02eb754"],["8a4bcf705c43eb17"]]},{"id":"1219e919a0c945e8","type":"PushMessage","z":"e390e8213c12e7f5","name":"","credentials":{"channelSecret":"ChannelSecret","channelAccessToken":"AccessToken","targetId":"UserID"},"x":700,"y":340,"wires":[]},{"id":"d857f50ec5f72096","type":"PushMessage","z":"e390e8213c12e7f5","name":"","credentials":{"channelSecret":"ChannelSecret","channelAccessToken":"Accesstoken","targetId":"UserId"},"x":720,"y":460,"wires":[]},{"id":"08245c791116c57c","type":"PushMessage","z":"e390e8213c12e7f5","name":"","credentials":{"channelSecret":"ChannelSecret","channelAccessToken":"AccessToken","targetId":"UserId"},"x":720,"y":540,"wires":[]},{"id":"87960e60c26ba072","type":"template","z":"e390e8213c12e7f5","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"姿勢が悪くなってるよ！","output":"str","x":540,"y":340,"wires":[["1219e919a0c945e8"]]},{"id":"4c9e4307f02eb754","type":"template","z":"e390e8213c12e7f5","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"まずまずの姿勢だね !","output":"str","x":520,"y":460,"wires":[["d857f50ec5f72096"]]},{"id":"8a4bcf705c43eb17","type":"template","z":"e390e8213c12e7f5","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"良い姿勢です!キープしよう！","output":"str","x":520,"y":540,"wires":[["08245c791116c57c"]]},{"id":"f1083f24865317a2","type":"PushMessage","z":"e390e8213c12e7f5","name":"","credentials":{"channelSecret":"ChannelSecret","channelAccessToken":"AccessToken","targetId":"UserId"},"x":880,"y":380,"wires":[]},{"id":"2f63cbc5e9482159","type":"delay","z":"e390e8213c12e7f5","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":540,"y":380,"wires":[["5ee287f5f4e867fc"]]},{"id":"5ee287f5f4e867fc","type":"template","z":"e390e8213c12e7f5","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"これみてストレッチでもしよう！\nhttps://www.health-net.or.jp/tairyoku_up/undo/stretch/t02_02_06.html","output":"str","x":700,"y":380,"wires":[["f1083f24865317a2"]]},{"id":"8c71456dbacf1732","type":"obniz","obnizId":"","deviceType":"obnizboard1y","name":"","accessToken":"","code":"obnizParts.hcsr04 = obniz.wired(\"HC-SR04\",{ gnd:0, echo:1, trigger:2, vcc:3 });\nobnizParts.WS2811 = obniz.wired('WS2811', { gnd:9, vcc:10, din:11 });"}]
```

### obniz repeat
```js:コード
msg.payload = await obnizParts.hcsr04.measureWait();
return msg;
```
### obniz function
```js:初期化処理
obnizParts.hcsr04 = obniz.wired("HC-SR04",{ gnd:0, echo:1, trigger:2, vcc:3 });
obnizParts.WS2811 = obniz.wired('WS2811', { gnd:9, vcc:10, din:11 });
```

```js:コード
obniz.display.print('mesure your posture');

// 距離を取得
let distance = msg.payload;
// そのままだと小数点以下の桁数がやたら多いので整数に丸めてもよい
distance = Math.floor(distance);

// 距離がある程度未満かどうかの判定
if (distance < 300) { // 300mm = 30cm 以下の場合
    // obnizディスプレイに姿勢が悪くなっていることを表示
    obniz.display.clear();
    obniz.display.print('your posture is too bad!!'); 
    obnizParts.WS2811.rgb(255, 0, 0); // 赤    
} else if (distance < 400){ // 400mm = 40cm以下の場合
    // obnizディスプレイに少し姿勢が悪いことを表示
    obniz.display.clear();
    obniz.display.print('your posture is bad')
    obnizParts.WS2811.rgb(255, 255, 0); // 黄    
} else {
    //obnizディスプレイに姿勢がいいことを表示
    obniz.display.clear();
    obniz.display.print('your posutre is greate')
    obnizParts.WS2811.rgb(0, 0, 255); // 青    
}
return msg;
```
### switch
<img width="500" alt="スクリーンショット 2022-10-30 11.00.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884816/a3a9e641-7b8d-34ff-764d-ec0b90cc797a.png">

switchでは30センチ未満、30から40センチ、40センチ以上、で場合分けするようにした。その場合訳に応じて、LINEbotから姿勢に関するメッセージが届く、といった感じだ。
あとはtemplateにLINEbotで出力したい文言を書けば、完成である。

# まとめ
いかがだっただろうか。
意外と簡単に作成できるので、ぜひ参考にしていただきたい。

今回のフローでは頻繁にLINEが届いてしまう。30分に一度、ランダムのタイミングで目と画面の距離を測定し、その結果がLINEに通知されるようにすれば、より実用性が上がると考えている。