LoginSignup
7
8

More than 5 years have passed since last update.

Node-REDでECHONET Liteの送受信nodeを作成してみた

Last updated at Posted at 2016-11-22

概要

 Node-REDにdefaultでinstallされるUDPの送信nodeと受信nodeを利用して、ECHONET Liteの送受信を容易にするnodeを作成しました。受信したUDP dataはパースされECHONET Liteで規定されるブロックに分解されます。データを送信する場合はECHONET Liteで規定される各ブロックの値を引数として渡します。ECHONET Liteはバイト単位でパケットが構成されますが、UInt8のdata typeを持たないJavaScriptでは扱いにくいため、データはIntで渡します。
 サンプルプログラムとして以下の3つを用意しました。

  • Node-REDからマニュアルでエアコンと照明のON/OFF制御
  • 電子錠の開閉でエアコンと照明のON/OFF制御
  • スマホのブラウザーをエアコンと照明のON/OFF制御リモコンにするweb application

なお、以下の環境で動作確認しています。
Node-RED version: v0.15.1
Node.js version: v6.9.1

全体のFLOWはこんな感じです。

全体Flow.png

送信

まず送信側から見ていきましょう。画面上で「EL send」と表示されているUDPの送信ノードの設定はこのようになります。to portに3610を入力してください。

udp_out.png

このudp nodeの入力側に接続されている「Send EL1」というfunction nodeの中身はこのようになりますが、理解しなくても使えます。

// Send ECHONET Lite packet
// Assumption: OPC = 1
//
//  Usage:
//      Input following data
//
//  msg.els.ip      // ip address (String)
//  msg.els.tid     // TID (Int)
//  msg.els.seoj    // SEOJ ([Int:device, Int:instance])
//  msg.els.deoj    // DEOJ ([Int:device, Int:instance])
//  msg.els.esv     // ESV (Int)
//  msg.els.epc     // EPC (Int)
//  msg.els.edt     // EDT ([Int])
//          // in case of no EDT data, no edt or []

const tid_buffer = Buffer.allocUnsafe(2);
let   seoj_buffer = Buffer.allocUnsafe(3);
const seoj = msg.els.seoj;
let   deoj_buffer = Buffer.allocUnsafe(3);
const deoj = msg.els.deoj;
const esv_buffer = Buffer.allocUnsafe(1);
const opc_buffer = Buffer.from([1]);
const epc_buffer = Buffer.allocUnsafe(1);
const pdc_buffer = Buffer.allocUnsafe(1);
let edt = msg.els.edt;

tid_buffer.writeUInt16BE(msg.els.tid, 0);
esv_buffer.writeUInt8(msg.els.esv, 0);
epc_buffer.writeUInt8(msg.els.epc, 0);

seoj_buffer.writeUInt16BE(seoj[0], 0);
seoj_buffer.writeUInt8(seoj[1], 2);
deoj_buffer.writeUInt16BE(deoj[0], 0);
deoj_buffer.writeUInt8(deoj[1], 2);

// edt[]からedt_bufferを作成
if ((typeof edt) == "undefined") {
    edt = [];
}

const edt_buffer = Buffer.allocUnsafe(edt.length);
for (var i = 0; i < edt.length; i++) {
    edt_buffer.writeUInt8(edt[i], i);
}

pdc_buffer.writeUInt8(edt_buffer.length, 0);

// Create ECHONET Lite packet
const el_buffer = Buffer.from([
    0x10, 0x81,
    tid_buffer[0], tid_buffer[1],
    seoj_buffer[0], seoj_buffer[1], seoj_buffer[2],
    deoj_buffer[0], deoj_buffer[1], deoj_buffer[2],
    esv_buffer[0], opc_buffer[0], epc_buffer[0], pdc_buffer[0]]);

// add EDT data
if (edt_buffer.length !== 0) {
    msg.payload = Buffer.concat([el_buffer, edt_buffer], 
        (el_buffer.length + edt_buffer.length));
} else {
    msg.payload = el_buffer;
}

msg.ip = msg.els.ip;
return msg;

 冒頭のコメントに記述されているように、このfunctionに以下のデータを渡してやると、byte列のECHONET Liteデータパケットに変換してudp nodeに渡します。なお、OPC=1のみ対応しています。

  • msg.els.ip // ip address (String)
  • msg.els.tid // TID (Int)
  • msg.els.seoj // SEOJ ([Int:device, Int:instance])
  • msg.els.deoj // DEOJ ([Int:device, Int:instance])
  • msg.els.esv // ESV (Int)
  • msg.els.epc // EPC (Int)
  • msg.els.edt // EDT ([Int])

具体的には、この「Send EL1」functionの入力側に接続されている「エアコン ON」functionを見てみましょう。

msg.els = {
    "ip" : "224.0.23.0",
    "tid" : 5,
    "seoj" : [0x05ff,1],
    "deoj" : [0x0130,1],
    "esv" : 0x61,
    "epc" : 0x80,
    "edt" : [0x30]
};

return msg;

このfunction内の必要な箇所の値を変更するだけで、ECHONET Liteのデータ送信を実現できます。

受信

続いて受信側を見ていきましょう。画面上で「EL receive」と表示されているUDPの受信ノードの設定はこのようになります。「Listen for」で「multicast message」を選択し、「Group」に224.0.23.0を「on port」に3610を入力してください。「Output」は「a Buffer」を選択してください。

udp_in.png

このudp nodeの出力側に接続されている「Parse EL1」というfunction nodeの中身はこのようになりますが、理解しなくても使えます。

// Parse ECHONET Lite packet
// Assumption: OPC = 1

//  OUTPUT:
//  msg.elr.ip      // ip address (String)
//  msg.elr.ehd     // EHD (Int)
//  msg.elr.tid     // TID (Int)
//  msg.elr.seoj    // SEOJ ([Int:device, Int:instance])
//  msg.elr.deoj    // DEOJ ([Int:device, Int:instance])
//  msg.elr.esv     // ESV (Int)
//  msg.elr.opc     // OPC (Int)
//  msg.elr.epc     // EPC (Int)
//  msg.elr.pdc     // PDC (Int)
//  msg.elr.edt     // EDT ([Int]) or [](no EDT data)

const buffer = msg.payload;
msg.elr = null;

if (buffer.length >= 14) {
  const ehd_buffer = buffer.slice(0, 2);
  const tid_buffer = buffer.slice(2, 4);
  const seoj_device_buffer = buffer.slice(4, 6);
  const seoj_instance_buffer = buffer.slice(6, 7);
  const deoj_device_buffer = buffer.slice(7, 9);
  const deoj_instance_buffer = buffer.slice(9, 10);
  const esv_buffer = buffer.slice(10, 11);
  const opc_buffer = buffer.slice(11, 12);
  const epc_buffer = buffer.slice(12, 13);
  const pdc_buffer = buffer.slice(13, 14);

  const ehd = ehd_buffer.readUInt16BE(0);
  const tid = tid_buffer.readUInt16BE(0);
  const seoj_device = seoj_device_buffer.readUInt16BE(0);
  const seoj_instance = seoj_instance_buffer.readUInt8(0);
  const seoj = [seoj_device, seoj_instance];
  const deoj_device = deoj_device_buffer.readUInt16BE(0);
  const deoj_instance = deoj_instance_buffer.readUInt8(0);
  const deoj = [deoj_device, deoj_instance];
  const esv = esv_buffer.readUInt8(0);
  const opc = opc_buffer.readUInt8(0);
  const epc = epc_buffer.readUInt8(0);
  const pdc = pdc_buffer.readUInt8(0);
  let edt = [];

  if (buffer.length >= 15) {
    const edt_buffer = buffer.slice(14);
    for (var i = 0; i < edt_buffer.length; i++) {
        edt[i] = edt_buffer.readUInt8(i);
    }
  }

  // ECHONET Lite header check
  if (ehd == 0x1081) {
    msg.elr = {
        "ip"            : msg.ip,
        "ehd"           : ehd,
        "tid"           : tid,
        "seoj"          : seoj,
        "deoj"          : deoj,
        "esv"           : esv,
        "opc"           : opc,
        "epc"           : epc,
        "pdc"           : pdc,
        "edt"           : edt
    };
  }
}

return msg;

 冒頭のコメントに記述されているように、このfunctionから以下のデータが出力されます。なお、OPC=1のみ対応しています。

  • msg.elr.ip // ip address (String)
  • msg.elr.ehd // EHD (Int)
  • msg.elr.tid // TID (Int)
  • msg.elr.seoj // SEOJ ([Int:device, Int:instance])
  • msg.elr.deoj // DEOJ ([Int:device, Int:instance])
  • msg.elr.esv // ESV (Int)
  • msg.elr.opc // OPC (Int)
  • msg.elr.epc // EPC (Int)
  • msg.elr.pdc // PDC (Int)
  • msg.elr.edt // EDT ([Int])

パースされたデータの使い方の例を、この「Parse EL1」functionの出力側に接続されている「filter keyStatus」functionで見てみましょう。受信したデータの送信元が「電子錠」で、プロパティが「開閉状態」ならば、開閉状態を表すEDTデータをmsg.payloadに格納しています。次のswitch nodeで閉(0x41)または開(0x42)で分岐し、エアコンや照明をON/OFF制御しています。

// 電子錠 EOJ=0x026f, 開閉状態 EPC=0xe0
if ((msg.elr.seoj[0] == 0x026f) && (msg.elr.epc == 0xe0)) {
    msg.payload = msg.elr.edt[0];
}

return msg;

Webリモコン

Node-REDはweb server機能をもっているので、web applicationを容易に作成することができます。全体Flowの下部の「ON/OFF Remote Controller」を見てください。スマホのブラウザで

http://:1880/control

をアクセスすると、このようなシンプルなリモコン画面が現れます。このON/OFFボタンでエアコンや照明をON/OFF制御できます。

web_remocon.PNG

全体のFlowの左下部にある「/control」と書かれたhttp nodeでGET requestを受け付けます。このnodeはURLに「/control」と入力してあるだけです。このnodeの出力が接続されている「ON/OFF button」と書かれたtemplate nodeがHTMLを出力して、ブラウザーにボタンを表示します。template nodeのソースコードはこのようになっています。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset=“UFT-8”>
    <style>
        body { background: #FAFAD2; }
        h1 {color:black; font-family:sans-serif;}
        button { width: 300px; height: 100px; font-size: 36px; border-radius: 10px; border-style: none; background-color: #aaaaaa;}
        button:hover {background-color: #dddddd;}
    </style>
    <title> ON/OFF BUTTON </title>
    <script language="javascript" type="text/javascript">
        function OnButtonClick() {
            location.href = "/on";
        }
        function OffButtonClick() {
            location.href = "/off";
        }
    </script>
</head>
<body>
    <h1>HEMS Controller</h1>
    <button type="button" name="buttonOn" onclick="OnButtonClick()">ON</button> 
    <button type="button" name="buttonOff" onclick="OffButtonClick()">OFF</button> <br/>
</body>
</html>

このHTMLがhttp response nodeから出力されます。

全体のFlow

全体のFlowのJSONデータはこちらです。

[{"id":"929982f7.1dfe88","type":"inject","z":"b25212d8.336a88","name":"Search","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":145.63636779785156,"y":159,"wires":[["48da7a43.d0e234"]]},{"id":"2ab8c00.fd8fd4","type":"link in","z":"b25212d8.336a88","name":"ON","links":["60038e3d.3ea5","60579462.f009ac","a47b7d1b.85f958"],"x":144,"y":242.18182373046875,"wires":[["8f824877.268258","30b813d1.96d6f4"]]},{"id":"7bab7379.ce52ac","type":"link in","z":"b25212d8.336a88","name":"OFF","links":["19f3c295.8e39bd","49fe4793.c299c8","d6714c57.f29c38"],"x":146,"y":329.18182373046875,"wires":[["46ac93c4.9bf35c","2bcde2cc.b0e0b6"]]},{"id":"4f1896ac.7cfcb","type":"comment","z":"b25212d8.336a88","name":"Check Key Status","info":"電子錠のOn/OFFでエアコンと照明のON/OFFを制御","x":128.22727966308594,"y":422.5454406738281,"wires":[]},{"id":"e46582fe.0e69b","type":"comment","z":"b25212d8.336a88","name":"Flow: demoRoom","info":"ECHONET Liteの送受信を実現。\nBrowserで接続するとON/OFF制御のリモコンとなる。","x":138.86363220214844,"y":114.81817626953125,"wires":[]},{"id":"6e147962.3b1508","type":"http in","z":"b25212d8.336a88","name":"/on","url":"/on","method":"get","swaggerDoc":"","x":87.5,"y":628.1818237304688,"wires":[["a47b7d1b.85f958","cd5ec784.0801d8"]]},{"id":"a47b7d1b.85f958","type":"link out","z":"b25212d8.336a88","name":"REST/on","links":["2ab8c00.fd8fd4"],"x":219.5,"y":627.1818313598633,"wires":[]},{"id":"85a91f31.a3686","type":"http in","z":"b25212d8.336a88","name":"/off","url":"/off","method":"get","swaggerDoc":"","x":88,"y":669.1818237304688,"wires":[["d6714c57.f29c38","cd5ec784.0801d8"]]},{"id":"d6714c57.f29c38","type":"link out","z":"b25212d8.336a88","name":"REST/off","links":["7bab7379.ce52ac"],"x":217.5,"y":668.1818237304688,"wires":[]},{"id":"e35592e3.6ced4","type":"http in","z":"b25212d8.336a88","name":"/control","url":"/control","method":"get","swaggerDoc":"","x":87,"y":710.1818237304688,"wires":[["387d2a5d.fa9d76","cd5ec784.0801d8"]]},{"id":"8bb17ee2.8b71c","type":"http response","z":"b25212d8.336a88","name":"","x":596.5,"y":654.1818237304688,"wires":[]},{"id":"387d2a5d.fa9d76","type":"debug","z":"b25212d8.336a88","name":"","active":true,"console":"false","complete":"true","x":371.5,"y":709.1818313598633,"wires":[]},{"id":"dfdee8d8.e1e74","type":"comment","z":"b25212d8.336a88","name":"ON/OFF Remote Controller","info":"Browserで接続すると、ON/OFF制御のボタンが表示される\n\nhttp://<Node-redのIP address>:1880/control","x":149.5,"y":588.1818237304688,"wires":[]},{"id":"baad2d25.311cc8","type":"debug","z":"b25212d8.336a88","name":"","active":true,"console":"false","complete":"true","x":601.5,"y":705.1818237304688,"wires":[]},{"id":"cd5ec784.0801d8","type":"template","z":"b25212d8.336a88","name":"ON/OFF button","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta charset=“UFT-8”>\n    <style>\n        body { background: #FAFAD2; }\n        h1 {color:black; font-family:sans-serif;}\n        button { width: 300px; height: 100px; font-size: 36px; border-radius: 10px; border-style: none; background-color: #aaaaaa;}\n        button:hover {background-color: #dddddd;}\n    </style>\n    <title> ON/OFF BUTTON </title>\n    <script language=\"javascript\" type=\"text/javascript\">\n        function OnButtonClick() {\n            location.href = \"/on\";\n        }\n        function OffButtonClick() {\n            location.href = \"/off\";\n        }\n    </script>\n</head>\n<body>\n\t<h1>HEMS Controller</h1>\n    <button type=\"button\" name=\"buttonOn\" onclick=\"OnButtonClick()\">ON</button> \n    <button type=\"button\" name=\"buttonOff\" onclick=\"OffButtonClick()\">OFF</button> <br/>\n</body>\n</html>","x":389.5,"y":653.1818237304688,"wires":[["8bb17ee2.8b71c","baad2d25.311cc8"]]},{"id":"2cd805cd.f6b84a","type":"function","z":"b25212d8.336a88","name":"Parse EL1","func":"// Parse ECHONET Lite packet\n// Assumption: OPC = 1\n\n//  OUTPUT:\n//  msg.elr.ip      // ip address (String)\n//  msg.elr.ehd     // EHD (Int)\n//  msg.elr.tid     // TID (Int)\n//  msg.elr.seoj    // SEOJ ([Int:device, Int:instance])\n//  msg.elr.deoj    // DEOJ ([Int:device, Int:instance])\n//  msg.elr.esv     // ESV (Int)\n//  msg.elr.opc     // OPC (Int)\n//  msg.elr.epc     // EPC (Int)\n//  msg.elr.pdc     // PDC (Int)\n//  msg.elr.edt     // EDT ([Int]) or [](no EDT data)\n\nconst buffer = msg.payload;\nmsg.elr = null;\n\nif (buffer.length >= 14) {\n  const ehd_buffer = buffer.slice(0, 2);\n  const tid_buffer = buffer.slice(2, 4);\n  const seoj_device_buffer = buffer.slice(4, 6);\n  const seoj_instance_buffer = buffer.slice(6, 7);\n  const deoj_device_buffer = buffer.slice(7, 9);\n  const deoj_instance_buffer = buffer.slice(9, 10);\n  const esv_buffer = buffer.slice(10, 11);\n  const opc_buffer = buffer.slice(11, 12);\n  const epc_buffer = buffer.slice(12, 13);\n  const pdc_buffer = buffer.slice(13, 14);\n\n  const ehd = ehd_buffer.readUInt16BE(0);\n  const tid = tid_buffer.readUInt16BE(0);\n  const seoj_device = seoj_device_buffer.readUInt16BE(0);\n  const seoj_instance = seoj_instance_buffer.readUInt8(0);\n  const seoj = [seoj_device, seoj_instance];\n  const deoj_device = deoj_device_buffer.readUInt16BE(0);\n  const deoj_instance = deoj_instance_buffer.readUInt8(0);\n  const deoj = [deoj_device, deoj_instance];\n  const esv = esv_buffer.readUInt8(0);\n  const opc = opc_buffer.readUInt8(0);\n  const epc = epc_buffer.readUInt8(0);\n  const pdc = pdc_buffer.readUInt8(0);\n  let edt = [];\n  \n  if (buffer.length >= 15) {\n    const edt_buffer = buffer.slice(14);\n    for (var i = 0; i < edt_buffer.length; i++) {\n        edt[i] = edt_buffer.readUInt8(i);\n    }\n  }\n\n  // ECHONET Lite header check\n  if (ehd == 0x1081) {\n    msg.elr = {\n        \"ip\"            : msg.ip,\n        \"ehd\"           : ehd,\n        \"tid\"           : tid,\n        \"seoj\"          : seoj,\n        \"deoj\"          : deoj,\n        \"esv\"           : esv,\n        \"opc\"           : opc,\n        \"epc\"           : epc,\n        \"pdc\"           : pdc,\n        \"edt\"           : edt\n    };\n  }\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":324,"y":458,"wires":[["f79f22e2.9b9448","c709dd31.ebd05"]]},{"id":"f79f22e2.9b9448","type":"function","z":"b25212d8.336a88","name":"filter keyStatus","func":"//  msg.elr.ip      // ip address (String)\n//  msg.elr.ehd     // EHD (Int)\n//  msg.elr.tid     // TID (Int)\n//  msg.elr.seoj    // SEOJ ([Int:device, Int:instance])\n//  msg.elr.deoj    // DEOJ ([Int:device, Int:instance])\n//  msg.elr.esv     // ESV (Int)\n//  msg.elr.opc     // OPC (Int)\n//  msg.elr.epc     // EPC (Int)\n//  msg.elr.pdc     // PDC (Int)\n//  msg.elr.edt     // EDT ([Int]) or [](no EDT data)\n\n// 電子錠 EOJ=0x026f, 開閉状態 EPC=0xe0\nif ((msg.elr.seoj[0] == 0x026f) && (msg.elr.epc == 0xe0)) {\n    msg.payload = msg.elr.edt[0];\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":519,"y":458,"wires":[["acff4917.ab63f8"]]},{"id":"acff4917.ab63f8","type":"switch","z":"b25212d8.336a88","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0x41","vt":"num"},{"t":"eq","v":"0x42","vt":"num"},{"t":"else"}],"checkall":"true","outputs":3,"x":682.5,"y":459,"wires":[["60038e3d.3ea5"],["49fe4793.c299c8"],[]]},{"id":"60038e3d.3ea5","type":"link out","z":"b25212d8.336a88","name":"0x41","links":["2ab8c00.fd8fd4"],"x":798.5,"y":446,"wires":[]},{"id":"49fe4793.c299c8","type":"link out","z":"b25212d8.336a88","name":"0x42","links":["7bab7379.ce52ac"],"x":800.5,"y":484,"wires":[]},{"id":"42922bec.b77014","type":"udp in","z":"b25212d8.336a88","name":"EL receive","iface":"","port":"3610","ipv":"udp4","multicast":"true","group":"224.0.23.0","datatype":"buffer","x":118,"y":459,"wires":[["2cd805cd.f6b84a","c617b521.c138c8","81a3a52d.f2ecd8"]]},{"id":"c617b521.c138c8","type":"debug","z":"b25212d8.336a88","name":"","active":true,"console":"false","complete":"false","x":324.5,"y":509,"wires":[]},{"id":"c709dd31.ebd05","type":"debug","z":"b25212d8.336a88","name":"","active":true,"console":"false","complete":"elr","x":520,"y":506,"wires":[]},{"id":"41393aaf.0409c4","type":"inject","z":"b25212d8.336a88","name":"Search","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":112,"y":1251,"wires":[["5819b7f9.f2929"]]},{"id":"5819b7f9.f2929","type":"function","z":"b25212d8.336a88","name":"Search","func":"//  msg.els.ip_string   // ip address (String)\n//  msg.els.tid         // TID (Int)\n//  msg.els.seoj        // SEOJ ([Int:device, Int:instance])\n//  msg.els.deoj        // DEOJ ([Int:device, Int:instance])\n//  msg.els.esv         // ESV (Int)\n//  msg.els.epc         // EPC (Int)\n//  msg.els.edt_int     // EDT ([Int])\n\nmsg.els = {\n    \"ip\" : \"224.0.23.0\",\n    \"tid\" : 5,\n    \"seoj\" : [0x05ff,1],\n    \"deoj\" : [0x0ef0,1],\n    \"esv\" : 0x62,\n    \"epc\" : 0xD6\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":301,"y":1260,"wires":[[]]},{"id":"d1d50d8a.9a455","type":"udp out","z":"b25212d8.336a88","name":"","addr":"","iface":"","port":"3610","ipv":"udp4","outport":"","base64":false,"multicast":"multi","x":769,"y":206,"wires":[]},{"id":"816be296.50e15","type":"inject","z":"b25212d8.336a88","name":"ON","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":146,"y":206,"wires":[["30b813d1.96d6f4","8f824877.268258"]]},{"id":"7b5baebc.d748d","type":"function","z":"b25212d8.336a88","name":"Send EL1","func":"// Send ECHONET Lite packet\n// Assumption: OPC = 1\n//\n//  Usage:\n//      Input following data\n//\n//  msg.els.ip      // ip address (String)\n//  msg.els.tid     // TID (Int)\n//  msg.els.seoj    // SEOJ ([Int:device, Int:instance])\n//  msg.els.deoj    // DEOJ ([Int:device, Int:instance])\n//  msg.els.esv     // ESV (Int)\n//  msg.els.epc     // EPC (Int)\n//  msg.els.edt     // EDT ([Int])\n//          // in case of no EDT data, no edt or []\n\nconst tid_buffer = Buffer.allocUnsafe(2);\nlet   seoj_buffer = Buffer.allocUnsafe(3);\nconst seoj = msg.els.seoj;\nlet   deoj_buffer = Buffer.allocUnsafe(3);\nconst deoj = msg.els.deoj;\nconst esv_buffer = Buffer.allocUnsafe(1);\nconst opc_buffer = Buffer.from([1]);\nconst epc_buffer = Buffer.allocUnsafe(1);\nconst pdc_buffer = Buffer.allocUnsafe(1);\nlet edt = msg.els.edt;\n\ntid_buffer.writeUInt16BE(msg.els.tid, 0);\nesv_buffer.writeUInt8(msg.els.esv, 0);\nepc_buffer.writeUInt8(msg.els.epc, 0);\n\nseoj_buffer.writeUInt16BE(seoj[0], 0);\nseoj_buffer.writeUInt8(seoj[1], 2);\ndeoj_buffer.writeUInt16BE(deoj[0], 0);\ndeoj_buffer.writeUInt8(deoj[1], 2);\n\n// edt[]からedt_bufferを作成\nif ((typeof edt) == \"undefined\") {\n    edt = [];\n}\n\nconst edt_buffer = Buffer.allocUnsafe(edt.length);\nfor (var i = 0; i < edt.length; i++) {\n    edt_buffer.writeUInt8(edt[i], i);\n}\n\npdc_buffer.writeUInt8(edt_buffer.length, 0);\n\n// Create ECHONET Lite packet\nconst el_buffer = Buffer.from([\n\t0x10, 0x81,\n\ttid_buffer[0], tid_buffer[1],\n\tseoj_buffer[0], seoj_buffer[1], seoj_buffer[2],\n\tdeoj_buffer[0], deoj_buffer[1], deoj_buffer[2],\n\tesv_buffer[0], opc_buffer[0], epc_buffer[0], pdc_buffer[0]]);\n\n// add EDT data\nif (edt_buffer.length !== 0) {\n    msg.payload = Buffer.concat([el_buffer, edt_buffer], \n        (el_buffer.length + edt_buffer.length));\n} else {\n    msg.payload = el_buffer;\n}\n\nmsg.ip = msg.els.ip;\nreturn msg;","outputs":1,"noerr":0,"x":547.5,"y":207,"wires":[["d1d50d8a.9a455","20a78033.c64988","2ecc22f4.b79f3e"]]},{"id":"20a78033.c64988","type":"debug","z":"b25212d8.336a88","name":"","active":true,"console":"false","complete":"ip","x":760,"y":262,"wires":[]},{"id":"8f824877.268258","type":"function","z":"b25212d8.336a88","name":"エアコン ON","func":"//  msg.els.ip_string   // ip address (String)\n//  msg.els.tid         // TID (Int)\n//  msg.els.seoj        // SEOJ ([Int:device, Int:instance])\n//  msg.els.deoj        // DEOJ ([Int:device, Int:instance])\n//  msg.els.esv         // ESV (Int)\n//  msg.els.epc         // EPC (Int)\n//  msg.els.edt_int     // EDT ([Int])\n\nmsg.els = {\n    \"ip\" : \"224.0.23.0\",\n    \"tid\" : 5,\n    \"seoj\" : [0x05ff,1],\n    \"deoj\" : [0x0130,1],\n    \"esv\" : 0x61,\n    \"epc\" : 0x80,\n    \"edt\" : [0x30]\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":348.5,"y":206,"wires":[["7b5baebc.d748d"]]},{"id":"30b813d1.96d6f4","type":"function","z":"b25212d8.336a88","name":"ライト ON","func":"//  msg.els.ip_string   // ip address (String)\n//  msg.els.tid         // TID (Int)\n//  msg.els.seoj        // SEOJ ([Int:device, Int:instance])\n//  msg.els.deoj        // DEOJ ([Int:device, Int:instance])\n//  msg.els.esv         // ESV (Int)\n//  msg.els.epc         // EPC (Int)\n//  msg.els.edt_int     // EDT ([Int])\n\nmsg.els = {\n    \"ip\" : \"224.0.23.0\",\n    \"tid\" : 5,\n    \"seoj\" : [0x05ff,1],\n    \"deoj\" : [0x0290,1],\n    \"esv\" : 0x61,\n    \"epc\" : 0x80,\n    \"edt\" : [0x30]\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":338.5,"y":248,"wires":[["7b5baebc.d748d"]]},{"id":"2bcde2cc.b0e0b6","type":"function","z":"b25212d8.336a88","name":"ライト OFF","func":"//  msg.els.ip_string   // ip address (String)\n//  msg.els.tid         // TID (Int)\n//  msg.els.seoj        // SEOJ ([Int:device, Int:instance])\n//  msg.els.deoj        // DEOJ ([Int:device, Int:instance])\n//  msg.els.esv         // ESV (Int)\n//  msg.els.epc         // EPC (Int)\n//  msg.els.edt_int     // EDT ([Int])\n\nmsg.els = {\n    \"ip\" : \"224.0.23.0\",\n    \"tid\" : 5,\n    \"seoj\" : [0x05ff,1],\n    \"deoj\" : [0x0290,1],\n    \"esv\" : 0x61,\n    \"epc\" : 0x80,\n    \"edt\" : [0x31]\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":334.5,"y":329,"wires":[["7b5baebc.d748d"]]},{"id":"46ac93c4.9bf35c","type":"function","z":"b25212d8.336a88","name":"エアコン OFF","func":"//  msg.els.ip_string   // ip address (String)\n//  msg.els.tid         // TID (Int)\n//  msg.els.seoj        // SEOJ ([Int:device, Int:instance])\n//  msg.els.deoj        // DEOJ ([Int:device, Int:instance])\n//  msg.els.esv         // ESV (Int)\n//  msg.els.epc         // EPC (Int)\n//  msg.els.edt_int     // EDT ([Int])\n\nmsg.els = {\n    \"ip\" : \"224.0.23.0\",\n    \"tid\" : 5,\n    \"seoj\" : [0x05ff,1],\n    \"deoj\" : [0x0130,1],\n    \"esv\" : 0x61,\n    \"epc\" : 0x80,\n    \"edt\" : [0x31]\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":348.5,"y":289,"wires":[["7b5baebc.d748d"]]},{"id":"9231a3bb.ce8bc","type":"inject","z":"b25212d8.336a88","name":"OFF","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":149,"y":290,"wires":[["2bcde2cc.b0e0b6","46ac93c4.9bf35c"]]},{"id":"2ecc22f4.b79f3e","type":"debug","z":"b25212d8.336a88","name":"","active":true,"console":"false","complete":"false","x":780,"y":308,"wires":[]},{"id":"fad08edd.8db6c8","type":"link in","z":"b25212d8.336a88","name":"UDP send","links":[],"x":605,"y":269,"wires":[["d1d50d8a.9a455"]]},{"id":"81a3a52d.f2ecd8","type":"link out","z":"b25212d8.336a88","name":"UDP receive","links":[],"x":177.5,"y":513,"wires":[]},{"id":"48da7a43.d0e234","type":"function","z":"b25212d8.336a88","name":"Search","func":"//  msg.els.ip_string   // ip address (String)\n//  msg.els.tid         // TID (Int)\n//  msg.els.seoj        // SEOJ ([Int:device, Int:instance])\n//  msg.els.deoj        // DEOJ ([Int:device, Int:instance])\n//  msg.els.esv         // ESV (Int)\n//  msg.els.epc         // EPC (Int)\n//  msg.els.edt_int     // EDT ([Int])\n\nmsg.els = {\n    \"ip\" : \"224.0.23.0\",\n    \"tid\" : 0x30f0,\n    \"seoj\" : [0x05ff,1],\n    \"deoj\" : [0x0ef0,1],\n    \"esv\" : 0x62,\n    \"epc\" : 0xd6,\n    \"edt\" : []\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":158,"wires":[["7b5baebc.d748d"]]},{"id":"276ccd10.744a02","type":"comment","z":"b25212d8.336a88","name":"Send EL1","info":"Description: msg.elsの値を元にECHONET Liteのバイナリーデータを作成しUDP送信nodeに値を渡す\n\nAssumption: OPC = 1\n\nUsage: 以下のデータを入力します\n\n- msg.els.ip\n    - Content: ip address\n    - Data Type: String\n    - Sample: \"224.0.23.0\"\n- msg.els.tid\n    - Content: TID\n    - Data Type: Int\n    - Sample: 0x0101\n- msg.els.seoj\n    - Content: SEOJ\n    - Data Type: [Int:device, Int:instance]\n    - device: EOJ, instance: instance number\n    - Sample: [0x05ff, 0x01]\n- msg.els.deoj\n    - Content: DEOJ\n    - Data Type: [Int:device, Int:instance]\n    - device: EOJ, instance: instance number\n    - Sample: [0x0130, 0x01]\n- msg.els.esv\n    - Content: ESV\n    - Data Type: Int\n    - Sample: 0x62\n- msg.els.epc\n    - Content: EPC\n    - Data Type: Int\n    - Sample: 0x80\n- msg.els.edt\n    - Content: EDT\n    - Data Type: [Int]\n    - Sample: [0x30]\n    - Note: in case of no EDT data, []","x":546.5,"y":168,"wires":[]},{"id":"ac7445a8.9d057","type":"comment","z":"b25212d8.336a88","name":"Parse EL1","info":"Description: UDP受信nodeから渡されたデータをパースしmsg.elrとして渡す\n\nAssumption: OPC = 1\n\nUsage: 以下のデータを出力する\n\n- msg.elr.ip\n    - Content: ip address\n    - Data Type: String\n    - Sample: \"224.0.23.0\"\n- msg.elr.ehd\n    - Content: EHD\n    - Data Type: Int\n    - Sample: 0x1081\n- msg.elr.tid\n    - Content: TID\n    - Data Type: Int\n    - Sample: 0x0101\n- msg.elr.seoj\n    - Content: SEOJ\n    - Data Type: [Int:device, Int:instance]\n    - device: EOJ, instance: instance number\n    - Sample: [0x05ff, 0x01]\n- msg.elr.deoj\n    - Content: DEOJ\n    - Data Type: [Int:device, Int:instance]\n    - device: EOJ, instance: instance number\n    - Sample: [0x0130, 0x01]\n- msg.elr.esv\n    - Content: ESV\n    - Data Type: Int\n    - Sample: 0x62\n- msg.elr.opc\n    - Content: OPC\n    - Data Type: Int\n    - Sample: 0x01\n- msg.elr.epc\n    - Content: EPC\n    - Data Type: Int\n    - Sample: 0x80\n- msg.elr.pdc\n    - Content: PDC\n    - Data Type: Int\n    - Sample: 0x01\n- msg.elr.edt\n    - Content: EDT\n    - Data Type: [Int]\n    - Sample: [0x30]\n    - Note: in case of no EDT data, []","x":313,"y":419,"wires":[]}]
7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8