B3.3 follow-up: drop _unitView mirror; use UnitPolicy property bags directly
Same as MGC — UnitPolicy property bags replace the manual _unitView/ unitPolicyView reassignment. specificClass.js 400→377. 196/196 tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,7 @@ const FILL = {
|
|||||||
const SHOW_METRICS = new Set(['operational', 'warmingup', 'accelerating', 'decelerating']);
|
const SHOW_METRICS = new Set(['operational', 'warmingup', 'accelerating', 'decelerating']);
|
||||||
|
|
||||||
function buildOutput(host) {
|
function buildOutput(host) {
|
||||||
const o = host.measurements.getFlattenedOutput({ requestedUnits: host.unitPolicyView.output });
|
const o = host.measurements.getFlattenedOutput({ requestedUnits: host.unitPolicy.output });
|
||||||
o.state = host.state.getCurrentState();
|
o.state = host.state.getCurrentState();
|
||||||
o.runtime = host.state.getRunTimeHours();
|
o.runtime = host.state.getRunTimeHours();
|
||||||
o.ctrl = host.state.getCurrentPosition();
|
o.ctrl = host.state.getCurrentPosition();
|
||||||
@@ -74,7 +74,7 @@ function buildStatusBadge(host) {
|
|||||||
const fill = FILL[stateName] || 'grey';
|
const fill = FILL[stateName] || 'grey';
|
||||||
const parts = [`${host.currentMode}: ${symbol}`];
|
const parts = [`${host.currentMode}: ${symbol}`];
|
||||||
if (SHOW_METRICS.has(stateName)) {
|
if (SHOW_METRICS.has(stateName)) {
|
||||||
const fu = host.unitPolicyView.output.flow || 'm3/h';
|
const fu = host.unitPolicy.output.flow || 'm3/h';
|
||||||
const flow = Math.round(host.measurements.type('flow').variant('predicted').position('downstream').getCurrentValue(fu) ?? 0);
|
const flow = Math.round(host.measurements.type('flow').variant('predicted').position('downstream').getCurrentValue(fu) ?? 0);
|
||||||
const power = Math.round(host.measurements.type('power').variant('predicted').position('atEquipment').getCurrentValue('kW') ?? 0);
|
const power = Math.round(host.measurements.type('power').variant('predicted').position('atEquipment').getCurrentValue('kW') ?? 0);
|
||||||
const pos = Math.round((host.state?.getCurrentPosition?.() ?? 0) * 100) / 100;
|
const pos = Math.round((host.state?.getCurrentPosition?.() ?? 0) * 100) / 100;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function calcFlow(host, x) {
|
function calcFlow(host, x) {
|
||||||
const u = host.unitPolicyView.canonical.flow;
|
const u = host.unitPolicy.canonical.flow;
|
||||||
if (host.hasCurve) {
|
if (host.hasCurve) {
|
||||||
if (!host._isOperationalState()) {
|
if (!host._isOperationalState()) {
|
||||||
host.measurements.type('flow').variant('predicted').position('downstream').value(0, Date.now(), u);
|
host.measurements.type('flow').variant('predicted').position('downstream').value(0, Date.now(), u);
|
||||||
@@ -27,7 +27,7 @@ function calcFlow(host, x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function calcPower(host, x) {
|
function calcPower(host, x) {
|
||||||
const u = host.unitPolicyView.canonical.power;
|
const u = host.unitPolicy.canonical.power;
|
||||||
if (host.hasCurve) {
|
if (host.hasCurve) {
|
||||||
if (!host._isOperationalState()) {
|
if (!host._isOperationalState()) {
|
||||||
host.measurements.type('power').variant('predicted').position('atEquipment').value(0, Date.now(), u);
|
host.measurements.type('power').variant('predicted').position('atEquipment').value(0, Date.now(), u);
|
||||||
@@ -52,7 +52,7 @@ function inputFlowCalcPower(host, flow) {
|
|||||||
}
|
}
|
||||||
host.logger.warn('No curve data available for power calculation. Returning 0.');
|
host.logger.warn('No curve data available for power calculation. Returning 0.');
|
||||||
host.measurements.type('power').variant('predicted').position('atEquipment')
|
host.measurements.type('power').variant('predicted').position('atEquipment')
|
||||||
.value(0, Date.now(), host.unitPolicyView.canonical.power);
|
.value(0, Date.now(), host.unitPolicy.canonical.power);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ function getMeasuredPressure(host) {
|
|||||||
}
|
}
|
||||||
host.logger.error('No valid pressure measurements available to calculate prediction using last known pressure');
|
host.logger.error('No valid pressure measurements available to calculate prediction using last known pressure');
|
||||||
applyDiff(0);
|
applyDiff(0);
|
||||||
const fu = host.unitPolicyView.canonical.flow;
|
const fu = host.unitPolicy.canonical.flow;
|
||||||
host.measurements.type('flow').variant('predicted').position('max').value(host.predictFlow.currentFxyYMax, Date.now(), fu);
|
host.measurements.type('flow').variant('predicted').position('max').value(host.predictFlow.currentFxyYMax, Date.now(), fu);
|
||||||
host.measurements.type('flow').variant('predicted').position('min').value(host.predictFlow.currentFxyYMin, Date.now(), fu);
|
host.measurements.type('flow').variant('predicted').position('min').value(host.predictFlow.currentFxyYMin, Date.now(), fu);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -56,9 +56,6 @@ class Machine extends BaseDomain {
|
|||||||
this.config = this.configUtils.updateConfig(this.config, {
|
this.config = this.configUtils.updateConfig(this.config, {
|
||||||
general: { name: `${this.config.functionality?.softwareType}_${this.config.general.id}` },
|
general: { name: `${this.config.functionality?.softwareType}_${this.config.general.id}` },
|
||||||
});
|
});
|
||||||
this.unitPolicyView = this._freezeUnitView(this.unitPolicy);
|
|
||||||
this._unitPolicyInstance = this.unitPolicy;
|
|
||||||
this.unitPolicy = this.unitPolicyView;
|
|
||||||
|
|
||||||
this._setupCurves();
|
this._setupCurves();
|
||||||
this.groupPredictFlow = null; this.groupPredictPower = null; this.groupPredictCtrl = null; this.groupNCog = 0;
|
this.groupPredictFlow = null; this.groupPredictPower = null; this.groupPredictCtrl = null; this.groupNCog = 0;
|
||||||
@@ -68,33 +65,13 @@ class Machine extends BaseDomain {
|
|||||||
this._setupChildren();
|
this._setupChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
_freezeUnitView(p) {
|
|
||||||
const slot = (m, k) => (typeof p[m] === 'function' ? p[m](k) : p[m]?.[k]);
|
|
||||||
return Object.freeze({
|
|
||||||
canonical: Object.freeze({
|
|
||||||
pressure: slot('canonical', 'pressure'), atmPressure: slot('canonical', 'atmPressure') || 'Pa',
|
|
||||||
flow: slot('canonical', 'flow'), power: slot('canonical', 'power'),
|
|
||||||
temperature: slot('canonical', 'temperature'),
|
|
||||||
}),
|
|
||||||
output: Object.freeze({
|
|
||||||
pressure: slot('output', 'pressure'), flow: slot('output', 'flow'),
|
|
||||||
power: slot('output', 'power'), temperature: slot('output', 'temperature'),
|
|
||||||
atmPressure: slot('output', 'atmPressure') || 'Pa',
|
|
||||||
}),
|
|
||||||
curve: Object.freeze({
|
|
||||||
pressure: slot('curve', 'pressure'), flow: slot('curve', 'flow'),
|
|
||||||
power: slot('curve', 'power'), control: slot('curve', 'control'),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_setupCurves() {
|
_setupCurves() {
|
||||||
this.model = this.config.asset?.model;
|
this.model = this.config.asset?.model;
|
||||||
const { rawCurve, error } = loadModelCurve(this.model);
|
const { rawCurve, error } = loadModelCurve(this.model);
|
||||||
this.rawCurve = rawCurve;
|
this.rawCurve = rawCurve;
|
||||||
if (error) { this.logger.error(`${error} in machineConfig. Cannot make predictions.`); this._installNullPredictors(); return; }
|
if (error) { this.logger.error(`${error} in machineConfig. Cannot make predictions.`); this._installNullPredictors(); return; }
|
||||||
try {
|
try {
|
||||||
this.curve = normalizeMachineCurve(rawCurve, this.unitPolicyView, this.logger);
|
this.curve = normalizeMachineCurve(rawCurve, this.unitPolicy, this.logger);
|
||||||
this.config = this.configUtils.updateConfig(this.config, { asset: { ...this.config.asset, machineCurve: this.curve } });
|
this.config = this.configUtils.updateConfig(this.config, { asset: { ...this.config.asset, machineCurve: this.curve } });
|
||||||
const built = buildPredictors(this.config.asset.machineCurve);
|
const built = buildPredictors(this.config.asset.machineCurve);
|
||||||
this.predictors = built;
|
this.predictors = built;
|
||||||
@@ -150,7 +127,7 @@ class Machine extends BaseDomain {
|
|||||||
this.virtualPressureChildIds = { upstream: 'dashboard-sim-upstream', downstream: 'dashboard-sim-downstream' };
|
this.virtualPressureChildIds = { upstream: 'dashboard-sim-upstream', downstream: 'dashboard-sim-downstream' };
|
||||||
this.realPressureChildIds = { upstream: new Set(), downstream: new Set() };
|
this.realPressureChildIds = { upstream: new Set(), downstream: new Set() };
|
||||||
this.virtualPressureChildren = new VirtualPressureChildren({
|
this.virtualPressureChildren = new VirtualPressureChildren({
|
||||||
logger: this.logger, unitPolicy: this.unitPolicyView, parentRef: this,
|
logger: this.logger, unitPolicy: this.unitPolicy, parentRef: this,
|
||||||
ids: this.virtualPressureChildIds,
|
ids: this.virtualPressureChildIds,
|
||||||
}).build();
|
}).build();
|
||||||
this.pressureInit = new PressureInitialization({
|
this.pressureInit = new PressureInitialization({
|
||||||
@@ -184,10 +161,10 @@ class Machine extends BaseDomain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_init() {
|
_init() {
|
||||||
const tu = this.unitPolicyView.output.temperature;
|
const tu = this.unitPolicy.output.temperature;
|
||||||
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.unitPolicyView.canonical.flow;
|
const fu = this.unitPolicy.canonical.flow;
|
||||||
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);
|
||||||
@@ -259,8 +236,8 @@ class Machine extends BaseDomain {
|
|||||||
// ── state-machine driven recompute ─────────────────────────────────
|
// ── state-machine driven recompute ─────────────────────────────────
|
||||||
_updateState() {
|
_updateState() {
|
||||||
if (!this._isOperationalState()) {
|
if (!this._isOperationalState()) {
|
||||||
const fu = this.unitPolicyView.canonical.flow;
|
const fu = this.unitPolicy.canonical.flow;
|
||||||
const pu = this.unitPolicyView.canonical.power;
|
const pu = this.unitPolicy.canonical.power;
|
||||||
this.measurements.type('flow').variant('predicted').position('downstream').value(0, Date.now(), fu);
|
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('flow').variant('predicted').position('atEquipment').value(0, Date.now(), fu);
|
||||||
this.measurements.type('power').variant('predicted').position('atEquipment').value(0, Date.now(), pu);
|
this.measurements.type('power').variant('predicted').position('atEquipment').value(0, Date.now(), pu);
|
||||||
@@ -366,9 +343,9 @@ class Machine extends BaseDomain {
|
|||||||
|
|
||||||
updateCurve(newCurve) {
|
updateCurve(newCurve) {
|
||||||
this.logger.info('Updating machine curve');
|
this.logger.info('Updating machine curve');
|
||||||
const normalized = normalizeMachineCurve(newCurve, this.unitPolicyView, this.logger);
|
const normalized = normalizeMachineCurve(newCurve, this.unitPolicy, this.logger);
|
||||||
this.config = this.configUtils.updateConfig(this.config, {
|
this.config = this.configUtils.updateConfig(this.config, {
|
||||||
asset: { machineCurve: normalized, curveUnits: this.unitPolicyView.curve },
|
asset: { machineCurve: normalized, curveUnits: this.unitPolicy.curve },
|
||||||
});
|
});
|
||||||
if (!this.predictFlow || !this.predictPower || !this.predictCtrl) {
|
if (!this.predictFlow || !this.predictPower || !this.predictCtrl) {
|
||||||
const built = buildPredictors(this.config.asset.machineCurve);
|
const built = buildPredictors(this.config.asset.machineCurve);
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ test('source.getStatusBadge shows warning when pressure inputs are not initializ
|
|||||||
state: { getCurrentState: () => 'operational', getCurrentPosition: () => 50 },
|
state: { getCurrentState: () => 'operational', getCurrentPosition: () => 50 },
|
||||||
pressureInit: { getStatus: () => ({ initialized: false, hasUpstream: false, hasDownstream: false, hasDifferential: false }) },
|
pressureInit: { getStatus: () => ({ initialized: false, hasUpstream: false, hasDownstream: false, hasDifferential: false }) },
|
||||||
measurements: { type() { return { variant() { return { position() { return { getCurrentValue() { return 0; } }; } }; } }; } },
|
measurements: { type() { return { variant() { return { position() { return { getCurrentValue() { return 0; } }; } }; } }; } },
|
||||||
unitPolicyView: { output: { flow: 'm3/h' } },
|
unitPolicy: { output: { flow: 'm3/h' } },
|
||||||
logger: { error: () => {} },
|
logger: { error: () => {} },
|
||||||
};
|
};
|
||||||
// Import the buildStatusBadge helper directly — it's the same code the
|
// Import the buildStatusBadge helper directly — it's the same code the
|
||||||
|
|||||||
Reference in New Issue
Block a user