refactor: use string/array helper functions consistently
Replace 9 manual .trim().length checks with isEmpty() and
isNotEmptyString() helpers. Replace Array.isArray+length
guards with isNotEmptyArray() in StatisticUtils. Simplify
isValidIdentifierValue to delegate to isNotEmptyString.
Replace hardcoded SecurityCtrlr.OrganizationName string
with OCPP20ComponentName/RequiredVariableName enums.
refactor: use utility helpers consistently across codebase
Replace manual * 1000 with secondsToMilliseconds() in auth
cache, remote strategy, and OCPP20 incoming request. Replace
manual / 1000 with millisecondsToSeconds() in auth helpers,
auth service, and cert signing retry. Replace 'in' operator
with has() in auth service. Replace configurationKey find
with getConfigurationKey() in OCPP20RequestService. Use
formatDurationMilliSeconds for reconnect delay log. Keep
ms precision in auth service logs (sub-second durations).
refactor(webui): remove redundant CSTable re-mount on toggle
The @clicked handler on the Add Charging Stations toggle
forced a CSTable re-mount on every click. This is unnecessary
since watch($chargingStations) already handles re-renders
when data changes via WS server notifications.
feat(webui): remove reload button (auto-refresh via WebSocket)
The WS server pushes refresh notifications on state changes,
making the manual reload button redundant. Remove ReloadButton
component, its styles, tests, and stub. Simplify need-refresh
handler to only reset add-stations toggle (data refresh and
CSTable re-render handled by server notification + watcher).
Remove dead --spacing-xl CSS variable from all themes.
refactor(webui): migrate globalProperties to provide/inject
Replace Vue 2-style app.config.globalProperties with Vue 3
provide/inject using typed InjectionKeys. Create useConfiguration
and useTemplates composables. Remove dead globalProperties
fallback paths and refreshChargingStations no-op. Update test
mounts to use provide. Clean ComponentCustomProperties from
shims-vue.d.ts.
refactor(webui): align $ prefix convention on composable locals
Rename uiClient to $uiClient in 4 components (convention:
composable-returned Vue service instances use $ prefix).
Rename ref to $chargingStations in Utils.ts (was shadowing
Vue ref import). Keep chargingStationsRef unchanged in
ChargingStationsView (would shadow globalProperty in template).
fix: restrict test coverage to src/ runtime code only
Add --test-coverage-include glob to exclude tests, scripts,
package.json and other non-runtime files from coverage report.
Aligns with web UI vitest coverage config pattern.
refactor(tests): migrate hardcoded test tags to shared constants
Replace 41 hardcoded tag/token strings across 13 test files
with imports from ChargingStationTestConstants. Includes
test utility factories. Normalize import paths to shortest
relative form and merge duplicate imports.
refactor(tests): use setupConnectorWithTransaction shared helper
Replace 19 inline transaction setup patterns across 3 test
files with the shared setupConnectorWithTransaction helper.
Only migrates sites where both transactionStarted and
transactionId are set together.
refactor(tests): migrate inline mock stations to shared factory
Replace inline as-unknown-as ChargingStation casts in
CertificateAuthStrategy and OCPP20AuthAdapter tests with
createMockAuthServiceTestStation factory. Add inAcceptedState
method to the shared auth test station factory.
refactor(tests): consolidate duplicate test helpers
Extract createStationWithRequestHandler to shared
TestLifecycleHelpers, eliminating duplication between
OCPPConnectorStatusOperations and OCPPServiceOperations tests.
Extend setupConnectorWithTransaction to support string
transactionId and pending mode, replacing local
setupTransaction/setupPendingTransaction helpers.
Add DisplayMessages, SupportedFormats, SupportedPriorities to
OCPP20VariableRegistry per OCPP 2.0.1 spec §3.1.8. Use
OCPP20MessageFormatEnumType for SupportedFormats enumeration.
Connector.ConnectorType deferred (requires isComponentValid
design change per OpenSpec process).
refactor(ocpp): consolidate payload validation into shared utility
Extract 4 near-identical validation methods into 1 shared
validatePayload function in OCPPServiceUtils. Each service
method becomes a thin wrapper delegating to the shared logic.
Preserves clone/date-conversion behavior per caller and
error message capitalization for OCPP protocol compliance.
refactor(ocpp): consolidate MeterValues validators and helpers
Replace 5 near-identical validators with 1 generic
validateMeasurandValue using options pattern for phase
and interval. Merge addLineToLineVoltageToMeterValue into
addPhaseVoltageToMeterValue with nominalVoltage and optional
noTemplateFallback params preserving voltage simulation
semantics. Inline dead getMeasurandDefaultContext and
getMeasurandDefault. Extract magic numbers as constants.
refactor(ocpp): consolidate variable access in auth adapter
Remove getVariableValue/getDefaultVariableValue wrappers from
OCPP20AuthAdapter in favor of OCPP20ServiceUtils.readVariableAs*
helpers. Fixes LocalAuthListCtrlr.Enabled default discrepancy
between adapter (true) and registry (false). Add readVariableAsString
helper for consistent string variable access.
Remove 19 unused re-exports from ocpp/index.ts (12) and
auth/index.ts (7). All consumers import directly from source
files. Convert OCPPIncomingRequestService and OCPPRequestService
to type-only exports matching their sole consumer.
refactor(ocpp): remove unnecessary exports from internal helpers
De-export 14 MeterValue helper functions in OCPPServiceUtils
that are now only used internally after builder consolidation.
Make readVariableAsIntervalMs private in OCPP20ServiceUtils.
refactor(ocpp): consolidate variable reading through shared helpers
Promote readVariableAs* helpers to public on OCPP20ServiceUtils.
Replace 10 inline getVariables + manual parsing patterns with
helper calls. Remove duplicated getVariableValue from
CertSigningRetryManager and parseBooleanVariable from
OCPP20AuthAdapter. Replace last parseInt with convertToIntOrNaN.
fix(ocpp): align OCPP 2.x auth adapter version to VERSION_201
OCPP20AuthAdapter was the only 2.x component identifying as
VERSION_20 while all services use VERSION_201. Align adapter
and CertificateAuthStrategy to match the established convention.
refactor(ocpp): consolidate MeterValue builders into shared core
Merge buildOCPP16MeterValue and buildOCPP20MeterValue into
buildMeterValue, eliminating ~250 lines of duplicated logic.
Version differences resolved via switch: evseId + sampled
value builder callback.
Harmonize MeterValues test structure between versions:
extract 1.6 tests to dedicated file, add cross-version
parameterized builder output tests, add missing 2.0
edge case and interval restart test coverage.
fix(ocpp): wire context param through OCPP 1.6 meter value builder
The context parameter was silently dropped during extraction
to OCPP16RequestBuilders, unlike the OCPP 2.0 version which
correctly passes it to all internal calls.
refactor: remove unnecessary type casts and improve type safety
- Remove redundant as any cast in __testable__/index.ts
- Rewrite isEmpty() with native type guards (typeof/instanceof)
- Replace parameter mutation with const in WorkerFactory
- Remove unnecessary cast in MessageChannelUtils
refactor(ocpp): complete version-separation in OCPPServiceUtils
Replace buildSampledValue version-switch with resolveSampledValueFields
helper + version-specific buildOCPP16SampledValue/buildOCPP20SampledValue.
Move mapStopReasonToOCPP20 to OCPP20RequestBuilders where it belongs.
OCPPServiceUtils.ts is now 100% version-agnostic — zero OCPP 1.6/2.0
types, zero inline version switches. All version-specific logic lives
in version-specific leaf modules (RequestBuilders, ServiceUtils).
test(ocpp): harmonize test constants and assertion messages
Replace hardcoded station IDs, tokens, and transaction IDs with
shared constants from ChargingStationTestConstants.ts across 8 test
files. Add TEST_TRANSACTION_UUID constant. Add descriptive messages
to 55 assert.ok() numeric comparison calls across 20+ test files
per TEST_STYLE_GUIDE.md requirements.
refactor(ocpp): align builder naming and harmonize test structure
Rename buildMeterValueForOCPP16/20 and buildSampledValueForOCPP16/20
to buildOCPP16/20MeterValue and buildOCPP16/20SampledValue matching
the established buildOCPP{version}{Thing} convention.
Merge IdTagAuthorization.test.ts into OCPPServiceOperations.test.ts
(source file was deleted). Move buildBootNotificationRequest tests
from OCPPServiceOperations.test.ts to OCPPServiceUtils-pure.test.ts
(function was moved to Utils).
refactor(ocpp): consolidate meter value builders into RequestBuilders
Merge OCPP16MeterValueBuilders.ts and OCPP20MeterValueBuilders.ts
into their respective OCPP16RequestBuilders.ts and OCPP20RequestBuilders.ts
files. Version-specific pure builders belong in a single leaf module
per stack, not separate files per builder type.
refactor(ocpp): extract version-specific builders and transaction operations
Extract meter value builders into OCPP16/20MeterValueBuilders.ts leaf
modules. Extract boot notification builders into OCPP16/20RequestBuilders.ts
leaf modules. Move buildBootNotificationRequest dispatcher from Operations
to Utils. Extract OCPP 2.0 startTransactionOnConnector and
stopTransactionOnConnector into OCPP20ServiceUtils, removing inline
OCPP 2.0 enums and logic from the shared Operations module.
refactor(ocpp): extract connector status operations into dedicated module
Move sendAndSetConnectorStatus, restoreConnectorStatus, and
checkConnectorStatusTransition into OCPPConnectorStatusOperations.ts
to enforce the operations/utils semantic separation without creating
circular dependencies. The new module depends only on Constants
(leaf modules), not on version-specific ServiceUtils.
refactor(ocpp): move isIdTagAuthorized into OCPPServiceOperations
The circular dependency that motivated the separate IdTagAuthorization
file no longer exists after auth module refactoring. Move the function
to OCPPServiceOperations alongside other cross-stack transaction
helpers and delete the standalone file.
Jérôme Benoit [Tue, 31 Mar 2026 23:32:29 +0000 (01:32 +0200)]
refactor(ocpp): consolidate Ajv type alias in OCPPServiceUtils
Export the Ajv type alias from OCPPServiceUtils and import it in
OCPPIncomingRequestService, OCPPRequestService, and OCPPResponseService
instead of each file duplicating the _Ajv.default type extraction.
Jérôme Benoit [Tue, 31 Mar 2026 23:15:35 +0000 (01:15 +0200)]
refactor: move constants to domain-appropriate locations
Move UNKNOWN_OCPP_COMMAND to OCPPConstants (cross-OCPP), DEFAULT_IDTAG
to OCPP16Constants (OCPP 1.6 only), OCPP_VALUE_ABSOLUTE_MAX_LENGTH to
OCPP20Constants renamed as MAX_VARIABLE_VALUE_LENGTH (OCPP 2.0 only).
Extract magic numbers: SECURITY_EVENT_RETRY_DELAY_MS in OCPP20Constants,
CLIENT_NOTIFICATION_DEBOUNCE_MS in AbstractUIServer,
DEFAULT_WS_RECONNECT_TIMEOUT_OFFSET in Constants.
Jérôme Benoit [Tue, 31 Mar 2026 22:34:20 +0000 (00:34 +0200)]
refactor(log): quote and truncate all auth identifiers in log messages
Wrap all idTag/idToken/identifier values in single quotes and apply
truncateId() consistently across OCPP 1.6, 2.0, and auth module log
messages. Removes eslint-disable comments for restrict-template-expressions
where ?? '' fallback eliminates the type issue.
Jérôme Benoit [Tue, 31 Mar 2026 22:03:59 +0000 (00:03 +0200)]
fix(ocpp): warn on OCPP 1.6 keys in template only, silent remap for internal code
Simplify OCPP2_PARAMETER_KEY_MAP to a plain Map<string, string> and
make resolveKey always silent. Move warning to a one-shot template
validation pass (warnOnOCPP16TemplateKeys) called after template
loading, before init defaults. Warnings now only fire when the
operator uses OCPP 1.6 key names in an OCPP 2.0 station template,
not when internal cross-version code resolves keys.
Jérôme Benoit [Tue, 31 Mar 2026 21:26:14 +0000 (23:26 +0200)]
refactor(auth): remove getAuthCache from interfaces, own cache in service
Remove getAuthCache() from AuthStrategy and OCPPAuthService interfaces.
Store authCache directly as private field on OCPPAuthServiceImpl during
initializeStrategies(), eliminating indirect access through LocalAuthStrategy
for clearCache, invalidateCache, and updateCacheEntry operations.
Add getTestAuthCache() helper to MockFactories to encapsulate cache
access in tests. Harmonize all test files to use the shared helper
instead of ad-hoc cast chains. Fix broken OCPPAuthIntegrationTest
references and extract KNOWN_STRATEGIES constant.
Jérôme Benoit [Tue, 31 Mar 2026 20:32:02 +0000 (22:32 +0200)]
fix(auth): trigger post-authorize by default when DisablePostAuthorize not configured
Change shouldTriggerPostAuthorize from === false to !== true so that
non-Accepted local/cached tokens correctly trigger remote re-auth
when disablePostAuthorize is undefined (not configured). Previously,
undefined === false evaluated to false, silently skipping re-auth.
Also flatten redundant double try/catch in OCPP20AuthAdapter.
Jérôme Benoit [Tue, 31 Mar 2026 20:06:21 +0000 (22:06 +0200)]
refactor(auth): make updateCacheEntry API OCPP version-agnostic
Decouple updateCacheEntry from OCPP 2.0-specific types by accepting
AuthorizationStatus and optional expiryDate instead of pre-built
AuthorizationResult and TTL. This centralizes result construction,
date conversion, TTL computation, and expired-entry guards in the
auth service, eliminating duplicated logic across OCPP 1.6 and 2.0
callers. Also change OCPPAuthAdapter generic default from
OCPP20IdTokenType|string to unknown to remove the last OCPP
version-specific type from the auth service interface.
Jérôme Benoit [Tue, 31 Mar 2026 18:51:32 +0000 (20:51 +0200)]
fix(ocpp): correct P0/P1 spec conformity gaps for OCPP 1.6 and 2.0.1
Addresses 7 non-conformities identified during algorithmic conformity audit:
P0 - OCPP-J protocol layer:
- Add MessageTypeNotSupported and RpcFrameworkError error codes (2.0.1 §4.3)
- Send CALLERROR with messageId "-1" on JSON parse failure (2.0.1 §4.2.3)
- Implement RetryBackOff reconnection algorithm using spec variables (2.0.1 §8.1-§8.3)
P1 - OCPP 1.6 logic fixes:
- Update authorization cache on Authorize/Start/StopTransaction responses
- Fix clearChargingProfiles to use AND logic per Errata 3.25
Infrastructure:
- Consolidate exponential backoff into computeExponentialBackOffDelay()
- Replace string literals with OCPP20OptionalVariableName enum entries
- Export OCPP16IdTagInfo type, make getAuthCache() non-optional on AuthStrategy
- Factor updateAuthorizationCache() into ServiceUtils for both 1.6 and 2.0
Jérôme Benoit [Tue, 31 Mar 2026 14:41:58 +0000 (16:41 +0200)]
refactor: reduce code duplication across OCPP services, UI server, and configuration
- Centralize AJV instantiation into createAjv() factory in OCPPServiceUtils
- Centralize payload validator config creation into createPayloadConfigs() generic
factory, simplifying OCPP16/20ServiceUtils from multi-line .map() to one-liners
- Move rate limiter creation from module-level duplicates in UIHttpServer and
UIMCPServer to a shared instance property on AbstractUIServer
- Extract 200-line checkDeprecatedConfigurationKeys() and helpers from
Configuration.ts into dedicated ConfigurationMigration.ts module
Jérôme Benoit [Tue, 31 Mar 2026 00:30:22 +0000 (02:30 +0200)]
refactor(ocpp): extract version-specific logic from consumer layer
Move remaining version-specific logic from charging-station/ consumer
layer into the ocpp/ component:
- Create OCPPServiceFactory.ts with createOCPPServices() factory that
instantiates version-specific OCPP services, removing 6 version-
specific class imports from ChargingStation.ts
- Move createBootNotificationRequest from Helpers.ts into version-
specific buildBootNotificationRequest methods in OCPP16ServiceUtils
and OCPP20ServiceUtils, with dispatcher in OCPPServiceOperations.ts
ChargingStation.ts no longer has any direct knowledge of OCPP version-
specific service classes. All version dispatch is handled by the ocpp/
component through factories and dispatchers.
Add unit tests for createOCPPServices (4 tests) and
buildBootNotificationRequest (6 tests) in existing test files.
Jérôme Benoit [Mon, 30 Mar 2026 23:03:46 +0000 (01:03 +0200)]
docs: fix JSDoc using historical language instead of current-state descriptions
Replace history-telling patterns ('previously', 'no longer valid',
'unused but required by interface', 'kept for API consistency') with
descriptions of current behavior.
Jérôme Benoit [Mon, 30 Mar 2026 22:59:34 +0000 (00:59 +0200)]
fix(auth): remove unnecessary async from sync interface methods
isRemoteAvailable() was declared as boolean | Promise<boolean> in the
OCPPAuthAdapter interface while both implementations return boolean
synchronously. This forced unnecessary await, Promise.resolve() wrappers,
and async propagation through the call chain.
Fix the interface to boolean and cascade through:
- RemoteAuthStrategy: getStats(), testConnectivity(), checkRemoteAvailability()
become synchronous
- AuthStrategy.getStats(): JsonObject | Promise<JsonObject> becomes JsonObject
- OCPPAuthService.getStats(): Promise<AuthStats> becomes AuthStats
- OCPPAuthServiceImpl.getStats() becomes synchronous
Jérôme Benoit [Mon, 30 Mar 2026 22:44:20 +0000 (00:44 +0200)]
refactor(ocpp): enforce strict version separation in OCPPServiceUtils
Extract version-specific logic from cross-version utilities:
- P1: Move buildStatusNotificationRequest into OCPP16ServiceUtils and
OCPP20ServiceUtils as version-specific static methods
- P2: Move buildTransactionEndMeterValue to OCPP16ServiceUtils, remove
dead OCPP 2.0 branch that was never called
- P3: Split buildMeterValue into thin dispatcher plus dedicated
buildMeterValueForOCPP16/buildMeterValueForOCPP20 internal functions
- P4: Simplify checkConnectorStatusTransition to select transition
tables by version then apply single shared lookup logic
Harmonize tests to match new module structure:
- Rename OCPPServiceUtils-StopTransaction.test.ts to
OCPPServiceOperations.test.ts (functions moved to that module)
- Move mapStopReasonToOCPP20 tests to OCPPServiceUtils-pure.test.ts
(function still lives in OCPPServiceUtils)
- Add dedicated unit tests for buildStatusNotificationRequest in both
OCPP16ServiceUtils.test.ts and new OCPP20ServiceUtils-StatusNotification.test.ts
- Fix redundant describe nesting in OCPP20 test file
Jérôme Benoit [Mon, 30 Mar 2026 21:45:32 +0000 (23:45 +0200)]
refactor(ocpp): dissolve OCPPServiceUtils class and eliminate dynamic imports
Dissolve the OCPPServiceUtils class into standalone exported functions,
removing the class hierarchy (extends) from OCPP16/20ServiceUtils.
Extract 6 version-dispatching operations into OCPPServiceOperations.ts
with static top-level imports, eliminating all 11 dynamic await import()
calls that were used to work around circular dependencies.
The dependency graph is now a clean DAG:
OCPPServiceUtils.ts (pure utilities, no version knowledge of subclasses)
OCPP16/20ServiceUtils.ts (version-specific, import utils directly)
OCPPServiceOperations.ts (dispatchers, static imports of both)
Cross-component imports now go through barrel files per project conventions.
JSDoc harmonized across all modified files.
Jérôme Benoit [Mon, 30 Mar 2026 20:33:31 +0000 (22:33 +0200)]
refactor(ocpp): remove static alias forwarding from OCPPServiceUtils class
Replace OCPPServiceUtils static property aliases with direct function
imports. All 7 aliases (buildTransactionEndMeterValue, mapStopReasonToOCPP20,
restoreConnectorStatus, sendAndSetConnectorStatus, stopRunningTransactions,
buildSampledValue, getSampledValueTemplate) were trivial forwarding to
standalone functions already defined in the same file.
Consumers now import these functions directly, reducing indirection and
moving toward dissolving the extraneous utility class.
* fix(ocpp): preserve OCPP 2.0 token type in authorizeToken per C01.FR.25
authorizeToken was hardcoding IdentifierType.ID_TAG, causing all
Authorize.req to carry type 'Local' regardless of the actual token
type (ISO14443, eMAID, etc.). Pass the OCPP 2.0 token type through
and use mapOCPP20TokenType for proper mapping.
Also fix log message attribution and deduplicate OCPPAuthServiceFactory
from the dynamic import (already available via static import).
* refactor(ocpp): eliminate unnecessary dynamic imports and synchronize auth factory
Extract isIdTagAuthorized to IdTagAuthorization.ts to break the
OCPPServiceUtils ESM evaluation cycle, enabling static imports from
the auth barrel. Convert AuthComponentFactory, OCPPAuthServiceFactory,
and OCPPAuthServiceImpl to fully synchronous APIs. Remove the
globalThis Symbol hack that was needed for cross-module-instance
sharing. Move getMessageTypeString to utils/Utils.ts where it belongs.
- 9 dynamic imports eliminated (20 → 11, remaining are inheritance cycles)
- Auth factory chain fully sync (getInstance, createAdapter, initialize)
- IdTagAuthorization.ts imports auth/index.js barrel statically
- Tests relocated to follow moved code
- All barrel exports consolidated between components
* build: add skott for type-aware circular dependency detection
Add skott as devDependency with a circular-deps script that scans
the entire src/ directory using --no-trackTypeOnlyDependencies to
ignore import type (unlike madge which reports false positives).
Exit code 0 for now since known cycles exist — switch to 1 when
integrated in CI.
* build: override effect>=3.20.0 to fix CVE-2026-32887 (skott transitive dep)
* refactor: break UI server circular dependency via IBootstrap DIP
Introduce IBootstrap interface to decouple AbstractUIService from the
Bootstrap singleton import. Bootstrap implements IBootstrap and is
injected through the UIServerFactory → AbstractUIServer → UIService
chain. This structurally eliminates the cycle:
AbstractUIServer → UIServiceFactory → AbstractUIService → Bootstrap →
UIServerFactory → UIHttpServer → extends AbstractUIServer.
Also removes the cross-component re-export workaround in
charging-station/index.ts (getMessageTypeString from utils/) that
was only needed to preserve ESM evaluation order around this cycle.
- Circular dependency paths: 177 → 39 (type-aware, skott)
- Short cycles (depth ≤ 4): 7 → 4
- ErrorUtils now imports getMessageTypeString from its own component
* test: fix mock isolation and type safety in UI server tests
Move mockBootstrap to beforeEach for per-test isolation.
Remove as-never cast by providing all SimulatorState fields.
Remove unnecessary JSDoc on self-documenting mock factory.
* fix: align auth barrel section headers with exports, use barrel for CertificateAuthStrategy import
* refactor(auth): eliminate code duplication, dead code, and type casts
- DRY: Replace duplicated mappers in OCPP20AuthAdapter with shared
mapToOCPP20TokenType/mapOCPP20TokenType from AuthTypes
- DRY: Extract duplicated enhanceResult from Local/Remote strategies
into shared enhanceAuthResult in AuthTypes
- Dead code: Remove unused parseIntegerVariable from OCPP20AuthAdapter
- YAGNI: Remove unused AuthHelpers from barrel export
- Type safety: Add getAuthCache() to AuthStrategy interface, eliminating
3 concrete as-LocalAuthStrategy casts in OCPPAuthServiceImpl
* fix(auth): preserve OCPP 2.0 Central/Local token type in adapter mapping
Remove post-processing that collapsed Central/Local to ID_TAG in
OCPP20AuthAdapter.convertToIdentifier. The shared mapOCPP20TokenType
correctly returns CENTRAL/LOCAL, which downstream code uses for spec
compliance (C03.FR.01 skip Authorize.req for Central tokens, C11
cache exclusion for Central identifiers).
Jérôme Benoit [Sun, 29 Mar 2026 10:56:29 +0000 (12:56 +0200)]
refactor: simplify getNumberOfReservableConnectors using iterateConnectors
Replace standalone getNumberOfReservableConnectors helper with inline
iterateConnectors(true).reduce(), matching the pattern already used by
getNumberOfConnectors and getNumberOfRunningTransactions. Remove the
now-unused helper from Helpers.ts.
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.