146 Commits

Author SHA1 Message Date
znetsixe
693517cc8f fix: conditional abort recovery — don't auto-transition on routine aborts
The unconditional transition to 'operational' after every movement abort
caused a bounce loop when MGC called abortActiveMovements on each demand
tick: abort→operational→new-flowmovement→abort→operational→... endlessly.
Pumps never reached their setpoint.

Fix: abortCurrentMovement now takes an options.returnToOperational flag
(default false). Routine MGC aborts leave the pump in accelerating/
decelerating — the pump continues its residual movement and reaches
operational naturally. Shutdown/emergency-stop paths pass
returnToOperational:true so the FSM unblocks for the stopping transition.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 12:01:41 +02:00
znetsixe
086e5fe751 fix: remove bogus machineCurve default that poisoned prediction splines
The schema default for machineCurve.nq had a dummy pressure slice at
key "1" with x=[1..5] y=[10..50]. configUtils.updateConfig deep-merges
defaults into the real config, so this fake slice survived alongside the
real pressure slices (70000, 80000, ..., 390000 Pa). The predict class
then included it in its pressure-dimension spline, pulling all
interpolated y-values toward the dummy data at low pressures and
producing NEGATIVE flow predictions (e.g. -243 m³/h) where the real
curve is strictly positive.

Fix: default to empty objects {nq: {}, np: {}} so the deep merge adds
nothing. The validateMachineCurve function already returns the whole
default if the real curve is missing or invalid, so the empty default
doesn't break the no-curve-data path — it just stops poisoning the
real curve data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 10:27:59 +02:00
znetsixe
29b78a3f9b fix(childRegistrationUtils): alias rotatingmachine/machinegroupcontrol so production parents see them
The MGC and pumpingStation registerChild handlers dispatch on
softwareType === 'machine' / 'machinegroup' / 'pumpingstation' /
'measurement'. But buildConfig sets functionality.softwareType to the
lowercased node name, so in production rotatingMachine reports
'rotatingmachine' and machineGroupControl reports 'machinegroupcontrol'.
Result: the MGC <-> rotatingMachine and pumpingStation <-> MGC wiring
silently never hit the right branch in production, even though every
unit test passes (tests pass an already-aliased softwareType manually).

Fix: tiny SOFTWARE_TYPE_ALIASES map at the central registerChild
dispatcher in childRegistrationUtils. Real production names get
translated to the dispatch keys parents already check for, while tests
that pass already-aliased keys are unaffected (their values aren't in
the alias map and pass through unchanged).

  rotatingmachine        -> machine
  machinegroupcontrol    -> machinegroup

Verified end-to-end on Dockerized Node-RED: MGC now reports
'3 machine(s) connected' when wired to 3 rotatingMachine ports;
pumpingStation registers MGC as a machinegroup child and listens to
its predicted-flow stream.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:53:21 +02:00
znetsixe
43f69066af fix(asset-menu): supplier->type->model cascade lost the model dropdown
Reproduction (any node using assetMenu — measurement, rotatingMachine,
pumpingStation, monster, …):
  open node -> pick Vega supplier -> pick Pressure type
  -> model dropdown stays "Awaiting Type Selection"

Root cause: two interacting bugs in the chained dropdown wiring.

1. populate() inside both wireEvents() and loadData() auto-dispatched a
   synthetic 'change' event whenever the value of the rebuilt <select>
   differed from before the rebuild. That meant rebuilding 'type' inside
   the supplier change handler could fire the *type* change handler
   mid-way through, populate the model dropdown, and then return — only
   for the supplier handler to continue and unconditionally call
   populate(elems.model, [], '', undefined, 'Awaiting Type Selection'),
   wiping the model dropdown back to empty.

2. loadData() ran the same auto-dispatch path, so on initial open of a
   saved node the synthetic change cascaded through wireEvents listeners
   AND loadData's own sequential populate calls double-populated each
   level. The visible state depended on which path won the race.

Fix: convert the chain to an explicit downward cascade.

- populate() no longer dispatches change events. It simply rebuilds the
  <select> with placeholder + options and assigns the requested value.
- New cascadeFromSupplier / cascadeFromType / cascadeFromModel helpers
  read the *current DOM value* of each upstream <select>, look up the
  matching item in menuData, and rebuild the next level — then call the
  next cascade explicitly. Order is now deterministic and the parent
  handler can never wipe the child after the child was populated.
- Each <select>'s native 'change' listener is just the corresponding
  cascade function. Same code path runs for user picks AND for initial
  load, so saved-node restore behaves identically to a fresh pick.
- The cascades are exposed under window.EVOLV.nodes.<name>.assetMenu._cascade
  so loadData (or future sync code) can re-run them after async data
  arrives without duplicating logic.

No new DOM dependencies, no test framework changes. Existing
generalFunctions tests still 52/61 (same 9 pre-existing failures
unrelated to this change).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:50:45 +02:00
znetsixe
e50be2ee66 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>
2026-04-13 13:42:31 +02:00
znetsixe
75d16c620a fix: make movement abort unblock subsequent FSM transitions + add rotatingMachine schema keys
state.js: When moveTo catches a 'Movement aborted' or 'Transition aborted'
error, transition the FSM back to 'operational'. This ensures a subsequent
shutdown or emergency-stop sequence is accepted — previously the FSM stayed
stuck in 'accelerating'/'decelerating' and rejected stopping/idle
transitions, silently dropping shutdown commands issued mid-ramp. Also
emits a 'movementAborted' event for observability.

rotatingMachine.json: Add schema entries for functionality.distance,
functionality.distanceUnit, functionality.distanceDescription, and top-level
output.{process,dbase}. These keys are produced by buildConfig / the HTML
editor but were previously stripped by the validator with an
'Unknown key' warning on every deploy.

configs/index.js: Trim buildConfig so it no longer unconditionally injects
distanceUnit/distanceDescription — those keys are rotatingMachine-specific
and would otherwise produce Unknown-key warnings on every other node.

Verified via Docker-hosted Node-RED E2E: shutdown from accelerating now
reaches idle; emergency stop from accelerating reaches off; 0 Unknown-key
warnings in container logs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:21:18 +02:00
znetsixe
024db5533a fix: correct 3 anomalous power values in hidrostal-H05K-S03R curve
At pressures 1600, 3200, and 3300 mbar, flow values had leaked into the
np (power) section. Replaced with linearly interpolated values from
adjacent pressure levels.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:37:06 +02:00
znetsixe
13d1f83a85 fix: prevent infinite recursion in validateSchema for non-object schema entries
migrateConfig stamps a version string into config schemas. validateSchema
then iterates the string's character indices, causing infinite recursion.
Skip the 'version' key and guard against any non-object schema entries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 08:44:48 +02:00
znetsixe
f96476bd23 Merge commit '12fce6c' into HEAD
# Conflicts:
#	index.js
#	src/configs/index.js
#	src/configs/machineGroupControl.json
#	src/helper/assetUtils.js
#	src/helper/childRegistrationUtils.js
#	src/helper/configUtils.js
#	src/helper/logger.js
#	src/helper/menuUtils.js
#	src/helper/menuUtils_DEPRECATED.js
#	src/helper/outputUtils.js
#	src/helper/validationUtils.js
#	src/measurements/Measurement.js
#	src/measurements/MeasurementContainer.js
#	src/measurements/examples.js
#	src/outliers/outlierDetection.js
2026-03-31 18:07:57 +02:00
Rene De Ren
12fce6c549 Add diffuser config schema 2026-03-12 16:39:25 +01:00
Rene De Ren
814ee3d763 Support config-driven output formatting 2026-03-12 16:13:39 +01:00
Rene De Ren
31928fd124 fix: add missing migrateConfig method, config versioning, and formatters module
ConfigManager.migrateConfig() was called but never defined — would crash at runtime.
Added config version checking, migration support, and fixed createEndpoint indentation.
New formatters module (csv, influxdb, json) for pluggable output formatting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:33:22 +01:00
Rene De Ren
7e40ea0797 test: add child registration integration tests
32 tests covering registerChild, getChildren, deregistration, edge cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:31:58 +01:00
Rene De Ren
dec5f63b21 refactor: adopt POSITIONS constants, fix ESLint warnings, break menuUtils into modules
- Replace hardcoded position strings with POSITIONS.* constants
- Prefix unused variables with _ to resolve no-unused-vars warnings
- Fix no-prototype-builtins with Object.prototype.hasOwnProperty.call()
- Extract menuUtils.js (543 lines) into 6 focused modules under menu/
- menuUtils.js now 35 lines, delegates via prototype mixin pattern
- Add 158 unit tests for ConfigManager, MeasurementContainer, ValidationUtils

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:36:52 +01:00
Rene De Ren
fe2631f29b refactor: extract validators from validationUtils.js into strategy pattern modules
Break the 548-line monolith into focused modules:
- validators/typeValidators.js (number, integer, boolean, string, enum)
- validators/collectionValidators.js (array, set, object)
- validators/curveValidator.js (curve, machineCurve, dimensionStructure)

validationUtils.js now uses a VALIDATORS registry map and delegates to
extracted modules. Reduced from 548 to 217 lines.

Closes #2

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:15:01 +01:00
Rene De Ren
bf39b9df42 Fix sorting bug in validationUtils and add cache cap to AssetLoader
- validationUtils: unsorted x values now actually sorted (was returning false)
- validationUtils: duplicate x values now actually removed (was returning false)
- validationUtils: areNumbers check no longer skipped after sort/dedup
- AssetLoader: add maxCacheSize (default 100) with LRU-style eviction

Closes #21, closes #24

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:07:16 +01:00
Rene De Ren
f95ef43f05 Standardize softwareType to lowercase everywhere
- ConfigManager.buildConfig() now lowercases softwareType
- Updated config JSON defaults to lowercase
- childRegistrationUtils lowercases softwareType on extraction
- Closes #8

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:06:41 +01:00
Rene De Ren
89aec9a7eb Reset chaining context in MeasurementContainer.clear()
Closes #25

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:06:17 +01:00
Rene De Ren
135dfc31d3 Add base config schema and ConfigManager.buildConfig()
- New baseConfig.json: shared schema for general/logging/functionality/asset sections
- ConfigManager.buildConfig(): builds runtime config from UI inputs + domain overrides
- Eliminates the need for each nodeClass to manually construct base config sections
- All nodes can now use: cfgMgr.buildConfig(name, uiConfig, nodeId, domainConfig)

Closes #1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:59:26 +01:00
Rene De Ren
96fdf2a27a Fix orphaned debug log and array bounds check
- Remove console.log('hello:') from Measurement.js (#22)
- Add bounds check for peakIndex in predict_class.js (#23)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:56:42 +01:00
Rene De Ren
c698e5a1bc Remove deprecated menuUtils and childRegistrationUtils files
Closes #6

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:56:28 +01:00
Rene De Ren
089f4c5129 Add position constants, reactor/settler config schemas
- New src/constants/positions.js: POSITIONS enum (upstream/downstream/atEquipment/delta)
- New src/configs/reactor.json: Full schema for CSTR/PFR reactor parameters and ASM3 initial state
- New src/configs/settler.json: Schema for settler node
- Export POSITIONS, POSITION_VALUES, isValidPosition from index.js

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 13:43:24 +01:00
Rene De Ren
82094d8d09 Fix ESLint errors, bugs, and add gravity export
- Fix missing return in childRegistrationUtils.registerChild()
- Fix assertionUtils: assertNoNaN uses this.assertNoNaN
- Fix logger: nameModule uses this.nameModule
- Fix assetUtils: convert ESM to CommonJS
- Fix childRegistrationUtils_DEPRECATED: desc -> softwareType
- Add gravity export to index.js for rotatingMachine
- Fix ESLint errors across 18 files (no-undef, no-case-declarations,
  no-mixed-spaces-and-tabs, parsing errors)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 13:39:40 +01:00
znetsixe
27a6d3c709 updates 2026-03-11 11:13:05 +01:00
znetsixe
c60aa40666 update 2026-02-23 13:17:47 +01:00
znetsixe
1cfb36f604 agent updates 2026-02-12 10:14:56 +01:00
znetsixe
105a3082ab updates 2026-01-29 13:32:20 +01:00
znetsixe
cde331246c updates for asset registration 2026-01-29 10:22:12 +01:00
znetsixe
15c33d650b updates 2026-01-29 09:16:41 +01:00
znetsixe
a536c6ed5e update fetch function 2026-01-28 14:25:12 +01:00
znetsixe
266a6ed4a3 updates 2026-01-28 14:04:22 +01:00
znetsixe
37796c3e3b Merge remote-tracking branch 'origin/main' into dev-Rene 2025-12-19 11:50:14 +01:00
znetsixe
067017f2ea bug fix 2025-11-30 17:45:45 +01:00
znetsixe
52f1cf73b4 bug fixes 2025-11-30 09:24:29 +01:00
Rene De ren
a81733c492 added examples 2025-11-28 16:29:24 +01:00
znetsixe
555d4d865b added sum and child id support 2025-11-28 09:59:39 +01:00
znetsixe
db85100c4d updates to pumping station control method 2025-11-27 17:46:43 +01:00
znetsixe
b884faf402 added monster config 2025-11-25 16:19:33 +01:00
znetsixe
2c43d28f76 updated safety features 2025-11-25 14:58:01 +01:00
pimmoerman
858189d6da Update get_all_assets.php vanaf tagcode.app 2025-11-21 03:00:01 +00:00
pimmoerman
ec42ebcb25 Update get_all_assets.php vanaf tagcode.app 2025-11-20 12:15:55 +00:00
znetsixe
d52a1827e3 Added min height based on | fixed dynamic speed in %/sec 2025-11-20 11:09:26 +01:00
pimmoerman
f4629e5fcc Update get_all_assets.php vanaf extern endpoint 2025-11-17 15:57:29 +00:00
pimmoerman
dafe4c5336 Delete datasets/tagcodeapp_product_models.json 2025-11-17 15:57:15 +00:00
pimmoerman
5439d5111a Delete datasets/tagcodeapp_assets.json 2025-11-17 15:57:08 +00:00
pimmoerman
1e5ef47a4d Delete datasets/get_all_assets.php 2025-11-17 15:57:02 +00:00
pimmoerman
2b87c67876 Update get_all_assets.php vanaf extern endpoint 2025-11-17 15:00:01 +00:00
pimmoerman
0db90c0e4b Delete data/get_all_assets.php 2025-11-17 14:58:33 +00:00
pimmoerman
1e07093101 Update get_all_assets.php vanaf extern endpoint 2025-11-17 14:58:01 +00:00
znetsixe
f2c9134b64 Added new menu jsons 2025-11-13 19:39:48 +01:00