Compare commits

..

1 Commits

Author SHA1 Message Date
znetsixe
0a3a0be15b feat(commands): adopt unified command envelope — msg.origin + unit shorthand
- Provenance resolved via msg.origin (registry-stamped, default parent) with a
  legacy fallback to payload.source; feeds handleInput's mode/source gating.
- set.flow-setpoint: units:{measure,default} -> unit:'m3/h' shorthand.

181/181 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 18:41:14 +02:00
2 changed files with 16 additions and 6 deletions

View File

@@ -16,6 +16,16 @@ function _logger(source, ctx) {
return ctx?.logger || source?.logger || null; return ctx?.logger || source?.logger || null;
} }
// Resolve the command origin (control authority: parent | GUI | fysical).
// The shared commandRegistry stamps msg.origin (default 'parent'); legacy flows
// carried the origin as payload.source. Prefer the legacy field when present so
// existing flows keep working, otherwise use the registry-stamped msg.origin.
function _origin(msg) {
const p = msg && msg.payload;
if (p && typeof p === 'object' && typeof p.source === 'string' && p.source) return p.source;
return (typeof msg?.origin === 'string' && msg.origin) ? msg.origin : 'parent';
}
function _send(ctx, ports) { function _send(ctx, ports) {
if (typeof ctx?.send === 'function') ctx.send(ports); if (typeof ctx?.send === 'function') ctx.send(ports);
} }
@@ -28,19 +38,19 @@ exports.setMode = (source, msg) => {
// forwards to these directly so behaviour is identical. // forwards to these directly so behaviour is identical.
exports.startup = async (source, msg) => { exports.startup = async (source, msg) => {
const p = msg.payload || {}; const p = msg.payload || {};
await source.handleInput(p.source ?? 'parent', 'execSequence', 'startup'); await source.handleInput(_origin(msg), 'execSequence', 'startup');
}; };
exports.shutdown = async (source, msg) => { exports.shutdown = async (source, msg) => {
const p = msg.payload || {}; const p = msg.payload || {};
await source.handleInput(p.source ?? 'parent', 'execSequence', 'shutdown'); await source.handleInput(_origin(msg), 'execSequence', 'shutdown');
}; };
exports.estop = async (source, msg) => { exports.estop = async (source, msg) => {
const p = msg.payload || {}; const p = msg.payload || {};
// Legacy emergencystop carried { source, action } — action defaults to // Legacy emergencystop carried { source, action } — action defaults to
// 'emergencystop' when only source is supplied via the canonical topic. // 'emergencystop' when only source is supplied via the canonical topic.
await source.handleInput(p.source ?? 'parent', p.action ?? 'emergencystop'); await source.handleInput(_origin(msg), p.action ?? 'emergencystop');
}; };
// Content-based alias router: legacy `execSequence` carried payload.action in // Content-based alias router: legacy `execSequence` carried payload.action in
@@ -57,13 +67,13 @@ exports.execSequenceAlias = async (source, msg, ctx) => {
exports.setSetpoint = async (source, msg) => { exports.setSetpoint = async (source, msg) => {
const p = msg.payload || {}; const p = msg.payload || {};
const action = p.action ?? 'execMovement'; const action = p.action ?? 'execMovement';
await source.handleInput(p.source ?? 'parent', action, Number(p.setpoint)); await source.handleInput(_origin(msg), action, Number(p.setpoint));
}; };
exports.setFlowSetpoint = async (source, msg) => { exports.setFlowSetpoint = async (source, msg) => {
const p = msg.payload || {}; const p = msg.payload || {};
const action = p.action ?? 'flowMovement'; const action = p.action ?? 'flowMovement';
await source.handleInput(p.source ?? 'parent', action, Number(p.setpoint)); await source.handleInput(_origin(msg), action, Number(p.setpoint));
}; };
exports.simulateMeasurement = (source, msg, ctx) => { exports.simulateMeasurement = (source, msg, ctx) => {

View File

@@ -63,7 +63,7 @@ module.exports = [
topic: 'set.flow-setpoint', topic: 'set.flow-setpoint',
aliases: ['flowMovement'], aliases: ['flowMovement'],
payloadSchema: { type: 'object' }, payloadSchema: { type: 'object' },
units: { measure: 'volumeFlowRate', default: 'm3/h' }, unit: 'm3/h',
description: 'Move the machine to a flow setpoint via flowMovement.', description: 'Move the machine to a flow setpoint via flowMovement.',
handler: handlers.setFlowSetpoint, handler: handlers.setFlowSetpoint,
}, },