feat: permissive unit check for user-defined measurement types + measurement digital-mode schema
MeasurementContainer.isUnitCompatible now short-circuits to accept any unit when the measurement type is not in the built-in measureMap. Known types (pressure, flow, power, temperature, volume, length, mass, energy) still validate strictly. This unblocks user-defined types in the measurement node's new digital/MQTT mode — e.g. 'humidity' with unit '%', 'co2' with 'ppm' — without forcing those units into the convert-module unit system. measurement.json schema: add 'mode.current' (analog | digital) and 'channels' (array) so the validator stops stripping them from the runtime config. Ignored in analog mode. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -411,6 +411,34 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mode": {
|
||||||
|
"current": {
|
||||||
|
"default": "analog",
|
||||||
|
"rules": {
|
||||||
|
"type": "enum",
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"value": "analog",
|
||||||
|
"description": "Single-scalar input mode (classic 4-20mA / PLC style). msg.payload is a number; the node runs one offset/scaling/smoothing/outlier pipeline and emits one MeasurementContainer slot."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "digital",
|
||||||
|
"description": "Multi-channel input mode (MQTT / IoT JSON style). msg.payload is an object keyed by channel names declared under config.channels; the node routes each key through its own pipeline and emits N slots from one input message."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Selects how incoming msg.payload is interpreted."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"channels": {
|
||||||
|
"default": [],
|
||||||
|
"rules": {
|
||||||
|
"type": "array",
|
||||||
|
"itemType": "object",
|
||||||
|
"minLength": 0,
|
||||||
|
"description": "Channel map used in digital mode. Each entry is a self-contained pipeline definition: {key, type, position, unit, scaling?, smoothing?, outlierDetection?, distance?}. Ignored in analog mode."
|
||||||
|
}
|
||||||
|
},
|
||||||
"outlierDetection": {
|
"outlierDetection": {
|
||||||
"enabled": {
|
"enabled": {
|
||||||
"default": false,
|
"default": false,
|
||||||
|
|||||||
@@ -141,11 +141,17 @@ class MeasurementContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isUnitCompatible(measurementType, unit) {
|
isUnitCompatible(measurementType, unit) {
|
||||||
const desc = this._describeUnit(unit);
|
// Unknown type (not in measureMap): accept any unit. This lets user-
|
||||||
if (!desc) return false;
|
// defined measurement types (e.g. 'humidity', 'co2', arbitrary IoT
|
||||||
|
// channels in digital mode) pass through without being rejected just
|
||||||
|
// because their unit string ('%', 'ppm', …) is not a known physical
|
||||||
|
// unit to the convert module. Known types are still validated strictly.
|
||||||
const normalizedType = this._normalizeType(measurementType);
|
const normalizedType = this._normalizeType(measurementType);
|
||||||
const expectedMeasure = this.measureMap[normalizedType];
|
const expectedMeasure = this.measureMap[normalizedType];
|
||||||
if (!expectedMeasure) return true;
|
if (!expectedMeasure) return true;
|
||||||
|
|
||||||
|
const desc = this._describeUnit(unit);
|
||||||
|
if (!desc) return false;
|
||||||
return desc.measure === expectedMeasure;
|
return desc.measure === expectedMeasure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user