Jérôme Benoit [Sun, 29 Mar 2026 01:04:50 +0000 (03:04 +0200)]
fix: harmonize idToken type to ISO14443 between Authorize and TransactionEvent Started
The Authorize request already used ISO14443 for RFID tag identifiers,
but startTransactionOnConnector hardcoded Central (now Local after
previous commit). Align both to ISO14443 for consistency.
- Auto-derive chargingState in buildTransactionEvent when not explicitly
provided (E02.FR.13: Started always has chargingState)
- Use idToken type Local instead of hardcoded Central in
startTransactionOnConnector for ATG local tag consistency (E02.FR.01)
- Add TimeLimitReached mapping in mapStopReasonToOCPP20 for stations
that need to report time-limited transaction stops
Jérôme Benoit [Sat, 28 Mar 2026 23:18:42 +0000 (00:18 +0100)]
refactor: harmonize connector iteration to use iterateConnectors() across prod and tests
Unify all connector/EVSE iteration patterns behind the iterateConnectors()
generator API, eliminating duplicated if(hasEvses)/else branching in both
production and test code.
Production:
- Refactor getNumberOfConnectors(), hasConnector(),
getNumberOfReservationsOnConnectorZero() to use iterateConnectors()
Tests:
- Harmonize 10 mock methods in StationHelpers.ts to match production patterns
- Collapse OCPP20TestUtils resetConnectorTransactionState from dual-path to
single iterateConnectors() loop
- Replace direct evseStatus.connectors map access with getConnectorStatus()
and getConnectorIdByEvseId() helpers across 4 test files
- Remove redundant EVSE cleanup loops in standardCleanup and fullResetStation
- Align getReservationBy mock signature to production types (ReservationKey)
- Fix alphabetical ordering of mock methods
Jérôme Benoit [Sat, 28 Mar 2026 20:15:44 +0000 (21:15 +0100)]
refactor: encapsulate connector/EVSE iteration behind generator API
Introduce iterateConnectors() and iterateEvses() generators on
ChargingStation, replacing ~30 duplicated if(hasEvses)/else iteration
patterns across the codebase. Make connectors and evses Maps private
to enforce usage of the new API.
- Add ConnectorEntry and EvseEntry as unified types for both iteration
and serialization, removing duplicate ConnectorDataEntry/EvseDataEntry
- Add hasEvse() accessor method for EVSE existence checks
- Fix remoteStartId not propagated in TransactionEvent (F01.FR.25)
- Fix messagesInQueue in GetTransactionStatus to check actual queue
- Fix OCPP 1.6 changeAvailability losing SCHEDULED response
- Consolidate ad-hoc test mock factories to use createMockChargingStation
- Update UI wire format and components for unified types
BREAKING CHANGE: connectors and evses Maps are now private on
ChargingStation. Use iterateConnectors(), iterateEvses(), hasEvse(),
getEvseStatus(), getConnectorStatus() instead of direct Map access.
Jérôme Benoit [Sat, 28 Mar 2026 16:37:58 +0000 (17:37 +0100)]
test: isolate readCombinedLog tests from real logs directory
Replace direct writes to the project's logs/ directory with temporary
directories and Configuration cache overrides, following the established
mkdtempSync/tmpdir pattern used in FileUtils and IdTagsCache tests.
Jérôme Benoit [Sat, 28 Mar 2026 16:15:58 +0000 (17:15 +0100)]
test: add symmetric Ended meter value tests for start/stop/zero-interval
Cover startEndedMeterValues (timer + array init), stopEndedMeterValues
(timer clear), and interval=0 edge case (array init without timer).
Follows existing Updated test pattern for consistency.
Jérôme Benoit [Sat, 28 Mar 2026 16:06:49 +0000 (17:06 +0100)]
feat: implement TxEnded meter value accumulator per OCPP 2.0.1 spec §2.1
Per E06.FR.11 and J02.FR.10, TransactionEvent(Ended) must contain meter
values sampled every TxEndedInterval from transaction start, with the
final sample marked as Transaction.End context.
- Add TxEndedInterval to OCPP20RequiredVariableName enum
- Add start/stopEndedMeterValues and getTxEndedInterval
- Accumulate periodic samples during transaction, flush in Ended event
- Harmonize Updated/Ended naming across API, variables, and log messages
- Exclude transactionEndedMeterValues from serialized configuration
- Fix stopEndedMeterValues incorrectly called in startUpdatedMeterValues
- Restore JSDoc-free ConnectorStatus fields
- Fix DEFAULT_WS_PING_INTERVAL constant reference
- Update test fixtures and assertions for serialization coverage
Jérôme Benoit [Sat, 28 Mar 2026 14:21:35 +0000 (15:21 +0100)]
refactor: move ConfigurationValueSize, ReportingValueSize, ValueSize to OCPP20OptionalVariableName
Per OCPP 2.0.1 appendices CSV (dm_components_vars.csv), these three
DeviceDataCtrlr variables are required=no. Move them from
OCPP20RequiredVariableName to OCPP20OptionalVariableName to match
the spec classification.
Jérôme Benoit [Sat, 28 Mar 2026 14:13:11 +0000 (15:13 +0100)]
refactor: add SimulateSignatureVerificationFailure to OCPP20VendorVariableName enum
Replace string literal with enum reference in OCPP20VariableRegistry
and OCPP20IncomingRequestService for type safety and consistency with
CertificatePrivateKey and ConnectionUrl vendor variables.
Jérôme Benoit [Sat, 28 Mar 2026 13:20:30 +0000 (14:20 +0100)]
refactor: use OCPP20RequiredVariableName for measurands in OCPP20ServiceUtils
Replace StandardParametersKey with OCPP20RequiredVariableName for
TxStartedMeasurands and TxEndedMeasurands in buildTransaction*MeterValues.
Remove unused StandardParametersKey import.
Jérôme Benoit [Sat, 28 Mar 2026 12:29:21 +0000 (13:29 +0100)]
refactor: move debug param to last position in buildMeterValue
Reorder buildMeterValue signature so debug is the last optional
parameter, consistent with all other validate*MeasurandValue functions.
Removes need to pass explicit false to reach measurandsKey and context.
Jérôme Benoit [Sat, 28 Mar 2026 12:05:34 +0000 (13:05 +0100)]
refactor: replace Measurands string literal with OCPP20RequiredVariableName enum
Add Measurands to OCPP20RequiredVariableName enum (required per OCPP
2.0.1 Part 2 §2.7.1, AlignedDataCtrlr component) and replace all string
literals in ConfigurationKeyUtils mapping and OCPP20VariableRegistry.
Jérôme Benoit [Sat, 28 Mar 2026 00:17:49 +0000 (01:17 +0100)]
fix: correct WebSocketPingInterval documentation and registry default
- Remove vendor-specific ChargingStation.WebSocketPingInterval entry
from README (already listed under OCPPCommCtrlr per OCPP 2.0.1 spec)
- Use Constants.DEFAULT_WEBSOCKET_PING_INTERVAL in OCPPCommCtrlr registry
entry instead of hardcoded '30' for single source of truth
Jérôme Benoit [Sat, 28 Mar 2026 00:09:34 +0000 (01:09 +0100)]
fix: map WebSocketPingInterval to OCPPCommCtrlr per OCPP 2.0.1 spec
ChargingStation.WebSocketPingInterval is vendor-specific. The canonical
variable per OCPP 2.0.1 Part 4 §8.4 is OCPPCommCtrlr.WebSocketPingInterval.
Update both the 1.6→2.0 mapping and the keba-ocpp2 template.
Jérôme Benoit [Sat, 28 Mar 2026 00:02:08 +0000 (01:02 +0100)]
test: add whitespace-padded value coverage for convertToBoolean
Align test coverage across root simulator and web UI components for
trim handling of ' true ', ' 1 ', ' false ', ' TRUE ', 'True', 'FALSE',
and numeric 2.
Jérôme Benoit [Fri, 27 Mar 2026 23:50:22 +0000 (00:50 +0100)]
test: restore and harmonize OCPP 2.0 transaction meter value assertions
- Add symmetric buildTransactionEndedMeterValues tests via requestStopTransaction
(context=Transaction.End, measurand=Energy, no config key, no EVSE template)
- Strengthen buildTransactionStartedMeterValues assertions with strict
context and measurand checks using OCPP enum constants
- Refactor Started tests: shared station setup in beforeEach, remove duplication
- Configure TxEndedMeasurands in deauthorization test for real coverage
- Remove comments that restate test names
Jérôme Benoit [Fri, 27 Mar 2026 23:13:03 +0000 (00:13 +0100)]
feat: support configurable measurands per transaction stage in OCPP 2.0
- Thread measurandsKey and context params through the meter value pipeline
(getSampledValueTemplate, build*MeasurandValue, voltage helpers)
- buildTransactionStartedMeterValues uses SampledDataCtrlr.TxStartedMeasurands
with Transaction.Begin context
- buildTransactionEndedMeterValues uses SampledDataCtrlr.TxEndedMeasurands
with Transaction.End context
- Add OCPP 1.6→2.0 mappings for MeterValuesAlignedData,
ClockAlignedDataInterval, StopTxnSampledData, StopTxnAlignedData
- Reorder getSampledValueTemplate params: measurandsKey before measurand
- Log warn (not debug) when meter value building fails in transaction events
- Add .trim() to convertToBoolean for whitespace-padded values
Jérôme Benoit [Fri, 27 Mar 2026 21:40:34 +0000 (22:40 +0100)]
fix: use case-insensitive boolean parsing for OCPP configuration values
- Replace strict string comparisons (=== 'true'/'false') with
convertToBoolean() or .toLowerCase() across OCPP 1.6 and 2.0 stacks
- Add missing OCPP 1.6→2.0 key mappings for HeartbeatInterval,
HeartBeatInterval, and WebSocketPingInterval
- Add missing readonly field to 4 chargex template configuration keys
- Add .trim() to convertToBoolean for whitespace-padded values
Jérôme Benoit [Fri, 27 Mar 2026 20:50:43 +0000 (21:50 +0100)]
refactor: harmonize errMsg → errorMsg for intra-file naming consistency
OCPPServiceUtils.ts used both errMsg (4x) and errorMsg (1x) for the
same semantic. PerformanceStatistics.ts used errMsg (4x) while the
rest of the codebase uses errorMsg. Align to errorMsg everywhere.
Jérôme Benoit [Fri, 27 Mar 2026 19:13:36 +0000 (20:13 +0100)]
refactor: use Number.isNaN() instead of global isNaN()
Replace global isNaN() with Number.isNaN() for stricter type checking.
Global isNaN() coerces the argument to a number first, which can produce
unexpected results for non-numeric strings.
Jérôme Benoit [Fri, 27 Mar 2026 19:10:32 +0000 (20:10 +0100)]
fix: replace incorrect zero fallbacks for maximumPower and maximumAmperage
Station physical properties (maximumPower, maximumAmperage) are validated
> 0 at startup. Using ?? 0 as fallback silently produces invalid states:
0W power limits blocking all charging, 0A amperage in config keys.
Jérôme Benoit [Fri, 27 Mar 2026 18:50:01 +0000 (19:50 +0100)]
refactor: eliminate all non-null assertion suppressions with proper null guards
Remove 104 eslint-disable-next-line @typescript-eslint/no-non-null-assertion
suppressions across 23 files by replacing non-null assertions (!) with
semantically correct alternatives: local variable extraction with null
guards, optional chaining (?.), nullish coalescing (??) with proper
default constants, and error logging for invalid states.
Key improvements:
- Use existing DEFAULT_POOL_MAX_SIZE, DEFAULT_POOL_MIN_SIZE, and
DEFAULT_ELEMENTS_PER_WORKER constants instead of hardcoded fallbacks
- Add proper error logging for powerDivider undefined/invalid states
instead of silently computing wrong values
- Add connectorId null guard with throw in handleMeterValues instead of
silently defaulting to connector 0
- Ensure .finally() always sends a response to prevent caller hangs
- Align variable naming with codebase conventions (connectorStatus,
templateStatistics, commandStatisticsData, entryStatisticsData)
Jérôme Benoit [Fri, 27 Mar 2026 14:30:15 +0000 (15:30 +0100)]
refactor: type buildTransactionEvent with OCPP20TransactionEventOptions
Replace the untyped Record<string, unknown> cast in buildTransactionEvent
with the proper OCPP20TransactionEventOptions parameter type. Add build
hint fields to the options interface. Remove 64 stale as-unknown-as casts
from transaction event tests.
Widen buildRegistryKey, buildCaseInsensitiveCompositeKey, and
VariableMetadata.component to accept OCPP20ComponentName and VariableName
enums directly, eliminating 429 as-string casts across the registry and
variable manager. 8 casts retained on enum comparison lines required by
no-unsafe-enum-comparison lint rule.
Jérôme Benoit [Fri, 27 Mar 2026 13:23:14 +0000 (14:23 +0100)]
refactor: consolidate enforceMessageLimits types with generic R and RejectionReason
- Add generic type parameter R to enforceMessageLimits and
enforcePostCalculationBytesLimit, eliminating 4 'as typeof' casts
- Extract RejectionReason interface (additionalInfo + reasonCode) to
replace inline anonymous types, aligned with StatusInfoType fields
- Remove all enum→string→enum round-trips in callers
Jérôme Benoit [Fri, 27 Mar 2026 12:55:08 +0000 (13:55 +0100)]
fix: type buildRejected reasonCode as ReasonCodeEnumType instead of string
Eliminates the pointless enum→string→enum round-trip: the callback
parameter is now typed as ReasonCodeEnumType directly, removing the
as-string casts at call sites and the reverse keyof-typeof reconversion
in callers.
Add LocalAuthListCtrlr.Enabled, ReservationCtrlr.Enabled/NonEvseSpecific,
TxCtrlr.EVConnectionTimeOut, AuthCtrlr.LocalAuthorizationOffline to
keba-ocpp2 template — previously impossible due to key collisions.
- Add LocalAuthListEnabled → LocalAuthListCtrlr.Enabled key remapping
- Add ReserveConnectorZeroSupported → ReservationCtrlr.NonEvseSpecific remapping
- Remove AuthCtrlr.Enabled from template (no application consumer)
- Add NonEvseSpecific, MaxEnergyOnInvalidId to OCPP20OptionalVariableName enum
- Replace string literals with enum refs in registry and service utils
- Add tests for the 2 new key remappings
Jérôme Benoit [Fri, 27 Mar 2026 11:31:06 +0000 (12:31 +0100)]
fix: use Component.Variable[.Instance] key format for OCPP 2.0 variable persistence
The previous format used bare variable names (e.g., 'Enabled'), causing
collisions across components (9 components define Enabled, 8+ define
Available, etc.). Now uses the spec's (Component, Variable, Instance)
triplet as the persisted configuration key.
- Rewrite computeConfigurationKeyName to return Component.Variable format
- Remove shouldFlattenInstance (no longer needed)
- Extract buildConfigKey helper in ConfigurationKeyUtils, export via barrel
- Add MaxCertificateChainSize to OCPP20OptionalVariableName enum
- Update all direct config key lookups with component prefix
- Update keba-ocpp2 template keys to new format
- Update OCPP2_PARAMETER_KEY_MAP resolved values
- Replace all enum string literals in log messages with enum references
- Update all tests to use new key format
Jérôme Benoit [Thu, 26 Mar 2026 22:55:28 +0000 (23:55 +0100)]
fix: remove OrganizationName from ISO15118Ctrlr (spec says SecurityCtrlr only)
Per OCPP 2.0.1 appendix section 3.1.15, OrganizationName belongs to
SecurityCtrlr only. The duplicate entry under ISO15118Ctrlr was not
in the spec and shadowed the SecurityCtrlr default value.
Jérôme Benoit [Thu, 26 Mar 2026 22:25:20 +0000 (23:25 +0100)]
refactor: add Enabled to OCPP20RequiredVariableName enum and fix LocalAuthListCtrlr.Enabled mapping
Replace all 'Enabled' string literals with OCPP20RequiredVariableName.Enabled
in the variable registry and auth adapter. Move LocalAuthListEnabled
default from AuthCtrlr to LocalAuthListCtrlr component per OCPP 2.0.1 spec.
Jérôme Benoit [Thu, 26 Mar 2026 22:09:05 +0000 (23:09 +0100)]
fix: align OCPP 2.0 variable names to spec (LocalPreAuthorization, LocalAuthorizationOffline)
Rename LocalPreAuthorize → LocalPreAuthorization and
LocalAuthorizeOffline → LocalAuthorizationOffline to match the OCPP
2.0.1 appendix. Add key resolution mapping for both. Replace string
literals with enum references in OCPP20AuthAdapter.
Jérôme Benoit [Thu, 26 Mar 2026 20:35:50 +0000 (21:35 +0100)]
fix: use OCPP version-specific parameter keys for meter value measurands
Remap keba-ocpp2 template configuration keys from OCPP 1.6 names to
OCPP 2.0 variable names (MeterValuesSampledData → TxUpdatedMeasurands,
MeterValueSampleInterval → TxUpdatedInterval, AuthorizeRemoteTxRequests
→ AuthorizeRemoteStart). Remove OCPP 1.6-only keys with no 2.0
equivalent. Use StandardParametersKey union to resolve the correct
key at runtime based on OCPP version.
Jérôme Benoit [Thu, 26 Mar 2026 20:00:03 +0000 (21:00 +0100)]
docs: list OCPP 2.0 device model variables by component in README
Replace the incorrect GetVariables/SetVariables command listing with
141 device model variables across 19 components extracted from
OCPP20VariableRegistry.ts. Vendor-specific variables are marked.
Matches the structure used for OCPP 1.6 configuration keys.
- Add test for InvalidSignature path when SimulateSignatureVerificationFailure is true
- Add test for normal path when SimulateSignatureVerificationFailure is false (TDD red phase)
- Tests verify lifecycle termination and SecurityEventNotification type correctness
- Evidence: typecheck & lint pass; tests fail as expected (awaiting Task 3 implementation)
* fix(ocpp2): address PR review feedback on firmware signature verification
- Await sendSecurityEventNotification in failure path for consistency with success path
- Reorder test assertions: check array length before index access
- Add tick-forward verification that lifecycle stops after InvalidSignature
- Remove redundant standardCleanup() calls already handled by afterEach
- Remove firmware signature verification note from README
* fix(ocpp2): improve firmware update spec conformance and test quality
- L01.FR.07: Move EVSE unavailability check inside wait loop for continuous monitoring
- L01.FR.30: Honor retries/retryInterval with simulated download retry cycle
- Merge retry test into existing DownloadFailed test (DRY)
- Add EVSE continuous monitoring lifecycle test (L01.FR.07)
- Fix assertion ordering: length checks before index access
- Remove as-unknown-as-string cast in favor of String()
- Tighten assert.ok to assert.notStrictEqual where applicable
* fix(tests): type CapturedOCPPRequest.command as OCPP20RequestCommand
- Replace string type with OCPP20RequestCommand enum on CapturedOCPPRequest.command
- Remove 6 unnecessary 'as string' casts across UpdateFirmware and TransactionEvent tests
- Replace 'Unavailable' string literal with OCPP20ConnectorStatusEnumType.Unavailable
- Remove unnecessary optional chaining on non-nullable payload
- Complete @param JSDoc for retries/retryInterval on simulateFirmwareUpdateLifecycle
* fix(tests): replace flaky sentRequests assertions with mock.method spy in EVSE monitoring test
Mock sendEvseStatusNotifications directly instead of asserting on fire-and-forget
side effects captured in sentRequests. The internal async chain (sendAndSetConnectorStatus
→ dynamic import → requestHandler) needed non-deterministic flushMicrotasks() stacking.
The spy makes assertions synchronous and CI-deterministic.
Jérôme Benoit [Thu, 26 Mar 2026 16:42:21 +0000 (17:42 +0100)]
fix: respect elementAddDelay by using sequential startup when configured
The perf commit 218fd550 switched to parallel Promise.allSettled for
startup speed, but broke elementAddDelay since all stations launched
simultaneously. Now uses sequential await loop when elementAddDelay > 0
and parallel allSettled when 0 or unset. Removes redundant outer
try/catch — config errors propagate as fatal, station errors are
handled per-station in both paths.
Jérôme Benoit [Thu, 26 Mar 2026 00:02:01 +0000 (01:02 +0100)]
fix: cleanup connector after queued TransactionEvent.Ended replay
Extract cleanupEndedTransaction() in OCPP20ServiceUtils to consolidate
stopPeriodicMeterValues + resetConnectorStatus + unlock + Available
status. Called from both stopTransaction20 (normal flow) and
sendQueuedTransactionEvents (offline replay). Fixes stale Occupied
status and orphaned meter value interval after queued Ended events.
Jérôme Benoit [Wed, 25 Mar 2026 22:15:51 +0000 (23:15 +0100)]
feat: add server-side refresh notification over WebSocket
Bootstrap calls scheduleClientNotification() after each cache mutation.
A 500ms debounce collapses rapid updates into a single broadcast of
ProtocolNotification [ServerNotification.REFRESH] to all connected WS
clients. setChargingStationData/deleteChargingStationData return boolean
so callers only notify on actual change. Frontend responseHandler uses
isServerNotification/isProtocolResponse guards to dispatch messages.
Jérôme Benoit [Wed, 25 Mar 2026 21:20:43 +0000 (22:20 +0100)]
fix: post updated message on connectorStatusChanged to fix stale UI cache
The .finally() in internalSendMessage emits the updated event BEFORE
sendAndSetConnectorStatus updates connectorStatus.status, causing the
UI cache to snapshot the old status. The connectorStatusChanged event
fires AFTER the update, so posting an updated message on it ensures
the cache receives the correct connector status.
Jérôme Benoit [Tue, 24 Mar 2026 18:08:34 +0000 (19:08 +0100)]
fix: prevent shutdown timeout with promiseWithTimeout helper
Extract a shared promiseWithTimeout<T>() utility from 3 divergent
Promise.race+timeout implementations. Use it in ChargingStation.stop()
to cap stopMessageSequence at 30s so the stopped event is always
emitted even when the OCPP server is unreachable, preventing the
60s Bootstrap shutdown timeout.
Also fix mock server SecurityEventNotification handler parameter name
and add OCPP 2.0.1 E2E test plan.
Jérôme Benoit [Tue, 24 Mar 2026 16:54:43 +0000 (17:54 +0100)]
docs: harmonize JSDoc @param/@returns across entire codebase
- Add missing dash separator to @param tags in OCPP20VariableRegistry
and OCPPServiceUtils (35 occurrences)
- Fill empty @param descriptions in Helpers, IdTagsCache,
OCPPRequestService, and Worker modules (23 occurrences)
- Replace type-only @returns with meaningful descriptions
Jérôme Benoit [Tue, 24 Mar 2026 16:45:25 +0000 (17:45 +0100)]
docs: add JSDoc to ChargingStation public API methods
Add concise JSDoc with @param and @returns tags to 29 public methods
following the project's established pattern (param - description).
Resolves all 45 jsdoc/require-param and jsdoc/require-returns warnings.
- Replace throw new Error with BaseError in OCPP20CertificateManager and
OCPP20VariableManager (3 occurrences)
- Move getMessageTypeString from OCPPServiceUtils to Helpers, resolving
the barrel bypass in ErrorUtils — consumers import via charging-station
barrel, tests moved to Helpers.test.ts
- Remove redundant console.warn in Helpers (logger.warn already called)
- Remove unused chalk import from Helpers
- Replace 71 improper assert.ok(comparison) with assert.strictEqual/notStrictEqual
in 10 test files per TEST_STYLE_GUIDE (assert.ok for boolean/existence only)
- Rename lastUpdated → lastUpdatedDate in auth interfaces and strategies
to follow Date suffix naming convention
- Extract hardcoded 'ws://localhost' to OCPP20Constants.DEFAULT_CONNECTION_URL
- Replace setTimeout(resolve, 50) with proper httpServer.close() await
in UIMCPServer integration test
Jérôme Benoit [Tue, 24 Mar 2026 11:47:53 +0000 (12:47 +0100)]
fix(webui): remove deprecated baseUrl for TypeScript 6 compatibility
TS6 deprecated baseUrl (TS5101). Since paths entries already use './'
prefix, they work standalone without baseUrl. Vite resolve.alias handles
runtime resolution independently.
Jérôme Benoit [Tue, 24 Mar 2026 11:07:03 +0000 (12:07 +0100)]
refactor(ocpp-server): harmonize shutdown tests with project conventions
Move fixture near other fixtures, replace _patch_main tuple return with
contextmanager, parametrize SIGINT/SIGTERM, remove dead code helpers,
merge two test classes into one.
Jérôme Benoit [Tue, 24 Mar 2026 10:44:28 +0000 (11:44 +0100)]
feat(ocpp-server): add graceful shutdown with signal handling
Handle SIGINT/SIGTERM for clean WebSocket close (code 1001) to all
connected charge points. Includes shutdown drain timeout, double-signal
force quit, and cross-platform Windows fallback via call_soon_threadsafe.
Verify that every broadcast channel OCPP command has a corresponding
MCP tool schema and OCPP schema mapping entry. Ensures schema coverage
stays in sync with supported commands as a single source of truth guard.
Jérôme Benoit [Tue, 24 Mar 2026 00:43:04 +0000 (01:43 +0100)]
refactor(broadcast-channel): extract response status registries from switch/case
Replace 11 repetitive switch/case blocks in commandResponseToResponseStatus
with two static registries:
- emptyResponseCommands: Set of commands where empty response = success
- acceptedStatusCommands: Map of commands to status check predicates
Custom cases (AUTHORIZE, START/STOP_TRANSACTION, HEARTBEAT,
TRANSACTION_EVENT) remain in switch for version-specific logic.
Adding a new command now requires 1 line in the registry instead of
a 5-line case block.
Replace 20 identical BroadcastChannel handler methods (handleAuthorize,
handleDataTransfer, handleHeartbeat, handleStatusNotification, etc.)
with a single passthrough(RequestCommand) factory method that creates
a CommandHandler forwarding the request payload to requestHandler.
Retain only handlers with custom logic: handleBootNotification (merges
bootNotificationRequest), handleMeterValues (version-specific meter
value building), handleStopTransaction (adds meterStop).