UNPKG

node-red-contrib-mobius-flow-dali

Version:

Node-RED nodes to work with MOBiUSFlow and DALI devices

384 lines (383 loc) 13.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CircuitFlashInterface = void 0; const events_1 = require("events"); const dali_linker_1 = require("./dali-linker"); class CircuitFlashInterface extends events_1.EventEmitter { circuit; daliMaster; flashLoop; currentlyFlashing; devices = []; deviceIndex = 0; selectedObjectIns = '0001'; addressingMode = 'short'; onLevel = 80; offLevel = 0; flashRate = 750; groupAddress = 0; linker; constructor(conID, getNode) { super(); this.daliMaster = getNode(conID).connection; this.circuit = this.daliMaster.circuit.split('/')[1]; this.flashLoop = null; this.currentlyFlashing = false; this.linker = new dali_linker_1.DaliLinker(this.daliMaster.circuit.split('/')[0], this.circuit, this.daliMaster.serviceConn); } /** * Send status update * @param message - Status update message */ updateStatus(message) { this.emit('flashNotification', message); } /** * Send updated device list */ sendUpdatedDeviceList() { this.emit('interfaceLuminaireDevices', this.devices); } /** * Send updated object list */ sendUpdatedObjectList() { this.linker.fetchObjects('0258', (err, response) => { if (!err) { const objects = []; for (let i = 0; i < response.length; i++) { objects.push({ daliAddress: response[i].daliAddress, ins: response[i].ins, selected: (() => (response[i].ins === this.selectedObjectIns) ? true : false)() }); } this.emit('interfaceLuminaireObjects', objects); } else { this.updateStatus(err); } }); } /** * Update the device list * @param deviceList - The new device list */ updateDeviceList(deviceList) { this.devices = deviceList; for (let i = 0; i < this.devices.length; i++) { this.devices[i].selected = (i === this.deviceIndex) ? true : false; } this.linker.fetchObjects('0258', (err, response) => { if (!err) { const linkedAddresses = []; const instances = []; for (let i = 0; i < response.length; i++) { if (response[i].daliAddress !== -1) { linkedAddresses.push(response[i].daliAddress); instances.push(response[i].ins); } } for (let i = 0; i < this.devices.length; i++) { if (!this.devices[i].linked) { for (let j = 0; j < linkedAddresses.length; j++) { if (this.devices[i].daliAddress === linkedAddresses[j]) { this.devices[i].linked = true; this.devices[i].linkedTo = instances[j]; } } } } this.sendUpdatedDeviceList(); } else { this.updateStatus(err); this.sendUpdatedDeviceList(); } }); } /** * Update the flash settings * @param addrMode - The new addressing mode (short / group / broadcast) * @param onLevel - The new on light level (0 - 100) * @param offLevel - The new off light level (0 - 100) * @param rate - The flash rate */ updateSettings(addrMode, onLevel, offLevel, rate) { this.addressingMode = addrMode; this.onLevel = onLevel; this.offLevel = offLevel; this.flashRate = rate; } /** * Select a device within the device list * @param addr - The DALI short address of the device to be selected */ selectDevice(addr) { switch (this.addressingMode) { case 'short': for (let i = 0; i < this.devices.length; i++) { if (this.devices[i].daliAddress === addr) { this.devices[i].selected = true; this.deviceIndex = i; } else { this.devices[i].selected = false; } } this.sendUpdatedDeviceList(); break; case 'group': this.groupAddress = addr; break; } if (this.currentlyFlashing) { this.stopFlash(); this.startFlash(); } this.notifyOfStateChange(addr); } /** * Select a new mobius luminaire object * @param ins - The ins of the mobius luminaire object to be selected (0001 - 003F) */ selectObject(ins) { this.selectedObjectIns = ins; this.sendUpdatedObjectList(); } /** * Send relevent notifications when a new device is selected * @param addr - DALI short address of new device */ notifyOfStateChange(addr) { switch (this.addressingMode) { case 'short': let isLinked = false; for (let i = 0; i < this.devices.length; i++) { if (this.devices[i].daliAddress === addr) { isLinked = this.devices[i].linked; } } if (this.currentlyFlashing) { this.updateStatus(isLinked ? `Flashing device ${addr} (already linked)` : `Flashing device ${addr}`); } else { this.updateStatus(isLinked ? `Device ${addr} selected (already linked)` : `Device ${addr} selected`); } this.sendUpdatedDeviceList(); break; case 'group': this.groupAddress = addr; this.updateStatus(this.currentlyFlashing ? `Flashing group ${addr}` : `Group ${addr} selected`); break; case 'broadcast': if (this.currentlyFlashing) { this.updateStatus('Flashing all'); } break; } } /** * Send a DALI command to control direct power to luminaires * @param addressingMode - The DALI addressing mode * @param address - The DALI address (group address or short address) * @param level - The set lighting level (0 - 100) */ sendDirectArcPowerCommand(addressingMode, address, level) { this.daliMaster.sendNormalDali({ topic: 'daliCommand', payload: { daliCircuitID: this.daliMaster.circuit.split('/')[1], daliCommandCode: 999, daliCommandName: 'Direct Power Control', daliAddressingMode: addressingMode, daliAddress: address, level: level } }); } /** * Start the flash process */ startFlash() { const addr = (this.addressingMode === 'short') ? this.devices[this.deviceIndex].daliAddress : this.groupAddress; if (this.devices.length >= 1 || this.addressingMode === 'broadcast') { let state = true; this.currentlyFlashing = true; this.notifyOfStateChange(addr); this.sendDirectArcPowerCommand(this.addressingMode, addr, this.offLevel); this.flashLoop = setInterval(() => { this.sendDirectArcPowerCommand(this.addressingMode, addr, (state ? this.onLevel : this.offLevel)); state = !state; }, this.flashRate); } else { this.updateStatus('No luminaires to flash'); } } /** * Stop the flash process */ stopFlash() { this.updateStatus(`Flash Stopped`); this.currentlyFlashing = false; clearInterval(this.flashLoop); let addr; if (this.addressingMode === 'short') { addr = this.devices[this.deviceIndex].daliAddress; } else { addr = this.groupAddress; } this.sendDirectArcPowerCommand(this.addressingMode, addr, this.onLevel); } /** * Select the next luminaire in the device list */ flashNext() { if (this.addressingMode === 'short') { this.devices[this.deviceIndex].selected = false; this.deviceIndex += 1; if (this.deviceIndex === this.devices.length) { this.deviceIndex = 0; } this.devices[this.deviceIndex].selected = true; this.sendUpdatedDeviceList(); this.notifyOfStateChange(this.devices[this.deviceIndex].daliAddress); if (this.currentlyFlashing) { this.stopFlash(); this.startFlash(); } } else { this.updateStatus('This function can only be used if short addressing is selected'); } } /** * Flash the previous luminaire in the device list */ flashPrevious() { if (this.addressingMode === 'short') { this.devices[this.deviceIndex].selected = false; this.deviceIndex -= 1; if (this.deviceIndex < 0) { this.deviceIndex = (this.devices.length - 1); } this.devices[this.deviceIndex].selected = true; this.sendUpdatedDeviceList(); this.notifyOfStateChange(this.devices[this.deviceIndex].daliAddress); if (this.currentlyFlashing) { this.stopFlash(); this.startFlash(); } } else { this.updateStatus('This function can only be used if short addressing is selected'); } } /** * Link the currently selected luminaire device to the currently selected mobius object */ linkLuminaire() { if (this.addressingMode === 'short') { if (this.devices.length >= 1) { for (let i = 0; i < this.devices.length; i++) { // Unlink any devices currently linked to the selected instance if (this.devices[i].linkedTo === this.selectedObjectIns) { this.devices[i].linked = false; this.devices[i].linkedTo = 'None'; } } if (!this.devices[this.deviceIndex].linked) { this.linker.link('0258', this.selectedObjectIns, this.devices[this.deviceIndex].daliAddress, (err) => { if (err) { this.updateStatus(`${err}`); } else { this.devices[this.deviceIndex].linked = true; this.devices[this.deviceIndex].linkedTo = this.selectedObjectIns; this.sendUpdatedDeviceList(); this.sendUpdatedObjectList(); this.updateStatus(`Linked device ${this.devices[this.deviceIndex].daliAddress} to object ${this.selectedObjectIns}`); } }); } else { this.updateStatus(`Device ${this.devices[this.deviceIndex].daliAddress} already linked`); } } else { this.updateStatus(`No devices to link`); } } else { this.updateStatus(`Linking can only be used when using short addressing`); } } /** * Unlink all luminaire objects */ unlinkAllMobObjects() { this.linker.unlinkAll('0258', (err) => { if (!err) { this.sendUpdatedObjectList(); } else { this.updateStatus(err); } }); for (let i = 0; i < this.devices.length; i++) { this.devices[i].linkedTo = 'None'; this.devices[i].linked = false; } this.sendUpdatedObjectList(); this.sendUpdatedDeviceList(); } /** * Unlink the selected luminaire object */ unlinkMobObject() { this.linker.unlink('0258', this.selectedObjectIns, (err) => { if (!err) { this.sendUpdatedObjectList(); } else { this.updateStatus(err); } }); for (let i = 0; i < this.devices.length; i++) { if (this.devices[i].linkedTo === this.selectedObjectIns) { this.devices[i].linkedTo = 'None'; this.devices[i].linked = false; } } this.sendUpdatedDeviceList(); } /** * Unlink a device / object pair as a result of a swap or delete process * @param addr - The DALI short address of the device within the pair to be unlinked */ unlinkOnSwap(addr) { let ins = ''; for (let i = 0; i < this.devices.length; i++) { if (this.devices[i].daliAddress === addr) { this.devices[i].linked = false; ins = this.devices[i].linkedTo; this.devices[i].linkedTo = 'None'; } } this.sendUpdatedDeviceList(); this.linker.unlink('0258', ins, (err) => { if (!err) { this.sendUpdatedObjectList(); } else { this.updateStatus(err); } }); } changeToThisCircuit() { this.sendUpdatedDeviceList(); this.sendUpdatedObjectList(); } } exports.CircuitFlashInterface = CircuitFlashInterface;