UNPKG

node-red-contrib-victron-ble

Version:

node-red node to parse Instant Readout advertisement data from Victron BLE devices

93 lines (92 loc) 3.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Scanner = void 0; const get_ble_adapter_1 = require("./ble/get-ble-adapter"); const devices_1 = require("./devices"); const events_1 = require("events"); class Scanner extends events_1.EventEmitter { adapterMode; ble = null; deviceKeys = {}; deviceRawOptions = {}; knownDevices = {}; discovered = new Map(); constructor(adapterMode = 'auto') { super(); this.adapterMode = adapterMode; } async start() { this.ble = await (0, get_ble_adapter_1.getBleAdapter)(this.adapterMode); if (!this.ble) return; this.ble.on('raw', (packet) => this.handleRawPacket(packet)); } async stop() { if (this.ble) await this.ble.stopScan(); } setSettings(address, key, includeRaw = false) { this.deviceKeys[address.toLowerCase()] = key; this.deviceRawOptions[address.toLowerCase()] = includeRaw; delete this.knownDevices[address.toLowerCase()]; } getDiscoveredDevices() { const devices = new Map(this.discovered); for (const device of this.ble?.getDiscoveredDevices() ?? []) { const address = device.address.toLowerCase(); const existing = devices.get(address); devices.set(address, { address, name: device.name ?? existing?.name ?? '', rssi: device.rssi ?? existing?.rssi ?? 0, }); } return Array.from(devices.values()); } handleRawPacket(packet) { const now = Date.now(); const address = packet.address.toLowerCase(); let dev = this.discovered.get(address); if (!dev) { dev = { address, name: packet.name || '', rssi: packet.rssi }; this.discovered.set(address, dev); } else { dev.name = packet.name || dev.name; dev.rssi = packet.rssi; } // Try to parse if we have a key if (this.deviceKeys[address]) { let emitRaw = true; try { if (packet.rawData.length > 0 && packet.rawData[0] == 0x10) { const deviceClass = (0, devices_1.detectDeviceType)(packet.rawData); if (!deviceClass) throw new Error(`Could not identify device type for ${address}`); let device = this.knownDevices[address]; if (!device) { device = new deviceClass(this.deviceKeys[address]); this.knownDevices[address] = device; } const parsedDevice = device.parse(packet.rawData); const payload = parsedDevice.toJson(); const parsedPacket = { ...packet, payload }; // copy decryptedData to packet if requested to send it out if (this.deviceRawOptions[address]) { parsedPacket.decryptedData = parsedPacket.payload.decryptedData.toString('hex'); } delete parsedPacket.payload.decryptedData; delete parsedPacket.rawData; this.emit('parsed', parsedPacket); emitRaw = false; } } catch (error) { // Parsing failed, emit as raw only } if (emitRaw) this.emit('raw', packet); } } } exports.Scanner = Scanner;