# Shelly blu DW sensor -\> shelly plus plug s scripting -\> node-red

**URL:** <https://discourse.nodered.org/t/shelly-blu-dw-sensor-shelly-plus-plug-s-scripting-node-red/81245>\
**Category:** General\
**Tags:** http-request\
**Created:** [12 September 2023 16:09 UTC](https://discourse.nodered.org/t/shelly-blu-dw-sensor-shelly-plus-plug-s-scripting-node-red/81245 "2023-09-12T16:09:06Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![juntiedt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/juntiedt/32/58357_2.png) [@juntiedt](https://discourse.nodered.org/u/juntiedt)\
**Post date:** [12 September 2023 16:09 UTC](https://discourse.nodered.org/t/shelly-blu-dw-sensor-shelly-plus-plug-s-scripting-node-red/81245/1 "2023-09-12T16:09:06Z")

</div>

I just got my new shelly blu DW sensor which is small and has low energy usage.  
I managed to connect it to a shelly plus Plug s and it works ok. Now I want to create actions within the shelly script on the plug s in order to send the status of the window to node-red. The plug should be a relais station of 3 DW sensors.  
I need help in doing this in the script.

I am already sending http messages (actions) from a shelly button to node red which works ok.  
That is excatly what I want to achive in my script.

---

<div class="post-metadata">

**Author:** ![juntiedt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/juntiedt/32/58357_2.png) [@juntiedt](https://discourse.nodered.org/u/juntiedt)\
**Post date:** [13 September 2023 16:36 UTC](https://discourse.nodered.org/t/shelly-blu-dw-sensor-shelly-plus-plug-s-scripting-node-red/81245/2 "2023-09-13T16:36:10Z")

</div>

The problem is solved.  
The shelly blu door window sensor is realy very good. It is small and due to ble very efficient. In order to use it in node-red you need to use a shelly plus or shelly pro and a script running on these shellies.  
I am using http request to connect the shelly as a relay for the bluetooth sensor to node-red but there are scripts using mqtt.

Here the script:

```auto
/**
 * This script uses the BLE scan functionality in scripting
 * Selects Shelly BLU DoorWindow from the aired advertisements, decodes
 * the service data payload and toggles a relay on the device on
 * button push
 */

// Shelly BLU devices:
// SBBT - Shelly BLU Button
// SBDW - Shelly BLU DoorWindow

// sample Shelly DW service_data payload
// 0x40 0x00 0x4E 0x01 0x64 0x05 0x00 0x00 0x00 0x2D 0x01 0x3F 0x00 0x00

// First byte: BTHome device info, 0x40 - no encryption, BTHome v.2
// bit 0: “Encryption flag”
// bit 1-4: “Reserved for future use”
// bit 5-7: “BTHome Version”

// AD 0: PID, 0x00
// Value: 0x4E

// AD 1: Battery, 0x01
// Value, 100%

// AD 2: Illuminance, 0x05
// Value: 0

// AD 3: Window, 0x2D
// Value: true, open

// AD 4: Rotation, 0x3F
// Value: 0

// Device name can be obtained if an active scan is performed
// You can rely only on the addresss filtering and forego device name matching

// CHANGE HERE

//Shelly Call Error Check
//HTTP Methode Error Check

function HTTP_ErrorCheck(response, extra) {
        if (response.code !== 200) {
            print('Error: Http call');
            print('Response: ', JSON.stringify(response));
            print('eMsg: ', response.message);
        }
        if (typeof (extra) !== 'undefined') {
            if (typeof (extra) === 'function') extra(response);
            if (typeof (extra) === 'object') extra.CallBack(response, extra.data);
        }
}

function Call_ErrorCheck(response, shellyCall_error_code, shellyCall_error_message, extra) {
        if (shellyCall_error_code !== 0) {
            print('Error: Shelly.call()');
            print('Response: ', JSON.stringify(response));
            print('eMsg: ', shellyCall_error_message);
            print('Response type is: ', typeof (response));
            if (typeof (response) !== 'object') {
                response = { callError: true, orgResponse: response };
            } else {
                response.callError = true;
            }
        }
        if (typeof (response) !== 'object') {
            response = { changedToObj: true, orgResponse: response };
        }
        if (typeof (extra) !== 'undefined') {
            if (typeof (extra) === 'function') extra(response);
            if (typeof (extra) === 'object') extra.CallBack(response, extra.data);
        }
}

function printOpen() {
  print("Window is open, will toggle the output");
  Shelly.call("Switch.set", { id: 0, on: true });
  Shelly.call('HTTP.GET', {url:"http://10.0.0.50:1880/output?s=shelly_DW-UGBU_1:open", timeout: 30}, Call_ErrorCheck, HTTP_ErrorCheck);
}

function printClosed() {
  print("Window is closed, will toggle the output");
  Shelly.call("Switch.set", { id: 0, on: false });
  Shelly.call('HTTP.GET', {url:"http://10.0.0.50:1880/output?s=shelly_DW-UGBU_1:closed", timeout: 30}, Call_ErrorCheck, HTTP_ErrorCheck);
}

// remove name prefix to not filter by device name
// remove address to not filter by address

let CONFIG = {
  //shelly_blu_name_prefix: 'SBDW',
  //"BIND" to only this address
  shelly_blu_address: "60:ef:ab:42:d4:a1",
  actions: [
    {
      cond: {
        Window: 0,
      },
      action: printClosed,
    },
    {
      cond: {
        Window: 1,
      },
      action: printOpen,
    },
  ],
};
// END OF CHANGE

let ALLTERCO_MFD_ID_STR = "0ba9";
let BTHOME_SVC_ID_STR = "fcd2";

let ALLTERCO_MFD_ID = JSON.parse("0x" + ALLTERCO_MFD_ID_STR);
let BTHOME_SVC_ID = JSON.parse("0x" + BTHOME_SVC_ID_STR);

let SCAN_DURATION = BLE.Scanner.INFINITE_SCAN;
let ACTIVE_SCAN =
  typeof CONFIG.shelly_blu_name_prefix !== "undefined" &&
  CONFIG.shelly_blu_name_prefix !== null;

let uint8 = 0;
let int8 = 1;
let uint16 = 2;
let int16 = 3;
let uint24 = 4;
let int24 = 5;

function getByteSize(type) {
  if (type === uint8 || type === int8) return 1;
  if (type === uint16 || type === int16) return 2;
  if (type === uint24 || type === int24) return 3;
  //impossible as advertisements are much smaller;
  return 255;
}

let BTH = [];
BTH[0x00] = { n: "pid", t: uint8 };
BTH[0x01] = { n: "Battery", t: uint8, u: "%" };
BTH[0x05] = { n: "Illuminance", t: uint24, f: 0.01 };
BTH[0x1a] = { n: "Door", t: uint8 };
BTH[0x20] = { n: "Moisture", t: uint8 };
BTH[0x2d] = { n: "Window", t: uint8 };
BTH[0x3a] = { n: "Button", t: uint8 };
BTH[0x3f] = { n: "Rotation", t: int16, f: 0.1 };

let BTHomeDecoder = {
  utoi: function (num, bitsz) {
    let mask = 1 << (bitsz - 1);
    return num & mask ? num - (1 << bitsz) : num;
  },
  getUInt8: function (buffer) {
    return buffer.at(0);
  },
  getInt8: function (buffer) {
    return this.utoi(this.getUInt8(buffer), 8);
  },
  getUInt16LE: function (buffer) {
    return 0xffff & ((buffer.at(1) << 8) | buffer.at(0));
  },
  getInt16LE: function (buffer) {
    return this.utoi(this.getUInt16LE(buffer), 16);
  },
  getUInt24LE: function (buffer) {
    return (
      0x00ffffff & ((buffer.at(2) << 16) | (buffer.at(1) << 8) | buffer.at(0))
    );
  },
  getInt24LE: function (buffer) {
    return this.utoi(this.getUInt24LE(buffer), 24);
  },
  getBufValue: function (type, buffer) {
    if (buffer.length < getByteSize(type)) return null;
    let res = null;
    if (type === uint8) res = this.getUInt8(buffer);
    if (type === int8) res = this.getInt8(buffer);
    if (type === uint16) res = this.getUInt16LE(buffer);
    if (type === int16) res = this.getInt16LE(buffer);
    if (type === uint24) res = this.getUInt24LE(buffer);
    if (type === int24) res = this.getInt24LE(buffer);
    return res;
  },
  unpack: function (buffer) {
    // beacons might not provide BTH service data
    if (typeof buffer !== "string" || buffer.length === 0) return null;
    let result = {};
    let _dib = buffer.at(0);
    result["encryption"] = _dib & 0x1 ? true : false;
    result["BTHome_version"] = _dib >> 5;
    if (result["BTHome_version"] !== 2) return null;
    //Can not handle encrypted data
    if (result["encryption"]) return result;
    buffer = buffer.slice(1);

    let _bth;
    let _value;
    while (buffer.length > 0) {
      _bth = BTH[buffer.at(0)];
      if (_bth === "undefined") {
        console.log("BTH: unknown type");
        break;
      }
      buffer = buffer.slice(1);
      _value = this.getBufValue(_bth.t, buffer);
      if (_value === null) break;
      if (typeof _bth.f !== "undefined") _value = _value * _bth.f;
      result[_bth.n] = _value;
      buffer = buffer.slice(getByteSize(_bth.t));
    }
    return result;
  },
};

let ShellyBLUParser = {
  getData: function (res) {
    let result = BTHomeDecoder.unpack(res.service_data[BTHOME_SVC_ID_STR]);
    result.addr = res.addr;
    result.rssi = res.rssi;
    return result;
  },
};

let last_packet_id = 0x100;
function scanCB(ev, res) {
  if (ev !== BLE.Scanner.SCAN_RESULT) return;
  // skip if there is no service_data member
  if (
    typeof res.service_data === "undefined" ||
    typeof res.service_data[BTHOME_SVC_ID_STR] === "undefined"
  )
    return;
  // skip if we are looking for name match but don't have active scan as we don't have name
  if (
    typeof CONFIG.shelly_blu_name_prefix !== "undefined" &&
    (typeof res.local_name === "undefined" ||
      res.local_name.indexOf(CONFIG.shelly_blu_name_prefix) !== 0)
  )
    return;
  // skip if we don't have address match
  if (
    typeof CONFIG.shelly_blu_address !== "undefined" &&
    CONFIG.shelly_blu_address !== res.addr
  )
    return;
  let BTHparsed = ShellyBLUParser.getData(res);
  // skip if parsing failed
  if (BTHparsed === null) {
    console.log("Failed to parse BTH data");
    return;
  }
  // skip, we are deduping results
  if (last_packet_id === BTHparsed.pid) return;
  last_packet_id = BTHparsed.pid;
  console.log("Shelly BTH packet: ", JSON.stringify(BTHparsed));
  // execute actions from CONFIG
  let aIdx = null;
  for (aIdx in CONFIG.actions) {
    // skip if no condition defined
    if (typeof CONFIG.actions[aIdx]["cond"] === "undefined") continue;
    let cond = CONFIG.actions[aIdx]["cond"];
    let cIdx = null;
    let run = true;
    for (cIdx in cond) {
      if (typeof BTHparsed[cIdx] === "undefined") run = false;
      if (BTHparsed[cIdx] !== cond[cIdx]) run = false;
    }
    // if all conditions evaluated to true then execute
    if (run) CONFIG.actions[aIdx]["action"](BTHparsed);
  }
}

BLE.Scanner.Start({ duration_ms: SCAN_DURATION, active: ACTIVE_SCAN }, scanCB);

```

and here my node-red nodes to receive the requests

```auto
[{"id":"bcf7383f.7d7018","type":"http in","z":"c9f02597841e11f7","name":"output","url":"/output","method":"get","upload":true,"swaggerDoc":"","x":70,"y":780,"wires":[["8146164e.545918"]]},{"id":"b2581bc3.ab74c8","type":"http response","z":"c9f02597841e11f7","name":"","statusCode":"200","headers":{},"x":400,"y":780,"wires":[]},{"id":"f0ea93fc.9a846","type":"html","z":"c9f02597841e11f7","name":"","property":"payload","outproperty":"payload","tag":"body","ret":"html","as":"single","x":150,"y":840,"wires":[["a55076ae.e77138"]]},{"id":"a55076ae.e77138","type":"function","z":"c9f02597841e11f7","name":"","func":"msg.payload = msg.payload[0];\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":840,"wires":[["da992246.5bfa6"]]},{"id":"8146164e.545918","type":"template","z":"c9f02597841e11f7","name":"shelly page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n <head></head>\n <body>\n {{req.query.s}}\n </body>\n</html>","x":210,"y":780,"wires":[["f0ea93fc.9a846","b2581bc3.ab74c8"]]},{"id":"da992246.5bfa6","type":"switch","z":"c9f02597841e11f7","name":"","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"shelly_Button1","vt":"str"},{"t":"cont","v":"shelly_Button2","vt":"str"},{"t":"cont","v":"shelly_1pm191","vt":"str"},{"t":"cont","v":"shelly_DW-UGBU_1","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":410,"y":840,"wires":[["800d2d48.b6b1d"],["4137125b8bfed28b"],["de0eae1240f50b8c"],["d68841ace2e51093"]]},{"id":"800d2d48.b6b1d","type":"switch","z":"c9f02597841e11f7","name":"shelly_Button1","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"shelly_Button1:s","vt":"str"},{"t":"eq","v":"shelly_Button1:ss","vt":"str"},{"t":"eq","v":"shelly_Button1:sss","vt":"str"},{"t":"eq","v":"shelly_Button1:l","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":640,"y":700,"wires":[["ce3ce537025552e1"],["1e1c8115.3ff44f"],["effaadcb.c1951"],["d03caf375de7919d"]]},{"id":"4137125b8bfed28b","type":"switch","z":"c9f02597841e11f7","name":"shelly_Button2","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"shelly_Button2:s","vt":"str"},{"t":"eq","v":"shelly_Button2:ss","vt":"str"},{"t":"eq","v":"shelly_Button2:sss","vt":"str"},{"t":"eq","v":"shelly_Button2:l","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":640,"y":1000,"wires":[["dfed5223dffde3ee"],["bfe2254927718aa3"],["3b45a66eafe26824"],["93c14f2e4800c612"]]},{"id":"de0eae1240f50b8c","type":"switch","z":"c9f02597841e11f7","name":"shelly_1pm191:on/off","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"shelly_1pm191:on","vt":"str"},{"t":"eq","v":"shelly_1pm191:off","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":660,"y":1160,"wires":[["5deae5fa4c7bf36f"],["3ba2d90c80e47596"]]},{"id":"d68841ace2e51093","type":"debug","z":"c9f02597841e11f7","name":"debug 7","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":580,"y":1260,"wires":[]}]

```

---

<div class="post-metadata">

**Author:** ![juntiedt](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/juntiedt/32/58357_2.png) [@juntiedt](https://discourse.nodered.org/u/juntiedt)\
**Post date:** [13 September 2023 16:40 UTC](https://discourse.nodered.org/t/shelly-blu-dw-sensor-shelly-plus-plug-s-scripting-node-red/81245/3 "2023-09-13T16:40:01Z")

</div>

sorry for the last post. How can I delete it?

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [27 September 2023 16:40 UTC](https://discourse.nodered.org/t/shelly-blu-dw-sensor-shelly-plus-plug-s-scripting-node-red/81245/4 "2023-09-27T16:40:35Z")

</div>

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.
