From: Jérôme Benoit Date: Wed, 22 Apr 2026 09:06:51 +0000 (+0200) Subject: fix(cli): make high-level OCPP commands version-aware (#1801) X-Git-Tag: cli@v4.5.0~13 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=804dce720fd281de52499510cba6d8cbb01fdf0d;p=e-mobility-charging-stations-simulator.git fix(cli): make high-level OCPP commands version-aware (#1801) * fix(cli): make high-level transaction and authorize commands OCPP version-aware - transaction start: detect station OCPP version, send TRANSACTION_EVENT with idToken/evse payload for 2.0.x or START_TRANSACTION for 1.6 - transaction stop: same version detection, send TRANSACTION_EVENT Ended for 2.0.x or STOP_TRANSACTION for 1.6; accept string transaction IDs - ocpp authorize --id-tag: send idToken object for 2.0.x, idTag for 1.6; -p payload passthrough unchanged (low-level override) - action.ts: extract fetchStationList helper, export resolveOcppVersion * docs(cli): clarify prefix matching behavior in resolveOcppVersion JSDoc * refactor(cli): use switch/case for OCPP version branching and clean up help text * fix(cli): address audit findings for cross-version OCPP compliance - R1: status-notification version-aware: --error-code optional, validated for OCPP 1.6; OCPP 2.0.x uses connectorStatus with optional --evse-id - R2: add optional --evse-id to meter-values - R3: skipped (callers already throw clear error for heterogeneous/no-match) - R4: skipped (handleStopTransaction is 1.6-only, transactionId always number) - R5: JSDoc on version-specific ProcedureName entries - R6: comment on handleStopTransaction noting 1.6-only * refactor(cli): consolidate version detection, fix DRY violations, and harden edge cases - F-01: comment noting OCPP20TriggerReasonEnumType duplication - F-02/F-04: extract resolveOcppVersionFromProgram (single fetch, returns resolved hashIds) - F-03: export MIXED_OCPP_VERSION_ERROR constant - F-05: default evse.id to 1, add --evse-id to transaction start - F-06: document -p limitation in help text - F-07: remove idTag ?? '' dead code - F-08: remove redundant === id check - F-09: add test for ambiguous prefix with homogeneous versions - F-10: rewrite handleStopTransaction comment * style: remove unnecessary duplication comments in ui/common enums * refactor(cli): use commander conflicts() for mutually exclusive options ocpp authorize: --id-tag and -p/--payload are now declared as mutually exclusive via Option.conflicts(). Commander enforces this at parse time. * fix(cli): resolve audit findings — BUG-01, DRY-01, DEAD-01, ROBUST-01, PERF-01 - BUG-01: use resolvedHashIds (not raw hashIds) in resolveOcppVersionFromProgram - DRY-01: extract resolveShortHashIdsFromList pure helper, used by both resolveShortHashIds and resolveOcppVersionFromProgram - DEAD-01/DOC-01: remove unused resolveOcppVersion, update JSDoc references - ROBUST-01: seqNo 1 for transaction stop (start uses 0) - PERF-01: resolveOcppVersionFromProgram returns config, runAction accepts preloadedConfig to skip redundant loadConfig call * chore: refine .gitignore Signed-off-by: Jérôme Benoit * fix(cli): simplify OCPP 2.0.x transaction payloads to match builder options - transaction start: send flat OCPP20TransactionEventOptions (connectorId, evseId, idToken) instead of wire-format fields (seqNo, timestamp, transactionInfo nesting, evse structure) - transaction stop: send flat transactionId instead of nested transactionInfo, remove hardcoded seqNo/timestamp/triggerReason - Remove evseId ?? 1 default (let builder resolve from connectorId) - Remove unused imports (randomUUID, OCPP20TriggerReasonEnumType) - Fix meter-values --evse-id misleading help text - Add test for mixed matching/non-matching hashIds Addresses review comments from hyperspace-insights and Copilot, cross-validated with audit v2 findings BUG-01, BUG-02, BUG-03. * fix(cli): harmonize all OCPP commands with version-aware conflicts pattern - Add early NO_STATIONS_ERROR check in resolveOcppVersionFromProgram - Refactor status-notification, meter-values, transaction start/stop to use .addOption/.conflicts() pattern matching authorize's design - Make meter-values version-aware: OCPP 1.6 sends connectorId, OCPP 2.0 sends evseId, passthrough mode sends only routing fields - Fix --evse-id help text in transaction start (was claiming false default) - Fix pre-existing jsdoc/require-throws-type lint warning * fix(cli): add connectorId to transaction stop for OCPP 2.0.x and harmonize evseId conflicts - Add --connector-id option to transaction stop (defaults to 1) so buildTransactionEvent resolves the correct connector on multi-connector stations - Convert all --evse-id options to .addOption/.conflicts('payload') for consistent UX with other semantic options - Add evseId to reverse .conflicts() lists on -p/--payload options * fix(cli): update JSDoc and comments to match current behavior - Update resolveOcppVersionFromProgram JSDoc: returns OCPPVersion (not undefined), add @throws documentation for all error cases - Update MIN_FULL_HASH_LENGTH comment: now validates existence, not just skips resolution * fix(cli): route version-detection errors through formatter for --json mode Add handleActionErrors wrapper that catches errors from version detection, option validation, and hash-ID resolution before runAction, routing them through the same formatter used by runAction. Without this, errors in --json mode were output as plain text instead of structured JSON. * Apply suggestion from @jerome-benoit * refactor(cli): extract shared error formatter and clean up exports - Extract formatError() from duplicated catch blocks in handleActionErrors and runAction - Align authorize error message with the pattern used by all other commands ('X is required when -p/--payload is not provided') - Remove unnecessary exports from 3 internal-only error constants (NO_STATIONS_ERROR, MIXED_OCPP_VERSION_ERROR, UNKNOWN_OCPP_VERSION_ERROR) * fix(cli): standardize option help texts and remove redundancy - Standardize EVSE ID help text to 'EVSE ID (OCPP 2.0.x; derived from connector ID if omitted)' across meter-values, status-notification, and transaction start - Simplify error-code help text from 'OCPP 1.6 only; required for 1.6' to 'OCPP 1.6' (the constraint is already enforced at runtime) * docs(cli): document version-aware commands and new OCPP 2.0.x options - Add --evse-id to meter-values, status-notification, transaction start - Add --connector-id to transaction stop (required for OCPP 2.0.x) - Mark --error-code as optional (OCPP 1.6 only) - Mark --vendor-id as optional in data-transfer - Document -p/--payload support for transaction commands - Add Version-aware commands section with OCPP 1.6 vs 2.0.x mapping - Update both README.md and SKILL.md consistently * docs(cli): fix pre-existing documentation gaps in README and SKILL.md - Add missing station add options: --persistent-config, --ocpp-strict - Add missing station delete --delete-config example in SKILL.md - Add missing atg stop --connector-ids in SKILL.md - Fix meter-values: both --connector-id and --evse-id are optional (at least one required) - Fix ATG --connector-ids notation: instead of - Add hashId prefix matching note to SKILL.md * fix(cli): harmonize user-facing strings and fix documentation accuracy Code: - Harmonize 'station(s)' terminology (drop 'charging' prefix in station.ts descriptions to match all other command files) - Fix NO_STATIONS_ERROR to use consistent 'stations' wording - Fix data-transfer --data description: free-form string, not JSON only - Fix transaction unsupported version error: direct users to 'ocpp transaction-event -p' instead of generic '-p' which forces 1.6 Docs (README + SKILL.md): - Fix merge claim: -p conflicts with typed options on most commands, only data-transfer allows merge - Add meter-values 'at least one required' constraint note - Add --connector-id required for transaction stop on OCPP 2.0.x in version-aware table - Fix data-transfer --data placeholder from to * refactor(cli): extract duplicated unsupported version error in transaction.ts Extract inline error string into a local const within createTransactionCommands to avoid duplication across the start and stop default switch branches. * fix(cli): correct meter-values payload for OCPP 2.0.x stations The OCPP 2.0.x MeterValues JSON schema does not allow connectorId as a property. The previous implementation conditionally included connectorId in the payload for OCPP 2.0.x, which caused schema validation failures in the simulator ("additionalProperty: connectorId — must NOT have additional properties"). For OCPP 2.0.x, evseId is the only valid EVSE identifier in a MeterValues request. The fix now requires --evse-id for OCPP 2.0.x stations and sends only evseId in the payload. If only --connector-id is supplied against a 2.0.x station, a clear error message guides the user to use --evse-id instead. The --connector-id help text is also updated to indicate it is OCPP 1.6 only for this command. Co-Authored-By: Claude Sonnet 4.6 * docs(cli): align meter-values documentation with evseId-only OCPP 2.0.x fix Update README and SKILL.md to reflect that meter-values requires --evse-id for OCPP 2.0.x (connectorId is not a valid MeterValues field in 2.0.x). Show separate OCPP 1.6 and 2.0.x usage lines. * fix(cli): harmonize meter-values help texts and error message - Drop 'only' from --connector-id help: '(OCPP 1.6)' matches --error-code pattern in status-notification - Drop 'required' from --evse-id help: '(OCPP 2.0.x)' matches version-only pattern used for version-exclusive options - Remove verbose parenthetical from evseId error message to match the terse pattern used by all other version-specific errors * fix(cli): use SCREAMING_CASE for error constant and add missing exit code - Rename unsupportedVersionError to UNSUPPORTED_VERSION_ERROR in transaction.ts to match the naming convention used by all error constants in action.ts - Add exit code 143 (SIGTERM) to SKILL.md exit codes table * fix(cli): complete resolveOcppVersionFromList JSDoc for unknown versions Add 'or all versions are unknown' to the @returns description to document that the function also returns undefined when all targeted stations have ocppVersion: undefined (Set {undefined}, size 1). * fix(cli): align error constant naming and fix README station list comment - Rename UNSUPPORTED_VERSION_ERROR to UNSUPPORTED_OCPP_VERSION_ERROR in transaction.ts to match the naming convention with OCPP_ prefix used by the exported constant in action.ts - Fix README inline comment: 'List all stations' to match station.ts description (was still 'List all charging stations') --------- Signed-off-by: Jérôme Benoit Co-authored-by: Claude Sonnet 4.6 --- diff --git a/.gitignore b/.gitignore index 6aeb9cba..46096a2b 100644 --- a/.gitignore +++ b/.gitignore @@ -126,3 +126,4 @@ temp/ performanceRecords.json performanceRecords.json.lock *.db +.hermes/ diff --git a/src/types/UIProtocol.ts b/src/types/UIProtocol.ts index 29f41cdb..da5e4db3 100644 --- a/src/types/UIProtocol.ts +++ b/src/types/UIProtocol.ts @@ -41,12 +41,15 @@ export enum ProcedureName { START_AUTOMATIC_TRANSACTION_GENERATOR = 'startAutomaticTransactionGenerator', START_CHARGING_STATION = 'startChargingStation', START_SIMULATOR = 'startSimulator', + /** OCPP 1.6 only. Use TRANSACTION_EVENT for OCPP 2.0.x. */ START_TRANSACTION = 'startTransaction', STATUS_NOTIFICATION = 'statusNotification', STOP_AUTOMATIC_TRANSACTION_GENERATOR = 'stopAutomaticTransactionGenerator', STOP_CHARGING_STATION = 'stopChargingStation', STOP_SIMULATOR = 'stopSimulator', + /** OCPP 1.6 only. Use TRANSACTION_EVENT for OCPP 2.0.x. */ STOP_TRANSACTION = 'stopTransaction', + /** OCPP 2.0.x only. Use START_TRANSACTION / STOP_TRANSACTION for OCPP 1.6. */ TRANSACTION_EVENT = 'transactionEvent', UNLOCK_CONNECTOR = 'unlockConnector', } diff --git a/ui/cli/README.md b/ui/cli/README.md index e2c0a811..0b7c663d 100644 --- a/ui/cli/README.md +++ b/ui/cli/README.md @@ -143,7 +143,7 @@ evse-cli simulator stop # Stop the simulator #### station ```shell -evse-cli station list # List all charging stations +evse-cli station list # List all stations evse-cli station start [hashId...] # Start station(s) evse-cli station stop [hashId...] # Stop station(s) evse-cli station add -t