オブプラス｜obnizを活用して、一人暮らしに彩りを与える

![6098C4AA-4DC6-4DA4-832F-AA368FEFBCD1_1_105_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/52fc0c98-b388-e0ee-04b1-a698c6bdf75b.jpeg)
解説が思いつきません。
タイトルと画像を見ればやりたいことがはっきりわかります。

#今回のプロダクト
![IMG_2347.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/d8d32a59-0a8f-4761-0a35-874ebf2f4fbe.jpeg)
**会話はVS Codeのターミナル上**で実施することとしました。
実際の挙動については後述します。
かわいいですね。



#環境・デバイス
>[obniz Board 1Y](https://obniz.com/ja/products/obnizboard)
[マイコン内蔵RGBLED 8mm PL9823-F8](https://obniz.com/ja/sdk/parts/FullcolorLED/README.md)
[マイクロサーボ 9g SG-90](https://obniz.com/ja/sdk/parts/ServoMotor/README.md)
[高精度IC温度センサ LM60BIZ](https://obniz.com/ja/sdk/parts/LM60/README.md)
[超音波距離センサー HC-SR04](https://obniz.com/ja/sdk/parts/HC-SR04/README.md)
Node.js v16.10.0
Visual Studio Code 1.60.2

#挨拶
気温に応じて、最初の一声を変えてくれます。
機械なので、どうしても暑さには弱いみたいです。
かわいい。

<iframe width="560" height="315" src="https://www.youtube.com/embed/W_yMZ59kKAY" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

![IMG_2366.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/768554f9-dc58-1683-c87b-b3e4dd63051b.png)
常温のとき

![IMG_2367.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/1b62aa98-41be-3362-33af-739a7cc25655.png)
低温のとき

:::note info
今回は撮影のため、コードを書き換えて色を変えています。
実際は温度条件で色、セリフを変えています。
:::

#恥ずかしがり屋
<iframe width="560" height="315" src="https://www.youtube.com/embed/eX6-Hyv8Tz4" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
恥ずかしがり屋なので、あまり近づきすぎると照れてしまいます。
かわいい。

#さよならのとき
<iframe width="560" height="315" src="https://www.youtube.com/embed/Sa4Oyc1zKSo" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
別れ際には頭を撫でると、手を振ってバイバイしてくれます。
かわいい。

#サンプルコード
```javascript

const Obniz = require('obniz');
const obniz = new Obniz('Obniz_ID');

obniz.onconnect = async () => {
    obniz.display.clear();
    // led
    const rgbled = obniz.wired("WS2811", {gnd: 4, vcc: 5, din: 6}); 
    //温度センサー
    const tempsens = obniz.wired('LM60', { gnd: 7, output: 8, vcc: 9 });
    const temp = await tempsens.getWait();
    // 温度をコンソールに表示
    console.log(temp);
        // 赤: rgbled.rgb(255, 0, 0);
        // 緑: rgbled.rgb(0, 255, 0);
        // 青: rgbled.rgb(0, 0, 255);
    if(temp < 15.0) {
        rgbled.rgb(0, 0, 255);
        console.log(`今日は寒いね。${temp}度しかないよ。`)
        await obniz.wait(5000);
    } else if(temp < 30.0) {
        rgbled.rgb(0, 255, 0);
        console.log(`今日は${temp}度。過ごしやすいね！`)
        await obniz.wait(5000);
    } else {
        rgbled.rgb(255, 0, 0);
        console.log(`${temp}度。暑いねー。熱中症にならないように家の中でだらだらしないと！`)
        await obniz.wait(5000);
    } 
    //距離センサー
    var hcsr04 = obniz.wired("HC-SR04", {gnd:0, echo:1, trigger:2, vcc:3});
    obniz.onloop = async function () {
        hcsr04.measure(function( distance ){
        //console.log("distance " + distance + " mm");
        if (distance > 200) {
            rgbled.rgb(0, 255, 0);
            } else {
            rgbled.rgb(255, 20, 50);
            console.log('近いって/// 恥ずかしいじゃん///');
            }
        });
        await new Promise((resolve) => { setTimeout(resolve, 3000) });    
    }; 
    //サーボモーター
    const servo = obniz.wired('ServoMotor', { signal: 11});
    let degrees = 90.0;
    // スイッチの反応を常時監視
    // 「スイッチ状態が変化した瞬間に1回だけ実行される」
    obniz.switch.onchange = async function (state) {
        if (state === 'right') {
            console.log('pushed');
            degrees = 180.0;
            servo.angle(degrees);
            await obniz.wait(400);
            degrees = 90.0;
            servo.angle(degrees);
            await obniz.wait(400);
            degrees = 180.0;
            servo.angle(degrees);
            await obniz.wait(400);
            degrees = 90.0;
            servo.angle(degrees);
            await obniz.wait(400);
        }else {
            // スイッチが押されていない状態
            degrees = 90.0;
            console.log('released');
        }
    }
}
```
:::note info 
距離センサーでLEDの色を変えるところは、setTimeoutでプログラムのみ停止、サーボモーターはawait obniz.wait(400)で止めてあげると、ちょうど良い挙動でした。
:::

#配線
<details><summary>必要に応じて参照ください。</summary><div>


![IMG_2362.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100048/797de696-1a04-a0b5-2353-669047b79c0e.jpeg)

距離センサーは0~3に接続
コードにもありますが配線の順番に注意してください。

```javascript

    const rgbled = obniz.wired("WS2811", {gnd: 4, vcc: 5, din: 6}); 
    //温度センサー
    const tempsens = obniz.wired('LM60', { gnd: 7, output: 8, vcc: 9 });
```
:::note warn
LED,温度センサーは配線を間違えると、破損や怪我につながるので、慎重に確認してください。
:::
</div></details>

#今後の展望｜LINEbotとの連携
現状では、こちらの声をobnizに届けることができておりませんので、LINE Messaging APIと連携し、L INE上で会話できるようにしたいと考えました。
現状実装できていないため、折り畳みとさせていただきますが、興味ある方はお読みいただければ幸いです。

<details><summary>サンプルコード</summary><div>

```javascript
// ########################################
//          obniz処理部分
//  Obniz_ID：自分のobniz ID（XXXX-XXXX）
// ########################################
const Obniz = require('obniz');
const obniz = new Obniz('Obniz_ID');
// obnizと接続確立したとき
obniz.onconnect = async () => {
    const rgbled = obniz.wired("WS2811", {gnd: 4, vcc: 5, din: 6}); // io0 is connected to anode, io1 is cathode 
    const getObnizTemp = async () => {
    const tempsens = obniz.wired('LM60', { gnd: 7, output: 8, vcc: 9 });
    const temp = await tempsens.getWait();
        if(temp < 15.0) {
            rgbled.rgb(0, 0, 255);
            console.log(`今日は寒いね。${temp}度しかないよ。`)
            await obniz.wait(5000);
        } else if(temp < 20.0) {
            rgbled.rgb(0, 255, 0);
            console.log(`今日${temp}度。過ごしやすいね！`)
            await obniz.wait(5000);
        } else {
            rgbled.rgb(255, 0, 0);
            console.log(`${temp}度。暑いねー。熱中症にならないように家の中でだらだらしないと！`)
            await obniz.wait(5000);
        }  
        return temp;
    }     
}
// ########################################
//          LINEBot イベント処理部分
//  channelSecret：LINE Developers → チャネル基本設定 → チャネルシークレット
//  channelAccessToken：LINE Developers → Messaging API設定 → チャネルアクセストークン（長期）
//  ターミナルで `ngrok http 3000` 実行後、発行されたURLをWebhook URLとして設定するのを忘れずに
//  「検証」ボタンをクリックするとターミナルにエラーが出ますがここでは問題ありません（検証イベントのハンドリングをしていないため）
// ########################################
const config = {
    channelSecret: 'channelSecret',
    channelAccessToken: 'channelAccessToken'    
};
const line = require('@line/bot-sdk');
const client = new line.Client(config);
// ExpressからMessaging APIイベントを渡されて処理するところ
const handleEvent = async (event) => {
    // テキストメッセージ以外を受信したときは何も行わずresolveを返す
    if (event.type !== 'message' || event.message.type !== 'text') {
        return Promise.resolve(null);
    }
    // テキストメッセージを受信したとき
    if (event.message.text === '温度教えて') {
        // 待ってねというメッセージを「リプライ」で先に返す
        await client.replyMessage(event.replyToken, {
            type: 'text',
            text: '.oO（ちょっと調べてきますねー。）'
        });
        // obnizの温度センサから値をとってくる（ブロッキング・時間のかかる処理で一旦ここで止まる）
        const temp = await getObnizTemp();
        // tempが取得できたらそれを含めたメッセージを「プッシュ」で送信する
        client.pushMessage(event.source.userId, {
            type: 'text',
            text: '今の温度は' + temp + '度ですねー。',
        });
    } else {
        // メッセージの中身が「温度教えて」以外だったとき
        client.replyMessage(event.replyToken, {
            type: 'text',
            text: '「温度教えて」と話しかけてね！'
        });
    }
    // resolveを返す
    return Promise.resolve(null);
}



// ########################################
//          Expressサーバー部分
// ########################################
const express = require('express');
const PORT = process.env.PORT || 3000;
const app = express();
// 「(サーバーURL)/webhook」にアクセス（LINEサーバーからのWebhook）があったとき
app.post('/webhook', line.middleware(config), (req, res) => {
    // 受信したイベントをターミナルに表示
    console.log(req.body.events);
    // イベントをhandleEventに渡して1つずつ処理
    Promise.all(
        req.body.events.map(handleEvent)
    ).then(
        result => res.json(result)
    );
});
// PORT番号のポートでサーバーを開始
app.listen(PORT);
console.log('express runnning: PORT =', PORT);

```

本文中にありました、センサーでの温度取得＋LED点灯に加えて、Line上で温度を尋ねると、そのデータを返してくれるように作成しておりましたが、実装できておりません。
温度を取得する関数として定義しているgetObnizTempが、obniz.onconnectの中でしか動かず、Line上で参照しようとしても参照できず、一方で、obniz.onconnectの外に出すと、データの取得はできるのですが、LEDの点灯などが実行されないというジレンマに陥っています。
</div></details>
以上、読んでみて少しでも面白いと思っていただければ幸いです。