const CONTROLLER_ID="550"; const senzori = [ "7c:c6:b6:74:a4:be", "7c:c6:b6:75:a1:21" ]; const temperature = ["22.0", "22.0"]; const humidity = ["50", "50"]; 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 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[0x3a] = { n: "Button", t: uint8 }; BTH[0x2e] = { n: "Humidity", t: uint8 }; BTH[0x45] = { n: "Temperature", 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 (typeof(_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; }, }; function sendToZoblak() { const url = "http://agrar.zoblak.com/api/v1.0/sensorData"; const owner = "Controller: " + CONTROLLER_ID; const payload = { owner: owner, temperatureValue: temperature[0], humidityValue: humidity[0], controllerId: CONTROLLER_ID, temperatures: temperature }; Shelly.call( "HTTP.POST", { "url": url, "body": JSON.stringify(payload) }, function(result) { if (result) { print("server says: ", result.code); } else { print("There is no server response present. Check connection!") } } ); } function handleScanResult(event, result) { if(event === BLE.Scanner.SCAN_RESULT) { for (var i in senzori) { if(result.addr === senzori[i]) { let data = ShellyBLUParser.getData(result); if(data.Temperature && data.Humidity) { temperature[i] = data.Temperature.toString(); humidity[i] = data.Humidity.toString(); sendToZoblak(); } else { console.log("Nesto nije uredu"); } } } } } //BLE.Scanner.Subscribe(handleScanResult); BLE.Scanner.Start({ duration_ms: SCAN_DURATION, active: false }, handleScanResult);