node-red上でobnizとsony meshを繋いでみた


sony meshがいろんなセンサついていて便利なんですが、プログラム書かないといないのがネックだ・・！と言う声を聞くので、node-red上で使ってみました。



MESHのボタンを押したらMESHのLEDが光る、というものを作ります。

:::note warn
obnizノードは0.7.0が最新です。こちらのノードを入れた前提でのプログラムになります
![ss.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/683a7a65-b8e3-e2e3-be94-21449ac78c6b.png)

:::


## 大枠方針


obniz初期セットアップノードではbleでデバイスを見つけて接続し続けるプログラムを書く
- ひたすらscanしてブロックを探す
- 見つけたらブロックリスト変数に入れる
- ブロックリスト変数に入っているブロックがconnectedになるように監視する


obniz repeat/functionノードではMESH Blockが接続されていない可能性も考慮してプログラムを書く
- ブロックリスト変数に入っているもののうち、接続済みのブロックから使いたいものを探す
- 接続済みじゃなかったら利用は諦める

## obniz初期ノード

ひたすらにScan！Scan！Scan！します





```mermaid
graph TB
  Start([Start])-->Scan
  Scan --> B{新しいMESHデバイスを\n見つけたら}
  B-->|True| ブロックリスト変数に入れる
  B-->|False| ブロックリスト変数内のブロックを\nすべて接続にする
  ブロックリスト変数に入れる --> ブロックリスト変数内のブロックを\nすべて接続にする
  ブロックリスト変数内のブロックを\nすべて接続にする-->Scan
  
```


```javascript
node.warn("obniz connected")

const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
const sessionId = Math.random();
obniz.sessionId = sessionId
obnizParts.meshblocks = {};
await obniz.ble.initWait();

node.warn("ble inited")

const MESH_100AC = obniz.constructor.getPartsClass("MESH_100AC");
const MESH_100BU = obniz.constructor.getPartsClass("MESH_100BU");
const MESH_100GP = obniz.constructor.getPartsClass("MESH_100GP");
const MESH_100LE = obniz.constructor.getPartsClass("MESH_100LE");
const MESH_100MD = obniz.constructor.getPartsClass("MESH_100MD");
const MESH_100PA = obniz.constructor.getPartsClass("MESH_100PA");
const MESH_100TH = obniz.constructor.getPartsClass("MESH_100TH");

const targetBlockTypes = [
    // MESH_100AC,
    MESH_100BU,
    // MESH_100GP,
    MESH_100LE,
    // MESH_100MD,
    // MESH_100PA,
    // MESH_100TH,
];

while (obniz.sessionId === sessionId && obniz.connectionState === 'connected') {

    // Step1 scanして見つけたブロックをlistに入れていく
    node.warn("scan starting...")
    await obniz.ble.scan.startWait(
        { localNamePrefix: "MESH-100" },
        { duration: 15 }
    );
    obniz.ble.scan.onfind = async (peripheral) => {

        if (!!obnizParts.meshblocks[peripheral.localName]) {
            //もうリストに入っている
            return;
        }
        const blockTypeClass = targetBlockTypes.find(b => b.isMESHblock(peripheral));
        if (!blockTypeClass) {
            return;
        }
        node.warn("found new MESH Block :" + peripheral.localName);
        obnizParts.meshblocks[peripheral.localName] = new blockTypeClass(peripheral);
        await obniz.ble.scan.endWait();
    };

    // scan停止まち
    while (obniz.ble.scan.state !== 'stopped') {
        await sleep(100);
    }
    node.warn("scan stopped")

    // Step2 リストを順番に接続していく
    for (let blockName in obnizParts.meshblocks) {
        const block = obnizParts.meshblocks[blockName];
        if (!block.peripheral.connected) {
            node.warn("connecting to " + block.peripheral.localName);
            try {
                await block.connectWait();
                node.warn("connected to " + block.peripheral.localName);
            } catch (e) {
                node.warn("connect failed to " + block.peripheral.localName);
            }
        }
    }

}

```


こちらを”初期化処理”の方に入れます。

![ss.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/3cee47b3-c2ab-babc-6b79-fd7b70567d88.png)



## obniz repeat/functionノード

ほしいBlockのインスタンスをobnizPartsから持ってきます

```javascript
const MESH_100BU = obniz.constructor.getPartsClass("MESH_100BU");
const buttonBlock = Object.values(obnizParts.meshblocks).find((b) => b instanceof MESH_100BU && b.peripheral.connected);
```

あとはこの `buttonBlock` をつかってプログラムを書くだけです

[ボタンブロックの使い方ドキュメント](https://docs.obniz.com/ja/sdk/parts/MESH_100BU/README.md)を見ながら作ります。
`node.send(msg)` あたりがnode-redっぽいですね


```javascript
if (buttonBlock){

    buttonBlock.onSinglePressed = (() => {
        msg.payload = "single";
        node.send(msg);
    });

    buttonBlock.onDoublePressed = (() => {
        msg.payload = "double";
        node.send(msg);
    });


    buttonBlock.onLongPressed = (() => {
        msg.payload = "long";
        node.send(msg);
    });
}

```


LEDの方も同じようにつなげてあげればokです！

```javascript

const MESH_100LE = obniz.constructor.getPartsClass("MESH_100LE");
const ledBlock = Object.values(obnizParts.meshblocks).find((b) => b instanceof MESH_100LE && b.peripheral.connected);

if (ledBlock) {

    if(msg.payload === 'single'){
        const colors = {
            red: 15,    // Set LED-Red in the range of 0 to 127.
            green: 63,  // Set LED-Green in the range of 0 to 127.
            blue: 0     // Set LED-Blue in the range of 0 to 127.
        };
        const totalTime = 1000;     // Set the total control time in the range of 0 to 65,535[ms].
        const cycleOnTime = 1000;   // Set the light on time in cycle in the range of 0 to 65,535[ms].
        const cycleOffTime = 500;   // Set the light off time in cycle in the range of 0 to 65,535[ms].
        const pattern = MESH_100LE.Pattern.FIREFLY; // Set the blinking pattern to blink or firefly.

        // Write
        ledBlock.setLed(colors, totalTime, cycleOnTime, cycleOffTime, pattern);

    } else if (msg.payload === 'double') {
        const colors = {
            red: 0,    // Set LED-Red in the range of 0 to 127.
            green: 0,  // Set LED-Green in the range of 0 to 127.
            blue: 127     // Set LED-Blue in the range of 0 to 127.
        };
        const totalTime = 3000;     // Set the total control time in the range of 0 to 65,535[ms].
        const cycleOnTime = 1000;   // Set the light on time in cycle in the range of 0 to 65,535[ms].
        const cycleOffTime = 500;   // Set the light off time in cycle in the range of 0 to 65,535[ms].
        const pattern = MESH_100LE.Pattern.BLINK; // Set the blinking pattern to blink or firefly.

        // Write
        ledBlock.setLed(colors, totalTime, cycleOnTime, cycleOffTime, pattern);

    } else if (msg.payload === 'long') {
        const colors = {
            red: 127,    // Set LED-Red in the range of 0 to 127.
            green: 0,  // Set LED-Green in the range of 0 to 127.
            blue: 0     // Set LED-Blue in the range of 0 to 127.
        };
        const totalTime = 3000;     // Set the total control time in the range of 0 to 65,535[ms].
        const cycleOnTime = 3000;   // Set the light on time in cycle in the range of 0 to 65,535[ms].
        const cycleOffTime = 500;   // Set the light off time in cycle in the range of 0 to 65,535[ms].
        const pattern = MESH_100LE.Pattern.FIREFLY; // Set the blinking pattern to blink or firefly.

        // Write
        ledBlock.setLed(colors, totalTime, cycleOnTime, cycleOffTime, pattern);

    }

    
}
```

サンプルの全フローはこちら↓

```json

[{"id":"dc2aa5752f56ddf0","type":"obniz-function","z":"56ff5f1b106b752a","obniz":"22b6be5b760eef74","name":"obniz/mesh LED","code":"\nconst MESH_100LE = obniz.constructor.getPartsClass(\"MESH_100LE\");\nconst ledBlock = Object.values(obnizParts.meshblocks).find((b) => b instanceof MESH_100LE && b.peripheral.connected);\n\nif (ledBlock) {\n\n    if(msg.payload === 'single'){\n        const colors = {\n            red: 15,    // Set LED-Red in the range of 0 to 127.\n            green: 63,  // Set LED-Green in the range of 0 to 127.\n            blue: 0     // Set LED-Blue in the range of 0 to 127.\n        };\n        const totalTime = 1000;     // Set the total control time in the range of 0 to 65,535[ms].\n        const cycleOnTime = 1000;   // Set the light on time in cycle in the range of 0 to 65,535[ms].\n        const cycleOffTime = 500;   // Set the light off time in cycle in the range of 0 to 65,535[ms].\n        const pattern = MESH_100LE.Pattern.FIREFLY; // Set the blinking pattern to blink or firefly.\n\n        // Write\n        ledBlock.setLed(colors, totalTime, cycleOnTime, cycleOffTime, pattern);\n\n    } else if (msg.payload === 'double') {\n        const colors = {\n            red: 0,    // Set LED-Red in the range of 0 to 127.\n            green: 0,  // Set LED-Green in the range of 0 to 127.\n            blue: 127     // Set LED-Blue in the range of 0 to 127.\n        };\n        const totalTime = 3000;     // Set the total control time in the range of 0 to 65,535[ms].\n        const cycleOnTime = 1000;   // Set the light on time in cycle in the range of 0 to 65,535[ms].\n        const cycleOffTime = 500;   // Set the light off time in cycle in the range of 0 to 65,535[ms].\n        const pattern = MESH_100LE.Pattern.BLINK; // Set the blinking pattern to blink or firefly.\n\n        // Write\n        ledBlock.setLed(colors, totalTime, cycleOnTime, cycleOffTime, pattern);\n\n    } else if (msg.payload === 'long') {\n        const colors = {\n            red: 127,    // Set LED-Red in the range of 0 to 127.\n            green: 0,  // Set LED-Green in the range of 0 to 127.\n            blue: 0     // Set LED-Blue in the range of 0 to 127.\n        };\n        const totalTime = 3000;     // Set the total control time in the range of 0 to 65,535[ms].\n        const cycleOnTime = 3000;   // Set the light on time in cycle in the range of 0 to 65,535[ms].\n        const cycleOffTime = 500;   // Set the light off time in cycle in the range of 0 to 65,535[ms].\n        const pattern = MESH_100LE.Pattern.FIREFLY; // Set the blinking pattern to blink or firefly.\n\n        // Write\n        ledBlock.setLed(colors, totalTime, cycleOnTime, cycleOffTime, pattern);\n\n    }\n\n    \n}","x":600,"y":220,"wires":[[]]},{"id":"22b6be5b760eef74","type":"obniz","obnizId":"70463008","deviceType":"obnizboard1y","name":"","accessToken":"","code":"node.warn(\"obniz connected\")\n\nconst sleep = (ms) => new Promise((res) => setTimeout(res, ms));\nconst sessionId = Math.random();\nobniz.sessionId = sessionId\nobnizParts.meshblocks = {};\nawait obniz.ble.initWait();\n\nnode.warn(\"ble inited\")\n\nconst MESH_100AC = obniz.constructor.getPartsClass(\"MESH_100AC\");\nconst MESH_100BU = obniz.constructor.getPartsClass(\"MESH_100BU\");\nconst MESH_100GP = obniz.constructor.getPartsClass(\"MESH_100GP\");\nconst MESH_100LE = obniz.constructor.getPartsClass(\"MESH_100LE\");\nconst MESH_100MD = obniz.constructor.getPartsClass(\"MESH_100MD\");\nconst MESH_100PA = obniz.constructor.getPartsClass(\"MESH_100PA\");\nconst MESH_100TH = obniz.constructor.getPartsClass(\"MESH_100TH\");\n\nconst targetBlockTypes = [\n    // MESH_100AC,\n    MESH_100BU,\n    // MESH_100GP,\n    MESH_100LE,\n    // MESH_100MD,\n    // MESH_100PA,\n    // MESH_100TH,\n];\n\nwhile (obniz.sessionId === sessionId && obniz.connectionState === 'connected') {\n\n    // Step1 scanして見つけたブロックをlistに入れていく\n    node.warn(\"scan starting...\")\n    await obniz.ble.scan.startWait(\n        { localNamePrefix: \"MESH-100\" },\n        { duration: 15 }\n    );\n    obniz.ble.scan.onfind = async (peripheral) => {\n\n        if (!!obnizParts.meshblocks[peripheral.localName]) {\n            //もうリストに入っている\n            return;\n        }\n        const blockTypeClass = targetBlockTypes.find(b => b.isMESHblock(peripheral));\n        if (!blockTypeClass) {\n            return;\n        }\n        node.warn(\"found new MESH Block :\" + peripheral.localName);\n        obnizParts.meshblocks[peripheral.localName] = new blockTypeClass(peripheral);\n        await obniz.ble.scan.endWait();\n    };\n\n    // scan停止まち\n    while (obniz.ble.scan.state !== 'stopped') {\n        await sleep(100);\n    }\n    node.warn(\"scan stopped\")\n\n    // Step2 リストを順番に接続していく\n    for (let blockName in obnizParts.meshblocks) {\n        const block = obnizParts.meshblocks[blockName];\n        if (!block.peripheral.connected) {\n            node.warn(\"connecting to \" + block.peripheral.localName);\n            try {\n                await block.connectWait();\n                node.warn(\"connected to \" + block.peripheral.localName);\n            } catch (e) {\n                node.warn(\"connect failed to \" + block.peripheral.localName);\n            }\n        }\n    }\n\n}"}]

```




## 動かしてみる



https://x.com/9wick/status/1722525509429690687?s=20