diff --git a/controller/Equipment.ts b/controller/Equipment.ts index a9bfdb75..96c7917c 100644 --- a/controller/Equipment.ts +++ b/controller/Equipment.ts @@ -115,6 +115,7 @@ export class PoolSystem implements IPoolSystem { } return cfg; } + public resetSystem() { conn.pause(); this.resetData(); @@ -143,6 +144,7 @@ export class PoolSystem implements IPoolSystem { public resetData() { if (sys.controllerType !== ControllerType.Virtual && sys.controllerType !== ControllerType.Nixie) { // Do not clear this out if it is a virtual controller this causes problems. + this.equipment.reset(); this.circuitGroups.clear(0); this.lightGroups.clear(0); this.circuits.clear(0); @@ -759,6 +761,9 @@ export class Equipment extends EqItem { public get controllerFirmware(): string { return this.data.softwareVersion; } public set bootloaderVersion(val: string) { this.setDataVal('bootloaderVersion', val); } public get bootloaderVersion(): string { return this.data.bootloaderVersion; } + public reset() { + + } setEquipmentIds() { this.data.equipmentIds = { circuits: { start: sys.board.equipmentIds.circuits.start, end: sys.board.equipmentIds.circuits.end }, diff --git a/controller/State.ts b/controller/State.ts index cd9be04e..fe3b270a 100644 --- a/controller/State.ts +++ b/controller/State.ts @@ -1425,6 +1425,7 @@ export class ChemControllerStateCollection extends EqStateCollection { - let id = typeof data.id !== 'undefined' ? parseInt(data.id, 10) : -1; - if (typeof id === 'undefined' || isNaN(id)) return Promise.reject(new InvalidEquipmentIdError(`Invalid Chem Controller Id`, id, 'chemController')); - let chem = sys.chemControllers.getItemById(id); - if (chem.type === sys.board.valueMaps.chemControllerTypes.getValue('intellichem') && !chem.isVirtual) - sys.board.virtualChemControllers.stop(); - let schem = state.chemControllers.getItemById(chem.id); - schem.isActive = chem.isActive = false; - await ncp.chemControllers.removeById(chem.id); - sys.chemControllers.removeItemById(chem.id); - state.chemControllers.removeItemById(chem.id); - sys.emitEquipmentChange(); - return Promise.resolve(chem); + try { + let id = typeof data.id !== 'undefined' ? parseInt(data.id, 10) : -1; + if (typeof id === 'undefined' || isNaN(id)) return Promise.reject(new InvalidEquipmentIdError(`Invalid Chem Controller Id`, id, 'chemController')); + let chem = sys.chemControllers.getItemById(id); + if (chem.type === sys.board.valueMaps.chemControllerTypes.getValue('intellichem') && !chem.isVirtual) + sys.board.virtualChemControllers.stop(); + let schem = state.chemControllers.getItemById(id); + schem.isActive = chem.isActive = false; + await ncp.chemControllers.removeById(id); + sys.chemControllers.removeItemById(id); + state.chemControllers.removeItemById(id); + sys.emitEquipmentChange(); + return Promise.resolve(chem); + } catch (err) { logger.error(`Error deleting chem controller ${err.message}`); } } public async manualDoseAsync(data: any): Promise { try { @@ -3409,10 +3411,11 @@ export class ChemControllerCommands extends BoardCommands { try { let chem = sys.chemControllers.find(elem => elem.id === data.id); if (typeof chem === 'undefined') return Promise.reject(`A valid IntelliChem controller could not be found at id ${data.id}`); + chem = sys.chemControllers.getItemById(chem.id, true); // Make sure we persist it. let address = typeof data.address !== 'undefined' ? parseInt(data.address, 10) : chem.address; if (typeof address === 'undefined' || isNaN(address) || (address < 144 || address > 158)) return Promise.reject(new InvalidEquipmentDataError(`Invalid IntelliChem address`, 'chemController', address)); - let pHSetpoint = typeof data.ph.setpoint !== 'undefined' ? parseFloat(data.ph.setpoint) : chem.ph.setpoint; - let orpSetpoint = typeof data.orp.setpoint !== 'undefined' ? parseInt(data.orp.setpoint, 10) : chem.orp.setpoint; + let pHSetpoint = typeof data.ph !== 'undefined' && typeof data.ph.setpoint !== 'undefined' ? parseFloat(data.ph.setpoint) : chem.ph.setpoint; + let orpSetpoint = typeof data.orp !== 'undefined' && typeof data.orp.setpoint !== 'undefined' ? parseInt(data.orp.setpoint, 10) : chem.orp.setpoint; let calciumHardness = typeof data.calciumHardness !== 'undefined' ? parseInt(data.calciumHardness, 10) : chem.calciumHardness; let cyanuricAcid = typeof data.cyanuricAcid !== 'undefined' ? parseInt(data.cyanuricAcid, 10) : chem.cyanuricAcid; let alkalinity = typeof data.alkalinity !== 'undefined' ? parseInt(data.alkalinity, 10) : chem.alkalinity; diff --git a/controller/comms/Comms.ts b/controller/comms/Comms.ts index ecc444ad..76606aed 100755 --- a/controller/comms/Comms.ts +++ b/controller/comms/Comms.ts @@ -41,6 +41,7 @@ export class Connection { } public isRTS: boolean=true; public emitter: EventEmitter; + public get enabled(): boolean { return typeof this._cfg !== 'undefined' && this._cfg.enabled; } public async openAsync(): Promise { if (typeof (this.buffer) === 'undefined') { this.buffer = new SendRecieveBuffer(); @@ -149,87 +150,6 @@ export class Connection { }); } } - //public open(timeOut?: string) { - // if (conn._cfg.netConnect && !conn._cfg.mockPort) { - // if (typeof conn._port !== 'undefined' !&& conn._port.destroyed) conn._port.destroy(); - // let nc = conn._port = new net.Socket(); - // nc.connect(conn._cfg.netPort, conn._cfg.netHost, function () { - // if (timeOut === 'retry_timeout' || timeOut === 'timeout') - // logger.warn('Net connect (socat) trying to recover from lost connection.'); - // }); - // nc.on('data', function (data) { - // conn.isOpen = true; - // if (timeOut === 'retry_timeout' || timeOut === 'timeout') { - // logger.info(`Net connect (socat) connected to: ${conn._cfg.netHost}:${conn._cfg.netPort}`); - // timeOut = undefined; - // } - // if (data.length > 0 && !conn.isPaused) conn.emitter.emit('packetread', data); - // conn.resetConnTimer('timeout'); - // }); - // } - // else { - // var sp: SerialPort = null; - // if (conn._cfg.mockPort) { - // this.mockPort = true; - // SerialPort.Binding = MockBinding; - // let portPath = 'FAKE_PORT'; - // MockBinding.createPort(portPath, { echo: false, record: true }); - // sp = new SerialPort(portPath, { autoOpen: false }); - // } - // else { - // this.mockPort = false; - // sp = new SerialPort(conn._cfg.rs485Port, conn._cfg.portSettings); - // } - - // conn._port = sp; - // sp.open(function(err) { - // if (err) { - // conn.resetConnTimer(); - // conn.isOpen = false; - // logger.error(`Error opening port: ${err.message}. ${conn._cfg.inactivityRetry > 0 ? `Retry in ${conn._cfg.inactivityRetry} seconds` : `Never retrying; inactivityRetry set to ${conn._cfg.inactivityRetry}`}`); - // } - // else - // logger.info(`Serial port: ${ this.path } request to open succeeded without error`); - // }); - // sp.on('open', function() { - // if (timeOut === 'retry_timeout' || timeOut === 'timeout') - // logger.error('Serial port %s recovering from lost connection', conn._cfg.rs485Port); - // else - // logger.info(`Serial port: ${ this.path } opened`); - // conn.isOpen = true; - // }); - // // RKS: 06-16-20 -- Unsure why we are using a stream event here. The data - // // is being sent via the data event and I can find no reference to the readable event. - // sp.on('data', function (data) { - // if (!this.mockPort) { - // if (!conn.isPaused) conn.emitter.emit('packetread', data); - // } - // conn.resetConnTimer(); - // }); - // //sp.on('readable', function () { - // // if (!this.mockPort) { - // // // If we are paused just read the port and do nothing with it. - // // if (conn.isPaused) - // // sp.read(); - // // else - // // conn.emitter.emit('packetread', sp.read()); - // // conn.resetConnTimer(); - // // } - // //}); - - // } - // if (typeof (conn.buffer) === 'undefined') { - // conn.buffer = new SendRecieveBuffer(); - // conn.emitter.on('packetread', function(pkt) { conn.buffer.pushIn(pkt); }); - // conn.emitter.on('messagewrite', function(msg) { conn.buffer.pushOut(msg); }); - // } - // conn.resetConnTimer('retry_timeout'); - // conn._port.on('error', function(err) { - // logger.error(`Error opening port: ${err.message}. ${conn._cfg.inactivityRetry > 0 ? `Retry in ${conn._cfg.inactivityRetry} seconds` : `Never retrying; inactivityRetry set to ${conn._cfg.inactivityRetry}`}`); - // conn.resetConnTimer(); - // conn.isOpen = false; - // }); - //} public closeAsync() { try { if (conn.connTimer) clearTimeout(conn.connTimer); @@ -275,7 +195,7 @@ export class Connection { netPort: 9801, inactivityRetry: 10 }); - conn.openAsync(); + if (conn._cfg.enabled) conn.openAsync(); config.emitter.on('reloaded', () => { console.log('Config reloaded'); this.reloadConfig(config.getSection('controller.comms', { @@ -302,7 +222,7 @@ export class Connection { if (JSON.stringify(c) !== JSON.stringify(this._cfg)) { this.closeAsync(); this._cfg = c; - this.openAsync(); + if(this._cfg.enabled) this.openAsync(); } } public queueSendMessage(msg: Outbound) { conn.emitter.emit('messagewrite', msg); } diff --git a/controller/comms/messages/status/IntelliChemStateMessage.ts b/controller/comms/messages/status/IntelliChemStateMessage.ts index 8595274c..89f65876 100644 --- a/controller/comms/messages/status/IntelliChemStateMessage.ts +++ b/controller/comms/messages/status/IntelliChemStateMessage.ts @@ -80,34 +80,34 @@ export class IntelliChemStateMessage { // This is an action 18 that comes from IntelliChem. There is also a 147 that comes from an OCP but this is the raw data. //[165, 0, 16, 144, 18, 41][2,228,3,2,2,228,2,188,0,0,0,16,0,0,0,0,0,35,0,0,6,6,3,0,250,0,44,0,160,20,0,81,8,0,149,0,80,1,0,0,0] // Bytes - Descrption - // 0-1 : pH 2x256 + 228 / 100 = 7.4 - // 2-3 : ORP 3x256 + 2 = 770 - // 4-5 : pH Setpoint : 2x256 + 228 / 100 = 7.4 - // 6-7 : ORP Setpoint : 2x256 + 188 = 700 + // 0-1 : pH byte(0) x 256 + byte(1) / 100 + // 2-3 : ORP byte(2) x 256 + byte(3) + // 4-5 : pH Setpoint : byte(4) x 256 + byte(5) / 100 + // 6-7 : ORP Setpoint : byte(6) x 256 + byte(7) // 8 : Unknown = 0 // 9 : Unknown = 0 // 10 : Unknown = 0 - // 11-12 : pH Dose time + // 11-12 : pH Dose time seconds. The number of seconds since the dose started. byte(11) x 256 + byte(12) // 13 : Unknown - // 14-15 : ORP Dose time seconds. The number of seconds since the dose started. - // 16-17 : pH Dose volume (unknown units) = 35 - // 18-19 : ORP Dose volume (unknown units) = 0 - // 20 : pH tank level 1-7 = 6 - // 21 : ORP tank level 1-7 = 6 - // 22 : LSI = 3 & 0x80 === 0x80 ? 256 - 3 / -100 : 3/100 = .03 - // 23-24 : Calcium Hardness = 0x256+250 = 250 - // 25 : Unknown = 0 - // 26 : CYA = 44 - // 27-28 : Alkalinity = 0x256+160 - // 29 : Salt level = 20 + // 14-15 : ORP Dose time seconds. The number of seconds since the dose started. byte(14) x 256 + byte(15) + // 16-17 : pH Dose volume (unknown units) - These appear to be mL. + // 18-19 : ORP Dose volume (unknown units) - These appear to be mL + // 20 : pH tank level 1-7 + // 21 : ORP tank level 1-7 + // 22 : LSI. (byte(22) & 0x80) === 0x80 ? (256 - byte(22) / -100 : byte(22)/100 + // 23-24 : Calcium Hardness = byte(23) x 256 + byte(24) = 250 + // 25 : Unknown = 0 (probably reserved CYA byte so the controller is always dealing with integers) + // 26 : CYA Max value = 210. + // 27-28 : Alkalinity = byte(27) x 256 + byte(28) + // 29 : Salt level = byte(29) x 50 // 30 : Unknown - // 31 : Temperature = 81 - // 32 : Alarms = 8 = (no alarm) - // 33 : pH Lockout, Daily Limit Reached, Invalid Setup, Chlorinator Comm error - // 34 : Dosing Status = 149 = (pH Monitoring, ORP Mixing) - // 35 : Delays = 0 + // 31 : Temperature + // 32 : Alarms + // 33 : Warnings pH Lockout, Daily Limit Reached, Invalid Setup, Chlorinator Comm error + // 34 : Dosing Status (pH Monitoring, ORP Mixing) + // 35 : Delays // 36-37 : Firmware = 80,1 = 1.080 - // 38 : Water Chemistry Warning + // 38 : Water Chemistry Warning (Corrosion...) // 39 : Unknown // 40 : Unknown let address = msg.source; @@ -143,9 +143,9 @@ export class IntelliChemStateMessage { scontroller.ph.tank.level = Math.max(msg.extractPayloadByte(20) > 0 ? msg.extractPayloadByte(20) - 1 : msg.extractPayloadByte(20), 0); // values reported as 1-7; possibly 0 if no tank present // 21 : ORP tank level 1-7 = 6 scontroller.orp.tank.level = Math.max(msg.extractPayloadByte(21) > 0 ? msg.extractPayloadByte(21) - 1 : msg.extractPayloadByte(21), 0); // values reported as 1-7; possibly 0 if no tank present - // 22 : LSI = 3 & 0x80 === 0x80 ? 256 - 3 / -100 : 3/100 = .03 + // 22 : LSI = 3 & 0x80 === 0x80 ? (256 - 3) / -100 : 3/100 = .03 let lsi = msg.extractPayloadByte(22); - scontroller.saturationIndex = (lsi & 0x80) ? 256 - lsi / -100 : lsi / 100; + scontroller.saturationIndex = (lsi & 0x80) === 0x80 ? (256 - lsi) / -100 : lsi / 100; // 23-24 : Calcium Hardness = 0x256+250 = 250 controller.calciumHardness = (msg.extractPayloadByte(23) * 256) + msg.extractPayloadByte(24); // 26 : CYA = 44 diff --git a/defaultConfig.json b/defaultConfig.json index c94ca021..e3d7061c 100755 --- a/defaultConfig.json +++ b/defaultConfig.json @@ -1,6 +1,7 @@ { "controller": { "comms": { + "enabled": true, "rs485Port": "/dev/ttyUSB0", "mockPort": false, "netConnect": false,