Compare commits
2 Commits
455f15dc55
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
889221fffd | ||
|
|
a8d9895cbf |
@@ -11,6 +11,10 @@ class nodeClass extends BaseNodeAdapter {
|
|||||||
static commands = commands;
|
static commands = commands;
|
||||||
static tickInterval = null;
|
static tickInterval = null;
|
||||||
static statusInterval = 1000;
|
static statusInterval = 1000;
|
||||||
|
// Realized control position holds constant in steady state, so delta
|
||||||
|
// compression would emit it ~once and the Grafana "% Control" line goes
|
||||||
|
// invisible. Force it every tick so the pump's movement always traces.
|
||||||
|
static alwaysEmitFields = ['ctrl'];
|
||||||
|
|
||||||
buildDomainConfig(uiConfig) {
|
buildDomainConfig(uiConfig) {
|
||||||
_rejectLegacyAssetFields(uiConfig);
|
_rejectLegacyAssetFields(uiConfig);
|
||||||
|
|||||||
@@ -229,10 +229,18 @@ class Machine extends BaseDomain {
|
|||||||
this.measurements.type('temperature').variant('measured').position('atEquipment').value(15, Date.now(), tu);
|
this.measurements.type('temperature').variant('measured').position('atEquipment').value(15, Date.now(), tu);
|
||||||
this.measurements.type('atmPressure').variant('measured').position('atEquipment').value(101325, Date.now(), 'Pa');
|
this.measurements.type('atmPressure').variant('measured').position('atEquipment').value(101325, Date.now(), 'Pa');
|
||||||
const fu = this.unitPolicy.canonical.flow;
|
const fu = this.unitPolicy.canonical.flow;
|
||||||
|
const pu = this.unitPolicy.canonical.power;
|
||||||
const fmin = this.predictFlow ? this.predictFlow.currentFxyYMin : 0;
|
const fmin = this.predictFlow ? this.predictFlow.currentFxyYMin : 0;
|
||||||
const fmax = this.predictFlow ? this.predictFlow.currentFxyYMax : 0;
|
const fmax = this.predictFlow ? this.predictFlow.currentFxyYMax : 0;
|
||||||
this.measurements.type('flow').variant('predicted').position('max').value(fmax, Date.now(), fu);
|
this.measurements.type('flow').variant('predicted').position('max').value(fmax, Date.now(), fu);
|
||||||
this.measurements.type('flow').variant('predicted').position('min').value(fmin, Date.now(), fu);
|
this.measurements.type('flow').variant('predicted').position('min').value(fmin, Date.now(), fu);
|
||||||
|
// Seed the operating-point series at boot so telemetry always carries them
|
||||||
|
// (0 while idle, real values once calcFlow/calcPower run when operational).
|
||||||
|
// Without this an idle-from-boot machine never emits these keys — the
|
||||||
|
// dashboard can't even show the off/0 state. Mirrors max/min above.
|
||||||
|
this.measurements.type('flow').variant('predicted').position('downstream').value(0, Date.now(), fu);
|
||||||
|
this.measurements.type('flow').variant('predicted').position('atEquipment').value(0, Date.now(), fu);
|
||||||
|
this.measurements.type('power').variant('predicted').position('atEquipment').value(0, Date.now(), pu);
|
||||||
}
|
}
|
||||||
|
|
||||||
_callMeasurementHandler(measurementType, value, position, context = {}) {
|
_callMeasurementHandler(measurementType, value, position, context = {}) {
|
||||||
|
|||||||
@@ -36,6 +36,31 @@ test('getOutput contains all required fields in idle state', () => {
|
|||||||
assert.ok('pressureDriftFlags' in output);
|
assert.ok('pressureDriftFlags' in output);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('getOutput seeds operating-point flow/power telemetry at boot (idle = 0, not absent)', () => {
|
||||||
|
// Regression: an idle-from-boot machine must still emit the operating-point
|
||||||
|
// series so dashboards can show the off/0 state. These keys are otherwise
|
||||||
|
// only written once the pump runs (calcFlow/calcPower) or on a state
|
||||||
|
// transition, leaving them absent in telemetry for a pump that never starts.
|
||||||
|
const machine = new Machine(makeMachineConfig(), makeStateConfig());
|
||||||
|
const output = machine.getOutput();
|
||||||
|
|
||||||
|
const hasPrefix = (p) => Object.keys(output).some((k) => k.startsWith(p));
|
||||||
|
const valueFor = (p) => output[Object.keys(output).find((k) => k.startsWith(p))];
|
||||||
|
|
||||||
|
for (const prefix of [
|
||||||
|
'flow.predicted.downstream',
|
||||||
|
'flow.predicted.atequipment',
|
||||||
|
'power.predicted.atequipment',
|
||||||
|
]) {
|
||||||
|
assert.ok(hasPrefix(prefix), `${prefix}.* must be present at boot (idle)`);
|
||||||
|
assert.equal(valueFor(prefix), 0, `${prefix}.* should be 0 while idle`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The envelope keys remain present too.
|
||||||
|
assert.ok(hasPrefix('flow.predicted.max'));
|
||||||
|
assert.ok(hasPrefix('flow.predicted.min'));
|
||||||
|
});
|
||||||
|
|
||||||
test('getOutput flow drift fields appear after sufficient measured flow samples', async () => {
|
test('getOutput flow drift fields appear after sufficient measured flow samples', async () => {
|
||||||
const machine = new Machine(makeMachineConfig(), makeStateConfig());
|
const machine = new Machine(makeMachineConfig(), makeStateConfig());
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user