UNPKG

node-red-contrib-mobius-flow-dali

Version:

Node-RED nodes to work with MOBiUSFlow and DALI devices

302 lines (301 loc) 10.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CircuitAddressingInterface = void 0; const events_1 = require("events"); const daliCommon = require('@ia/dali-common'); class CircuitAddressingInterface extends events_1.EventEmitter { circuit; name; operationInProgress = false; outTopic = ''; addressingInProgress = false; devices = []; addresses = []; populatedDeviceIndex = 0; expNoDevices; addressingTimeout; scanningTimeout; scanningTimeoutTime; addressingTimeoutTime; queryingLoop; ungroupingLoop; daliMaster; constructor(addrTimeoutTime, scanningTimeoutTime, expectedDevices, conID, getNode) { super(); this.daliMaster = getNode(conID).connection; this.circuit = this.daliMaster.circuit.split('/')[1]; this.name = getNode(conID).name; this.expNoDevices = expectedDevices; this.addressingTimeoutTime = addrTimeoutTime; this.scanningTimeoutTime = scanningTimeoutTime; // Start Event listeners this.processFetchTypeResponse(); this.daliMaster.on('addressingStatus', (message) => { this.updateStatus(message); }); } /** * Send a notification * @param message - Message sent with notification */ updateStatus(message) { this.emit('addressingNotification', message); } /** * Ungroup all DALI devices */ ungroup() { this.operationInProgress = true; this.updateStatus(`Ungrouping All`); let i = 0; this.ungroupingLoop = setInterval(() => { this.daliMaster.sendNormalDali({ topic: 'daliCommand', payload: { daliCircuitID: this.circuit, daliCommandCode: 112 + i, daliCommandName: daliCommon.daliLookup.commandLookup[112 + i], daliAddressingMode: 'broadcast' } }); i = i + 1; this.updateStatus(`Ungrouping ${Math.round((i / 16) * 100)}% complete...`); if (i >= 16) { clearInterval(this.ungroupingLoop); this.updateStatus(`Ungrouping Complete`); this.operationInProgress = false; } }, 1500); } /** * Swap the short addresses of two DALI devices * @param addr1 - Current short address of device 1 * @param addr2 - Current short address of device 2 */ swap(addr1, addr2) { this.operationInProgress = true; this.updateStatus(`Swapped DALI addresses ${addr1} & ${addr2}, scan to confirm change`); this.daliMaster.addressSwap(addr1, addr2); this.operationInProgress = false; } /** * Delete the short address of a DALI device * @param addr - The current short address of the device to delete */ del(addr) { this.operationInProgress = true; this.updateStatus(`Deleted DALI address ${addr}, scan to confirm change`); this.daliMaster.addressDelete(addr); this.operationInProgress = false; } /** * Perform full addressing on DALI circuit */ addressCircuit() { this.operationInProgress = true; this.addressingInProgress = true; this.addresses = []; this.outTopic = 'daliAddress'; this.updateStatus(`DALI Addressing In Progress...`); this.startAddressingTimeout(); this.daliMaster.fullAddressCircuit(this.expNoDevices, (err, quantityOfFoundAddresses) => { if (!err) { this.finishAddressing(quantityOfFoundAddresses); } else { this.updateStatus(`Addressing Error: ${err}`); } }); } /** * Add any unaddressed devices to an already addressed circuit */ addToCircuit() { this.operationInProgress = true; this.addresses = []; this.outTopic = 'daliAdd'; this.startAddressingTimeout(); this.updateStatus(`Started DALI Addressing (Unaddressed Only)...`); this.daliMaster.addAddressToCircuit((err, quantityOfFoundAddresses) => { if (!err) { this.finishAddressing(quantityOfFoundAddresses); } else { this.updateStatus(`Addressing Error: ${err}`); } }); } /** * Finish an addressing process */ finishAddressing(quantityOfFoundAddresses) { this.daliMaster.abortAddressing(); this.stopAddressingTimeout(); this.addressingInProgress = false; this.updateStatus(`DALI Addressing Complete`); if (quantityOfFoundAddresses > 0) { this.scanCircuit(); } else { this.updateStatus(`No devices to addressed`); this.operationInProgress = false; } } /** * Scan a circuit for all devices with a defined short address */ scanCircuit() { this.operationInProgress = true; this.addresses = []; this.outTopic = 'daliScan'; this.startScanningTimeout(); this.daliMaster.scanCircuit((err, addresses) => { if (!err) { this.addresses = addresses; this.finishScan(); } else { this.updateStatus(`Addressing Error: ${err}`); } }); } /** * Finish a scan process */ finishScan() { this.updateStatus(`DALI Scan Complete`); this.addresses = [...new Set(this.addresses)]; if (this.addresses.length > 0) { this.queryTypes(); } else { this.updateStatus(`No devices found`); this.stopScanningTimeout(); this.operationInProgress = false; } } /** * Gather and store query responses when querying device types */ processFetchTypeResponse() { this.daliMaster.on('queryResponse', (msg) => { msg = JSON.parse(JSON.stringify(msg)); msg = daliCommon.daliMain.daliProcess(msg); if (this.operationInProgress === true && msg.payload.daliCommandCode === 153) { this.devices[this.populatedDeviceIndex] = { daliAddress: msg.payload.daliAddress, deviceType: msg.payload.responseData.deviceType, deviceTypeName: daliCommon.daliLookup.deviceTypeLookup[msg.payload.responseData.deviceType], linked: false, selected: false, linkedTo: 'None' }; } }); } /** * Query device types of all newly added devices */ queryTypes() { this.operationInProgress = true; this.devices = []; while (this.devices.length < this.addresses.length) { this.devices.push(null); } this.queryingLoop = setInterval(() => { let j = 0; let k = 0; while (j < this.devices.length) { if (this.devices[j] === null) { this.daliMaster.sendNormalDali({ topic: 'daliCommand', payload: { daliCircuitID: this.circuit, daliCommandCode: 153, daliCommandName: 'Query Device Type', daliAddressingMode: 'short', daliAddress: this.addresses[j], } }); j = 65; } else { k = k + 1; } j = j + 1; } this.updateStatus(`Querying Types ${Math.round((k / this.addresses.length) * 100)}% Complete`); this.populatedDeviceIndex = k; if (k === this.addresses.length) { clearInterval(this.queryingLoop); this.finishQuerying(); } }, 500); } /** * Finsih a querying device types process */ finishQuerying() { this.operationInProgress = false; this.stopScanningTimeout(); if (this.devices.length !== this.expNoDevices) { this.updateStatus(`Complete, Expected ${this.expNoDevices}, found ${this.devices.length}`); } else { this.updateStatus(`Complete`); } this.emit('daliAddressingFunction', { topic: this.outTopic, payload: { daliCircuitID: this.circuit, numberOfDevices: this.devices.length, expectedNumberOfDevices: this.expNoDevices, devices: this.devices } }); } /** * Start a timeout to ensure any given process continues for a maximum time */ startScanningTimeout() { this.scanningTimeout = setTimeout(() => { this.daliMaster.abortScanning(); clearInterval(this.queryingLoop); this.updateStatus('Scanning Timed Out'); this.operationInProgress = false; }, this.scanningTimeoutTime); } /** * Stop function timeout if a given process finishes */ stopScanningTimeout() { clearTimeout(this.scanningTimeout); } /** * Start a monitor to detect when no more devices are responding during an addressing process */ startAddressingTimeout() { this.addressingTimeout = setTimeout(() => { this.updateStatus('Addressing Finished due to timeout'); this.finishAddressing(0); }, this.addressingTimeoutTime); } /** * Stop the addressing monitor when addressing has finished */ stopAddressingTimeout() { clearTimeout(this.addressingTimeout); } /** * On node close: clear all intervals and timeouts, stop listening to events */ close() { clearInterval(this.queryingLoop); clearInterval(this.ungroupingLoop); clearTimeout(this.scanningTimeout); clearTimeout(this.addressingTimeout); this.daliMaster.removeAllListeners('queryResponse'); this.daliMaster.removeAllListeners('addressingResponse'); } } exports.CircuitAddressingInterface = CircuitAddressingInterface;