/* nodejs-poolController. An application to control pool equipment. Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022. Russell Goldin, tagyoureit. russ.goldin@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ import { Inbound, Outbound } from '../../comms/messages/Messages'; import { VirtualPump } from './VirtualPump'; /** * IntelliFlo VS (variable speed) simulator. * * Action 1 payload shape (from OCP or Nixie): * [2, 196, rpmHi, rpmLo] * * A real pump acks with the full 4-byte payload echo. The existing * PumpStateMessage.processDirectPumpMessages() decodes it as: * if (payload[2] & 0x20) === 0 then RPM else GPM * setAmount = payload[2]*256 + payload[3] */ export class VirtualPumpVS extends VirtualPump { public static readonly MAX_RPM = 3450; public static readonly NOMINAL_WATTS = 2000; protected supportedActions = new Set([1, 4, 6, 7]); public get type(): string { return 'vs'; } protected processSpeedCommand(msg: Inbound, response: Outbound): boolean { if (msg.action !== 1) return false; if (msg.payload.length < 4) return false; const b0 = msg.extractPayloadByte(0); const b1 = msg.extractPayloadByte(1); const rpmHi = msg.extractPayloadByte(2); const rpmLo = msg.extractPayloadByte(3); this._targetRpm = rpmHi * 256 + rpmLo; response.appendPayloadByte(b0); response.appendPayloadByte(b1); response.appendPayloadByte(rpmHi); response.appendPayloadByte(rpmLo); return true; } /** * Cheap watts curve: power scales with the cube of the speed ratio. * At MAX_RPM this returns NOMINAL_WATTS. Not physically accurate for * any specific pump model — just a plausible, deterministic signature * that isn't obviously zero. */ protected computeWatts(): number { if (this._targetRpm <= 0) return 0; const ratio = this._targetRpm / VirtualPumpVS.MAX_RPM; return ratio * ratio * ratio * VirtualPumpVS.NOMINAL_WATTS; } }