Advertisement
-Teme-

BLE2mqtt

Aug 7th, 2023 (edited)
1,042
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. let mqttPrefix = Shelly.getComponentConfig( "mqtt" ).topic_prefix;
  2. let BTHOME_SVC_ID_STR = "fcd2";
  3. let last_packet_id;
  4.  
  5. let uint8  = 0;
  6. let int8   = 1;
  7. let uint16 = 2;
  8. let int16  = 3;
  9. let uint24 = 4;
  10. let int24  = 5;
  11. function getByteSize(type) {
  12.   if (type === uint8 || type === int8) return 1;
  13.   if (type === uint16 || type === int16) return 2;
  14.   if (type === uint24 || type === int24) return 3;
  15.   return null;
  16. }
  17. let BTH = [];
  18. BTH[0x00] = { n: "pid", t: uint8 };
  19. BTH[0x01] = { n: "battery", t: uint8 };
  20. BTH[0x02] = { n: "Temperature", t: int16, f: 0.01 };
  21. BTH[0x03] = { n: "Humidity", t: uint16, f: 0.01 };
  22. BTH[0x05] = { n: "lux", t: uint24, f: 0.01 };
  23. //BTH[0x1a] = { n: "Door", t: uint8 };
  24. //BTH[0x20] = { n: "Moisture", t: uint8 };
  25. BTH[0x21] = { n: "motion", t: uint8 };
  26. BTH[0x2d] = { n: "state", t: uint8 };
  27. BTH[0x3a] = { n: "button", t: uint8 };
  28. BTH[0x3f] = { n: "tilt", t: int16, f: 0.1 };
  29. let buttonEvent = ["-","S","SS","SSS","L"];
  30. let BTHomeDecoder = {
  31.   utoi: function (num, bitsz) {
  32.     let mask = 1 << (bitsz - 1);
  33.     return num & mask ? num - (1 << bitsz) : num;
  34.   },
  35.   getUInt8: function (buffer) {
  36.     return buffer.at(0);
  37.   },
  38.   getInt8: function (buffer) {
  39.     return this.utoi(this.getUInt8(buffer), 8);
  40.   },
  41.   getUInt16LE: function (buffer) {
  42.     return 0xffff & ((buffer.at(1) << 8) | buffer.at(0));
  43.   },
  44.   getInt16LE: function (buffer) {
  45.     return this.utoi(this.getUInt16LE(buffer), 16);
  46.   },
  47.   getUInt24LE: function (buffer) {
  48.     return (
  49.       0x00ffffff & ((buffer.at(2) << 16) | (buffer.at(1) << 8) | buffer.at(0))
  50.     );
  51.   },
  52.   getInt24LE: function (buffer) {
  53.     return this.utoi(this.getUInt24LE(buffer), 24);
  54.   },
  55.   getBufValue: function (type, buffer) {
  56.     if (buffer.length < getByteSize(type)) return null;
  57.     let res = null;
  58.     if (type === uint8)  res = this.getUInt8(buffer);
  59.     if (type === int8)   res = this.getInt8(buffer);
  60.     if (type === uint16) res = this.getUInt16LE(buffer);
  61.     if (type === int16)  res = this.getInt16LE(buffer);
  62.     if (type === uint24) res = this.getUInt24LE(buffer);
  63.     if (type === int24)  res = this.getInt24LE(buffer);
  64.     return res;
  65.   },
  66.   unpack: function (buffer) {
  67.     // beacons might not provide BTH service data
  68.     if (typeof buffer !== "string" || buffer.length === 0) return null;
  69.     let result = {};
  70.     let _dib = buffer.at(0);
  71.     result["encryption"] = _dib & 0x1 ? true : false;
  72.     result["BTHome_version"] = _dib >> 5;
  73.     if (result["BTHome_version"] !== 2) return null;
  74.     //Can not handle encrypted data
  75.     if (result["encryption"]) return result;
  76.     buffer = buffer.slice(1);
  77.  
  78.     let _bth;
  79.     let _value;
  80.     while (buffer.length > 0) {
  81.       _bth = BTH[buffer.at(0)];
  82.       if (typeof _bth === "undefined") {
  83.         console.log("BTH: unknown type",buffer.at(0));
  84.         break;
  85.       }
  86.       buffer = buffer.slice(1);
  87.       _value = this.getBufValue(_bth.t, buffer);
  88.       if (_value === null) break;
  89.       if (typeof _bth.f !== "undefined") _value = _value * _bth.f;
  90.       result[_bth.n] = _value;
  91.       buffer = buffer.slice(getByteSize(_bth.t));
  92.     }
  93.     return result;
  94.   },
  95. };
  96.  
  97. function shellyBLUParser(res)
  98. {
  99.     let result  = BTHomeDecoder.unpack( res.service_data[BTHOME_SVC_ID_STR] );
  100.     result.addr = res.addr;
  101.     result.rssi = res.rssi;
  102.     return result;
  103. }
  104.  
  105. BLE.Scanner.Start( {duration_ms: BLE.Scanner.INFINITE_SCAN},
  106.     function(event,result,ud)
  107.     {
  108.         if( event === BLE.Scanner.SCAN_RESULT &&
  109.             result !== null &&
  110.             result.service_data !== undefined &&
  111.             result.service_data[BTHOME_SVC_ID_STR] !== undefined )
  112.         {
  113.             let BTHparsed = shellyBLUParser( result );
  114.             if( BTHparsed !== null )
  115.             {
  116.                 print( JSON.stringify( BTHparsed ) );
  117.                 if( last_packet_id !== BTHparsed.pid )
  118.                 {
  119.                     last_packet_id = BTHparsed.pid;
  120.                     if( BTHparsed.button !== undefined )
  121.                     {
  122.                         BTHparsed.button = buttonEvent[BTHparsed.button];
  123.                     }
  124.                     if( BTHparsed.state !== undefined )
  125.                     {
  126.                         BTHparsed.state = BTHparsed.state ? "open" : "close";
  127.                     }
  128.                     MQTT.publish( "shellies/BLU/" + result.addr +"/ble", JSON.stringify( BTHparsed ), 1, false );
  129.                 }
  130.             }
  131.         }
  132.     } );
  133.  
  134. print( "started" );
Tags: Shelly mqtt blu
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement