Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions controller/Equipment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2292,6 +2292,7 @@ export class ChemController extends EqItem implements IChemController {
if (typeof this.data.borates === 'undefined') this.data.borates = 0;
if (typeof this.data.siCalcType === 'undefined') this.data.siCalcType = 0;
if (typeof this.data.intellichemStandalone === 'undefined') this.data.intellichemStandalone = false;
if (typeof this.data.singleMixPeriod === 'undefined') this.data.singleMixPeriod = false;
super.initData();
}
public dataName = 'chemControllerConfig';
Expand Down Expand Up @@ -2327,6 +2328,8 @@ export class ChemController extends EqItem implements IChemController {
public get lsiRange(): AlarmSetting { return new AlarmSetting(this.data, 'lsiRange', this); }
public get firmware(): string { return this.data.firmware; }
public set firmware(val: string) { this.setDataVal('firmware', val); }
public get singleMixPeriod(): boolean { return this.data.singleMixPeriod; }
public set singleMixPeriod(val: boolean) { this.setDataVal('singleMixPeriod', val); }
public getExtended() {
let chem = this.get(true);
chem.type = sys.board.valueMaps.chemControllerTypes.transform(this.type);
Expand Down Expand Up @@ -2364,6 +2367,7 @@ export class ChemDoser extends EqItem implements IChemical {
if (typeof this.mixingTime === 'undefined') this.data.mixingTime = 3600;
if (typeof this.data.setpoint === 'undefined') this.data.setpoint = 100;
if (typeof this.data.type === 'undefined') this.data.type = 0;
if (typeof this.data.singleMixPeriod === 'undefined') this.data.singleMixPeriod = false;
super.initData();
}
public get id(): number { return this.data.id; }
Expand Down Expand Up @@ -2402,6 +2406,8 @@ export class ChemDoser extends EqItem implements IChemical {
public get flowSensor(): ChemFlowSensor { return new ChemFlowSensor(this.data, 'flowSensor', this); }
public get flowOnlyMixing(): boolean { return utils.makeBool(this.data.flowOnlyMixing); }
public set flowOnlyMixing(val: boolean) { this.setDataVal('flowOnlyMixing', val); }
public get singleMixPeriod(): boolean { return this.data.singleMixPeriod; }
public set singleMixPeriod(val: boolean) { this.setDataVal('singleMixPeriod', val); }
public get pump(): ChemicalPump { return new ChemicalPump(this.data, 'pump', this); }
public get tank(): ChemicalTank { return new ChemicalTank(this.data, 'tank', this); }
public getExtended() {
Expand Down
1 change: 1 addition & 0 deletions controller/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,7 @@ export class PumpState extends EqState {
c.units = sys.board.valueMaps.pumpUnits.transformByName('gpm');
break;
case 'hwvs':
case 'hwsp':
case 'vssvrs':
case 'vs':
case 'regalmodbus':
Expand Down
3 changes: 2 additions & 1 deletion controller/boards/EasyTouchBoard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ export class EasyTouchBoard extends SystemBoard {
[257, { name: 'ss', desc: 'Single Speed', maxCircuits: 0, hasAddress: false, hasBody: true, equipmentMaster: 1, maxRelays: 1, relays: [{ id: 1, name: 'Pump On/Off' }] }],
[256, { name: 'sf', desc: 'SuperFlo VS', hasAddress: false, maxCircuits: 8, maxRelays: 4, equipmentMaster: 1, maxSpeeds: 4, relays: [{ id: 1, name: 'Program #1' }, { id: 2, name: 'Program #2' }, { id: 3, name: 'Program #3' }, { id: 4, name: 'Program #4' }] }],
[258, { name: 'hwrly', desc: 'Hayward Relay VS', hasAddress: false, maxCircuits: 8, maxRelays: 4, equipmentMaster: 1, maxSpeeds: 8, relays: [{ id: 1, name: 'Step #1' }, { id: 2, name: 'Step #2' }, { id: 3, name: 'Step #3' }, { id: 4, name: 'Pump On' }] }],
[259, { name: 'hwvs', desc: 'Hayward Eco/TriStar VS', minSpeed: 450, maxSpeed: 3450, maxCircuits: 8, hasAddress: true, equipmentMaster: 1 }]
[259, { name: 'hwvs', desc: 'Hayward Eco/TriStar VS', minSpeed: 450, maxSpeed: 3450, maxCircuits: 8, hasAddress: true, equipmentMaster: 1 }],
[260, { name: 'hwsp', desc: 'Hayward Super Pump VS 700', minSpeed: 450, maxSpeed: 3450, maxCircuits: 8, hasAddress: true, equipmentMaster: 1 }]
]);
this.valueMaps.heaterTypes = new byteValueMap([
[0, { name: 'none', desc: 'No Heater', hasAddress: false }],
Expand Down
3 changes: 2 additions & 1 deletion controller/boards/IntelliCenterBoard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ export class IntelliCenterBoard extends SystemBoard {
[5, { name: 'vf', desc: 'Intelliflo VF', maxPrimingTime: 6, minFlow: 15, maxFlow: 130, maxCircuits: 8, hasAddress: true }],
[100, { name: 'sf', desc: 'SuperFlo VS', hasAddress: false, maxCircuits: 8, maxRelays: 4, equipmentMaster: 1, maxSpeeds: 4, relays: [{ id: 1, name: 'Program #1' }, { id: 2, name: 'Program #2' }, { id: 3, name: 'Program #3' }, { id: 4, name: 'Program #4' }] }],
[101, { name: 'hwrly', desc: 'Hayward Relay VS', hasAddress: false, maxCircuits: 8, maxRelays: 4, equipmentMaster: 1, maxSpeeds: 8, relays: [{ id: 1, name: 'Step #1' }, { id: 2, name: 'Step #2' }, { id: 3, name: 'Step #3' }, { id: 4, name: 'Pump On' }] }],
[102, { name: 'hwvs', desc: 'Hayward Eco/TriStar VS', minSpeed: 450, maxSpeed: 3450, maxCircuits: 8, hasAddress: true, equipmentMaster: 1 }]
[102, { name: 'hwvs', desc: 'Hayward Eco/TriStar VS', minSpeed: 450, maxSpeed: 3450, maxCircuits: 8, hasAddress: true, equipmentMaster: 1 }],
[103, { name: 'hwsp', desc: 'Hayward Super Pump VS 700', minSpeed: 450, maxSpeed: 3450, maxCircuits: 8, hasAddress: true, equipmentMaster: 1 }]
]);
// RSG - same as systemBoard definition; can delete.
this.valueMaps.heatModes = new byteValueMap([
Expand Down
1 change: 1 addition & 0 deletions controller/boards/NixieBoard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export class NixieBoard extends SystemBoard {
[5, { name: 'vf', desc: 'Intelliflo VF', minFlow: 15, maxFlow: 130, maxCircuits: 8, hasAddress: true, addresses: addrsPentairPump }],
[6, { name: 'hwvs', desc: 'Hayward Eco/TriStar VS', minSpeed: 450, maxSpeed: 3450, maxCircuits: 8, hasAddress: true, addresses: addrsPentairPump }],
[7, { name: 'hwrly', desc: 'Hayward Relay VS', hasAddress: false, maxCircuits: 8, maxRelays: 4, maxSpeeds: 8, relays: [{ id: 1, name: 'Step #1' }, { id: 2, name: 'Step #2'}, { id: 3, name: 'Step #3' }, { id: 4, name: 'Pump On' }], addresses: [] }],
[8, { name: 'hwsp', desc: 'Hayward Super Pump VS 700', minSpeed: 450, maxSpeed: 3450, maxCircuits: 8, hasAddress: true, addresses: addrsPentairPump }],
[100, { name: 'sf', desc: 'SuperFlo VS', hasAddress: false, maxCircuits: 8, maxRelays: 4, equipmentMaster: 1, maxSpeeds: 4, relays: [{ id: 1, name: 'Program #1' }, { id: 2, name: 'Program #2' }, { id: 3, name: 'Program #3' }, { id: 4, name: 'Program #4' }], addresses: [] }],
[200, { name: 'regalmodbus', desc: 'Regal Modbus', minSpeed: 450, maxSpeed: 3450, maxCircuits: 8, hasAddress: true, addresses: addrsRegalModbusPump}],
[201, { name: 'neptunemodbus', desc: 'Neptune Modbus', minSpeed: 450, maxSpeed: 3450, maxCircuits: 8, hasAddress: true, addresses: addrsNeptuneModbusPump }],
Expand Down
3 changes: 3 additions & 0 deletions controller/boards/SystemBoard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ import { setTimeout as setTimeoutSync } from 'timers';


export class byteValueMap extends Map<number, any> {
constructor(entries?: [number, any][]) {
super(entries);
}
public transform(byte: number, ext?: number) { return extend(true, { val: byte || 0 }, this.get(byte) || this.get(0)); }
public toArray(): any[] {
let arrKeys = Array.from(this.keys());
Expand Down
17 changes: 16 additions & 1 deletion controller/comms/messages/Messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@ export class Message {
}
}
export class Inbound extends Message {
private static readonly MAX_REWINDS_PER_MESSAGE = 250;
private static readonly REWIND_LOG_EVERY = 25;
private static readonly REWIND_LOG_PREVIEW_BYTES = 32;
// /usr/bin/socat TCP-LISTEN:9801,fork,reuseaddr FILE:/dev/ttyUSB0,b9600,raw
// /usr/bin/socat TCP-LISTEN:9801,fork,reuseaddr FILE:/dev/ttyUSB0,b9600,cs8,cstopb=1,parenb=0,raw
// /usr/bin / socat TCP - LISTEN: 9801,fork,reuseaddr FILE:/dev/ttyUSB0, b9600, cs8, cstopb = 1, parenb = 0, raw
Expand All @@ -358,6 +361,12 @@ export class Inbound extends Message {
public isProcessed: boolean = false;
public collisions: number = 0;
public rewinds: number = 0;
private logRewindCollision(buff: number[], ndx: number, inLen: number) {
if (this.collisions === 1 || this.collisions % Inbound.REWIND_LOG_EVERY === 0) {
const preview = buff.slice(0, Inbound.REWIND_LOG_PREVIEW_BYTES);
logger.warn(`rewinding message collision count=${this.collisions} rewinds=${this.rewinds} ndx=${ndx} inLen=${inLen} buffLen=${buff.length} preview=${JSON.stringify(preview)}${buff.length > preview.length ? '...truncated' : ''}`);
}
}
// Private methods
private isValidChecksum(): boolean {
switch (this.protocol) {
Expand Down Expand Up @@ -543,7 +552,13 @@ export class Inbound extends Message {

this.collisions++;
this.rewinds++;
logger.info(`rewinding message collision ${this.collisions} ${ndx} ${bytes.length} ${JSON.stringify(buff)}`);
if (this.rewinds > Inbound.MAX_REWINDS_PER_MESSAGE) {
logger.warn(`rewind limit exceeded for inbound message: rewinds=${this.rewinds} collisions=${this.collisions} inLen=${bytes.length}. Dropping current packet to protect heap.`);
this._complete = true;
this.isValid = false;
return bytes.length;
}
this.logRewindCollision(buff, ndx, bytes.length);
this.readPacket(buff);
return ndx;
//return this.padding.length + this.preamble.length;
Expand Down
11 changes: 11 additions & 0 deletions controller/nixie/chemistry/ChemController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@ export class NixieChemController extends NixieChemControllerBase {
if (typeof data.lsiRange.low === 'number') chem.lsiRange.low = data.lsiRange.low;
if (typeof data.lsiRange.high === 'number') chem.lsiRange.high = data.lsiRange.high;
}
if (typeof data.singleMixPeriod !== 'undefined') chem.singleMixPeriod = utils.makeBool(data.singleMixPeriod);
if (typeof data.siCalcType !== 'undefined') schem.siCalcType = chem.siCalcType = data.siCalcType;
await this.flowSensor.setSensorAsync(data.flowSensor);
// Alright we are down to the equipment items all validation should have been completed by now.
Expand Down Expand Up @@ -1794,6 +1795,11 @@ export class NixieChemicalPh extends NixieChemical {
else if (sph.dailyLimitReached) {
await this.cancelDosing(sph, 'daily limit');
}
else if (this.chemController.chem.singleMixPeriod && sph.chemController.orp.dosingStatus === 1) {
// Don't dose pH if ORP is mixing - enforce single mixing period (only when enabled)
await this.cancelDosing(sph, 'orp mixing');
return;
}
else if (status === 'monitoring' || status === 'dosing') {
// Figure out what mode we are in and what mode we should be in.
//sph.level = 7.61;
Expand Down Expand Up @@ -2288,6 +2294,11 @@ export class NixieChemicalORP extends NixieChemical {
await this.cancelDosing(sorp, 'ph pump dosing + dose priority');
return;
}
else if (chem.singleMixPeriod && sorp.chemController.ph.dosingStatus === 1) {
// Don't dose ORP if pH is mixing - enforce single mixing period (only when enabled)
await this.cancelDosing(sorp, 'ph mixing');
return;
}
else if (status === 'monitoring' || status === 'dosing') {
// let _doseCalculatedSec = 0;
if (!sorp.lockout) {
Expand Down
17 changes: 17 additions & 0 deletions controller/nixie/chemistry/ChemDoser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ export class NixieChemDoser extends NixieChemDoserBase implements INixieChemical
(typeof data.mixingTimeSeconds !== 'undefined' ? parseInt(data.mixingTimeSeconds, 10) : 0);
}
chem.mixingTime = typeof data.mixingTime !== 'undefined' ? parseInt(data.mixingTime, 10) : chem.mixingTime;
if (typeof data.singleMixPeriod !== 'undefined') chem.singleMixPeriod = utils.makeBool(data.singleMixPeriod);
await this.flowSensor.setSensorAsync(data.flowSensor);
await this.tank.setTankAsync(schem.tank, data.tank);
await this.pump.setPumpAsync(schem.pump, data.pump);
Expand Down Expand Up @@ -586,6 +587,22 @@ export class NixieChemDoser extends NixieChemDoserBase implements INixieChemical
await this.cancelDosing(sd, 'daily limit');
}
else if (status === 'monitoring' || status === 'dosing') {
// Check if any other chem doser is currently mixing - only if singleMixPeriod is enabled
if (this.chem.singleMixPeriod) {
let otherDoserMixing = false;
for (let i = 0; i < state.chemDosers.length; i++) {
let otherDoser = state.chemDosers.getItemByIndex(i);
if (otherDoser.id !== sd.id && otherDoser.dosingStatus === 1) { // 1 is mixing
logger.info(`Cannot dose ${sd.chemType} - ${otherDoser.chemType} doser is currently mixing`);
otherDoserMixing = true;
break;
}
}
if (otherDoserMixing) {
await this.cancelDosing(sd, 'another doser mixing');
return;
}
}
// Figure out what mode we are in and what mode we should be in.
//sph.level = 7.61;
// Check the setpoint and the current level to see if we need to dose.
Expand Down
Loading