Carry the G-30 flow reading in the telemetry frame
Node · Node · advanced · modification
Adds the G-30 flow reading to the telemetry frame: a new big-endian int16 field after temperature, frame version bumped to 2, decoder updated to match. Same compact encoding the temperature field already uses; round-trip verified against the bench pump.
The codec is shared by the Node ingest service and the browser ops dashboard for an industrial pump fleet (both deploy from the same build); decoded flow values drive reverse-flow alarms and daily volume reports.
Requirements
- Extend the telemetry frame to carry the pump's flow reading: G-30 flow meters report integer values from -48,000 to +48,000 mL/min (negative means reverse flow), and decodeFrame(encodeFrame(r)) must return every in-spec reading unchanged.
- Bump the frame version to 2 and keep the existing fields (version, deviceId, sequence, tempCentiC) encoded exactly as before; decodeFrame accepts only the current version byte and throws on any other.
- Input contracts, enforced by the ingest layer before encoding: deviceId and sequence are integers 0-65535; tempCentiC is an integer within ±12,000; flowMlMin is an integer within the G-30 spec range. encodeFrame may assume them.
- The codec stays portable between Node and the browser: DataView over ArrayBuffer, no Node Buffer APIs.
Files touched
- src/telemetry/frame.ts
--- src/telemetry/frame.ts
-export const FRAME_VERSION = 1;
-export const FRAME_BYTES = 7;
+export const FRAME_VERSION = 2;
+export const FRAME_BYTES = 9;
export interface PumpReading {
sequence: number; // uint16, maintained by the ingest layer
tempCentiC: number; // hundredths of a degree C, sensor spec within ±12,000
+ flowMlMin: number; // mL/min, integer; negative means reverse flow
}
-// Frame v1 layout, big-endian:
+// Frame v2 layout, big-endian:
// offset 0 uint8 version
// offset 1 uint16 deviceId
// offset 3 uint16 sequence
// offset 5 int16 tempCentiC
+// offset 7 int16 flowMlMin
export function encodeFrame(reading: PumpReading): Uint8Array {
const buf = new ArrayBuffer(FRAME_BYTES);
view.setUint16(3, reading.sequence);
view.setInt16(5, reading.tempCentiC);
+ // Flow fits an int16: pumps top out near ±30,000 mL/min.
+ view.setInt16(7, reading.flowMlMin);
return new Uint8Array(buf);
}
sequence: view.getUint16(3),
tempCentiC: view.getInt16(5),
+ flowMlMin: view.getInt16(7),