]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/log
e-mobility-charging-stations-simulator.git
8 days agochore: remove accidentally committed test plan
Jérôme Benoit [Tue, 31 Mar 2026 21:27:43 +0000 (23:27 +0200)] 
chore: remove accidentally committed test plan

8 days agorefactor(auth): remove getAuthCache from interfaces, own cache in service
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.

8 days agofix(auth): trigger post-authorize by default when DisablePostAuthorize not configured
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.

8 days agorefactor: merge duplicate same-kind imports from identical sources
Jérôme Benoit [Tue, 31 Mar 2026 20:20:00 +0000 (22:20 +0200)] 
refactor: merge duplicate same-kind imports from identical sources

8 days agofix(auth): use Math.floor for TTL computation to avoid serving expired cache entries
Jérôme Benoit [Tue, 31 Mar 2026 20:14:39 +0000 (22:14 +0200)] 
fix(auth): use Math.floor for TTL computation to avoid serving expired cache entries

8 days agorefactor(auth): rename parsed to expiry in updateCacheEntry
Jérôme Benoit [Tue, 31 Mar 2026 20:09:33 +0000 (22:09 +0200)] 
refactor(auth): rename parsed to expiry in updateCacheEntry

8 days agorefactor(auth): make updateCacheEntry API OCPP version-agnostic
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.

8 days agotest(ocpp): strengthen mock call verification in OCPP 2.0 handler tests
Jérôme Benoit [Tue, 31 Mar 2026 19:26:36 +0000 (21:26 +0200)] 
test(ocpp): strengthen mock call verification in OCPP 2.0 handler tests

Replace loose assertions (assert.ok(>0), boolean flags) with strict
mock.fn() callCount() and argument verification across 4 test files:

- UnlockConnector: verify exact call count + STATUS_NOTIFICATION command
- ClearCache: replace 3 boolean flags with mock.fn() + callCount()
- CertificateSigned: verify closeWSConnection called/not-called per cert type
- ChangeAvailability: capture requestHandler via factory, verify side effects

8 days agofix(ocpp): correct P0/P1 spec conformity gaps for OCPP 1.6 and 2.0.1
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

P1 - OCPP 2.0.1 security lifecycle:
- Add certificate signing retry with exponential back-off (A02.FR.17-19)
- Add security event notification queue with guaranteed delivery (A04.FR.02)
- Update authorization cache on AuthorizeResponse (C10.FR.04)

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

8 days agochore(deps): lock file maintenance (#1765)
renovate[bot] [Tue, 31 Mar 2026 15:07:37 +0000 (17:07 +0200)] 
chore(deps): lock file maintenance (#1765)

* chore(deps): lock file maintenance

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
8 days agorefactor: reduce code duplication across OCPP services, UI server, and configuration
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

8 days agofix(deps): update all non-major dependencies (#1766)
renovate[bot] [Tue, 31 Mar 2026 13:46:49 +0000 (15:46 +0200)] 
fix(deps): update all non-major dependencies (#1766)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
8 days agorefactor(ocpp): extract version-specific logic from consumer layer
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.

9 days agodocs: fix JSDoc using historical language instead of current-state descriptions
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.

9 days agofix(auth): remove unnecessary async from sync interface methods
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

Update mocks and tests to match sync signatures.

9 days agorefactor(ocpp): enforce strict version separation in OCPPServiceUtils
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

9 days agorefactor(ocpp): dissolve OCPPServiceUtils class and eliminate dynamic imports
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.

9 days agorefactor(ocpp): remove static alias forwarding from OCPPServiceUtils class
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.

9 days agorefactor(ocpp): integrate unified auth as sole authorization mechanism (#1764)
Jérôme Benoit [Mon, 30 Mar 2026 20:02:25 +0000 (22:02 +0200)] 
refactor(ocpp): integrate unified auth as sole authorization mechanism (#1764)

* refactor(ocpp): route v1.6 auth through unified system, remove legacy functions

* refactor(ocpp): replace OCPP 2.0 inline auth with unified auth service

* test(ocpp): update OCPP 1.6 authorization tests for unified auth path

* test(ocpp): add OCPP 2.0 unified auth integration tests

* chore: pass all quality gates

* [autofix.ci] apply automated fixes

* refactor(ocpp): pass correct AuthContext to isIdTagAuthorized callers

REMOTE_START for RemoteStartTransaction, RESERVATION for ReserveNow.
ATG keeps the default TRANSACTION_START.

* refactor(ocpp): use auth barrel index instead of deep imports

* refactor(ocpp): use auth barrel for all external imports

* refactor(ocpp): remove redundant 'unified' naming from auth system

* refactor(ocpp): extract authorizeToken helper and fix rejection test assertions

* test(ocpp): add coverage for auth error and context parameter paths

* test(ocpp): remove redundant tests and unnecessary JSDoc from authorization tests

* refactor(ocpp): address review feedback — explicit switch cases, parameterize context, merge imports

* 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).

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
9 days agofix: add Vue LSP settings and disable Biome in Zed project config
Jérôme Benoit [Mon, 30 Mar 2026 02:47:08 +0000 (04:47 +0200)] 
fix: add Vue LSP settings and disable Biome in Zed project config

9 days agofeat: add Zed project settings
Jérôme Benoit [Mon, 30 Mar 2026 01:16:58 +0000 (03:16 +0200)] 
feat: add Zed project settings

10 days agodocs: fix broken MCP specification URL in README
Jérôme Benoit [Sun, 29 Mar 2026 23:29:00 +0000 (01:29 +0200)] 
docs: fix broken MCP specification URL in README

10 days agochore: release main (#1762) ocpp-server@v4.0.3 simulator@v4.0.3 v4.0 webui@v4.0.3
Jérôme Benoit [Sun, 29 Mar 2026 11:14:57 +0000 (13:14 +0200)] 
chore: release main (#1762)

* chore: release main

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
10 days agorefactor: simplify getNumberOfReservableConnectors using iterateConnectors
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.

10 days agostyle: normalize blank line spacing in Constants.ts
Jérôme Benoit [Sun, 29 Mar 2026 01:28:18 +0000 (03:28 +0200)] 
style: normalize blank line spacing in Constants.ts

10 days agochore: release main (#1761) ocpp-server@v4.0.2 simulator@v4.0.2 webui@v4.0.2
Jérôme Benoit [Sun, 29 Mar 2026 01:09:06 +0000 (03:09 +0200)] 
chore: release main (#1761)

* chore: release main

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
10 days agofix: harmonize idToken type to ISO14443 between Authorize and TransactionEvent Started
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.

10 days agochore: release main (#1760) ocpp-server@v4.0.1 simulator@v4.0.1 webui@v4.0.1
Jérôme Benoit [Sun, 29 Mar 2026 00:53:58 +0000 (01:53 +0100)] 
chore: release main (#1760)

* chore: release main

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
10 days agofix: improve OCPP 2.0.1 TransactionEvent spec compliance
Jérôme Benoit [Sun, 29 Mar 2026 00:45:59 +0000 (01:45 +0100)] 
fix: improve OCPP 2.0.1 TransactionEvent spec compliance

- 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

11 days agochore: release main (#1758) ocpp-server@v4.0.0 simulator@v4.0.0 webui@v4.0.0
Jérôme Benoit [Sat, 28 Mar 2026 23:31:23 +0000 (00:31 +0100)] 
chore: release main (#1758)

* chore: release main

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
11 days agochore(deps): lock file maintenance
Jérôme Benoit [Sat, 28 Mar 2026 23:20:46 +0000 (00:20 +0100)] 
chore(deps): lock file maintenance

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
11 days agorefactor: harmonize connector iteration to use iterateConnectors() across prod and...
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

11 days agorefactor: encapsulate connector/EVSE iteration behind generator API
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.

11 days agochore(webui): update screenshot
Jérôme Benoit [Sat, 28 Mar 2026 17:12:20 +0000 (18:12 +0100)] 
chore(webui): update screenshot

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
11 days agotest: isolate readCombinedLog tests from real logs directory
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.

11 days agotest: add symmetric Ended meter value tests for start/stop/zero-interval
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.

11 days agofeat: implement TxEnded meter value accumulator per OCPP 2.0.1 spec §2.1
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

11 days agostyle: apply prettier formatting to test files
Jérôme Benoit [Sat, 28 Mar 2026 14:45:15 +0000 (15:45 +0100)] 
style: apply prettier formatting to test files

Reformatting applied by lint-staged hooks during previous commits.
No behavioral changes.

11 days agofix: align ConnectionTimeOut semantics with OCPP spec
Jérôme Benoit [Sat, 28 Mar 2026 14:36:18 +0000 (15:36 +0100)] 
fix: align ConnectionTimeOut semantics with OCPP spec

ConnectionTimeOut/EVConnectionTimeOut is the EV cable insertion timeout
per OCPP 1.6 §9.1.6 and OCPP 2.0.1 TxCtrlr spec, not a WebSocket
timeout. Split DEFAULT_CONNECTION_TIMEOUT into three purpose-specific
constants:
- DEFAULT_EV_CONNECTION_TIMEOUT (180s): OCPP cable insertion timeout
- DEFAULT_WS_HANDSHAKE_TIMEOUT (30s): WebSocket handshake timeout
- DEFAULT_WS_RECONNECT_DELAY (30s): WebSocket reconnection delay
- DEFAULT_MESSAGE_TIMEOUT (30s): OCPP 2.0 MessageTimeout default

Dissociate WebSocket handshake/reconnect from OCPP ConnectionTimeOut
configuration. Initialize ConnectionTimeOut with 180s per spec.

11 days agorefactor: move ConfigurationValueSize, ReportingValueSize, ValueSize to OCPP20Optiona...
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.

11 days agorefactor: add SimulateSignatureVerificationFailure to OCPP20VendorVariableName enum
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.

11 days agorefactor: use OCPP20RequiredVariableName for measurands in OCPP20ServiceUtils
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.

11 days agorefactor: move debug param to last position in buildMeterValue
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.

11 days agorefactor: replace Measurands string literal with OCPP20RequiredVariableName enum
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.

11 days agofix: correct WebSocketPingInterval documentation and registry default
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

11 days agofix: map WebSocketPingInterval to OCPPCommCtrlr per OCPP 2.0.1 spec
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.

11 days agotest: add whitespace-padded value coverage for convertToBoolean
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.

11 days agotest: restore and harmonize OCPP 2.0 transaction meter value assertions
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

12 days agofeat: support configurable measurands per transaction stage in OCPP 2.0
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

12 days agorefactor: extract normalized boolean variable in validation checks
Jérôme Benoit [Fri, 27 Mar 2026 21:50:32 +0000 (22:50 +0100)] 
refactor: extract normalized boolean variable in validation checks

12 days agofix: use case-insensitive boolean parsing for OCPP configuration 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

12 days agorefactor: harmonize errMsg → errorMsg for intra-file naming consistency
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.

12 days agochore: untrack accidentally committed test plan file
Jérôme Benoit [Fri, 27 Mar 2026 20:16:16 +0000 (21:16 +0100)] 
chore: untrack accidentally committed test plan file

12 days agorefactor: align variable naming and remove non-null assertions in tests and UI
Jérôme Benoit [Fri, 27 Mar 2026 20:15:44 +0000 (21:15 +0100)] 
refactor: align variable naming and remove non-null assertions in tests and UI

Apply the same naming conventions established in src/ to tests/ and ui/:
- connector → connectorStatus for ConnectorStatus values (48 instances)
- Stats → Statistics: heartbeatStats, authStats, rateLimitStats (3)
- Config → Configuration: atgConfig, originalConfig, updatedConfig,
  singleServerConfig, multiServerConfig (7)
- Remove 11 eslint-disable no-non-null-assertion suppressions in
  tests/ and ui/web/src/ with proper null guards

12 days agorefactor: align intermediate variable naming with codebase conventions
Jérôme Benoit [Fri, 27 Mar 2026 19:54:42 +0000 (20:54 +0100)] 
refactor: align intermediate variable naming with codebase conventions

Systematic rename of 24 variables to follow established patterns:
- connector → connectorStatus for ConnectorStatus values (8 decls + params)
- Stats → Statistics: workerScriptStats, strategyStats, cacheStats (5)
- Config → Configuration: newConfig, authConfig, logConfig, configData (7)
- entry → descriptive names: ipRateLimitEntry, authCacheEntry,
  rateLimitEntry, variableGroupEntry, pairedBoundsEntry (6)
- Fix variable shadowing in OCPP20ServiceUtils.startPeriodicMeterValues
  by naming outer setup variable initialConnectorStatus

12 days agodocs: align README OCPP 2.0.1 variable list with code registry
Jérôme Benoit [Fri, 27 Mar 2026 19:31:05 +0000 (20:31 +0100)] 
docs: align README OCPP 2.0.1 variable list with code registry

- Rename LocalAuthorizeOffline → LocalAuthorizationOffline and
  LocalPreAuthorize → LocalPreAuthorization to match code enum names
- Remove commented-out OrganizationName from ISO15118Ctrlr
- Add 7 implemented variables missing from documentation:
  AlignedDataCtrlr/TxEndedMeasurands, AuthCacheCtrlr/Storage,
  EVSE/Power, LocalAuthListCtrlr/Storage,
  SampledDataCtrlr/TxEndedMeasurands, SampledDataCtrlr/TxUpdatedMeasurands,
  SmartChargingCtrlr/RateUnit

12 days agochore: remove accidentally tracked test plan file
Jérôme Benoit [Fri, 27 Mar 2026 19:15:49 +0000 (20:15 +0100)] 
chore: remove accidentally tracked test plan file

12 days agorefactor: use Number.isNaN() instead of global isNaN()
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.

12 days agofix: replace incorrect zero fallbacks for maximumPower and maximumAmperage
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.

Replace with proper null guards that log errors and fail-open:
- getConnectorMaximumAvailablePower: return Infinity (no limit known)
- getMaximumAmperage: return undefined (caller already handles it)
- initializeOcppConfiguration: skip config key, log error
- getChargingStationChargingProfilesLimit: return limit uncapped
- getConnectorChargingProfilesLimit: return limit uncapped

12 days agorefactor: eliminate all non-null assertion suppressions with proper null guards
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)

12 days agorefactor: deduplicate imports
Jérôme Benoit [Fri, 27 Mar 2026 16:44:08 +0000 (17:44 +0100)] 
refactor: deduplicate imports

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
12 days agorefactor: use `OCPP20MessageFormatEnumType` instead of string literal union
Jérôme Benoit [Fri, 27 Mar 2026 16:43:03 +0000 (17:43 +0100)] 
refactor: use `OCPP20MessageFormatEnumType` instead of string literal union

12 days agofix(deps): add security overrides for brace-expansion, picomatch, smol-toml
Jérôme Benoit [Fri, 27 Mar 2026 16:32:44 +0000 (17:32 +0100)] 
fix(deps): add security overrides for brace-expansion, picomatch, smol-toml

12 days agorefactor: make `eventType` required in `OCPP20TransactionEventOptions`
Jérôme Benoit [Fri, 27 Mar 2026 16:31:41 +0000 (17:31 +0100)] 
refactor: make `eventType` required in `OCPP20TransactionEventOptions`

12 days agochore: lock file maintenance
Jérôme Benoit [Fri, 27 Mar 2026 16:13:19 +0000 (17:13 +0100)] 
chore: lock file maintenance

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
12 days agorefactor: use `JsonObject` and generic `OCPPAuthAdapter<TVersionId>` in auth module
Jérôme Benoit [Fri, 27 Mar 2026 16:07:17 +0000 (17:07 +0100)] 
refactor: use `JsonObject` and generic `OCPPAuthAdapter<TVersionId>` in auth module

12 days agorefactor: type deprecated config key maps with `keyof` to eliminate 4 casts
Jérôme Benoit [Fri, 27 Mar 2026 15:28:26 +0000 (16:28 +0100)] 
refactor: type deprecated config key maps with `keyof` to eliminate 4 casts

12 days agorefactor: centralize handler type bridges in OCPP base classes
Jérôme Benoit [Fri, 27 Mar 2026 15:18:10 +0000 (16:18 +0100)] 
refactor: centralize handler type bridges in OCPP base classes

12 days agorefactor: eliminate explicit `any` from `once()` and `toHandler()` with proper generics
Jérôme Benoit [Fri, 27 Mar 2026 14:56:48 +0000 (15:56 +0100)] 
refactor: eliminate explicit `any` from `once()` and `toHandler()` with proper generics

12 days agorefactor: type buildTransactionEvent with OCPP20TransactionEventOptions
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.

12 days agorefactor: accept enum types in registry/manager signatures, remove 429 redundant...
Jérôme Benoit [Fri, 27 Mar 2026 13:39:32 +0000 (14:39 +0100)] 
refactor: accept enum types in registry/manager signatures, remove 429 redundant as-string casts

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.

12 days agofix(deps): update all non-major dependencies (#1759)
renovate[bot] [Fri, 27 Mar 2026 13:26:42 +0000 (14:26 +0100)] 
fix(deps): update all non-major dependencies (#1759)

* fix(deps): update all non-major dependencies

* [autofix.ci] apply automated fixes

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
12 days agorefactor: consolidate enforceMessageLimits types with generic R and RejectionReason
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

12 days agofix: type buildRejected reasonCode as ReasonCodeEnumType instead of string
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.

12 days agofeat: enrich OCPP 2.0 template with OCPP 1.6 equivalent config keys
Jérôme Benoit [Fri, 27 Mar 2026 12:46:34 +0000 (13:46 +0100)] 
feat: enrich OCPP 2.0 template with OCPP 1.6 equivalent config keys

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

12 days ago[autofix.ci] apply automated fixes
autofix-ci[bot] [Fri, 27 Mar 2026 11:34:09 +0000 (11:34 +0000)] 
[autofix.ci] apply automated fixes

12 days agofix: use Component.Variable[.Instance] key format for OCPP 2.0 variable persistence
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

13 days agofeat: log once per key when OCPP 1.6 configuration key is remapped to OCPP 2.0 variable
Jérôme Benoit [Thu, 26 Mar 2026 23:09:30 +0000 (00:09 +0100)] 
feat: log once per key when OCPP 1.6 configuration key is remapped to OCPP 2.0 variable

13 days agofix: remove OrganizationName from ISO15118Ctrlr (spec says SecurityCtrlr only)
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.

13 days agorefactor: add Enabled to OCPP20RequiredVariableName enum and fix LocalAuthListCtrlr...
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.

13 days agofix: align OCPP 2.0 variable names to spec (LocalPreAuthorization, LocalAuthorization...
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.

13 days agochore: remove test plan from git tracking
Jérôme Benoit [Thu, 26 Mar 2026 21:43:28 +0000 (22:43 +0100)] 
chore: remove test plan from git tracking

13 days agofeat: resolve OCPP 1.6 configuration keys to OCPP 2.0 equivalents transparently
Jérôme Benoit [Thu, 26 Mar 2026 21:42:53 +0000 (22:42 +0100)] 
feat: resolve OCPP 1.6 configuration keys to OCPP 2.0 equivalents transparently

Add resolveKey() inside ConfigurationKeyUtils that maps OCPP 1.6 key
names to their OCPP 2.0 equivalents (MeterValuesSampledData →
TxUpdatedMeasurands, ConnectionTimeOut → EVConnectionTimeOut, etc.)
transparently in get/add/set/delete operations. Remap keba-ocpp2
template keys and add missing OCPP 2.0 variables. Add exhaustive
tests for key resolution across all OCPP versions.

13 days agofix: use OCPP version-specific parameter keys for meter value measurands
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.

13 days agofix(docs): use bold instead of italic for vendor-specific markers to avoid underscore...
Jérôme Benoit [Thu, 26 Mar 2026 20:03:00 +0000 (21:03 +0100)] 
fix(docs): use bold instead of italic for vendor-specific markers to avoid underscore conflicts

13 days agodocs: list OCPP 2.0 device model variables by component in README
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.

13 days agochore: release main (#1751) ocpp-server@v3.4.0 simulator@v3.4.0 v3 v3.4 webui@v3.4.0
Jérôme Benoit [Thu, 26 Mar 2026 19:31:47 +0000 (20:31 +0100)] 
chore: release main (#1751)

* chore: release main

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
13 days agofeat(ocpp2): add configurable firmware signature verification simulation (L01.FR...
Jérôme Benoit [Thu, 26 Mar 2026 19:06:53 +0000 (20:06 +0100)] 
feat(ocpp2): add configurable firmware signature verification simulation (L01.FR.03/L01.FR.04) (#1757)

* feat(ocpp2): add FirmwareCtrlr component and signature verification variable

* test(ocpp2): add firmware signature verification failure tests

- 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)

* feat(ocpp2): implement configurable firmware signature verification simulation

* docs: update README firmware signature verification note

* 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

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* 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.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
13 days agofix: respect elementAddDelay by using sequential startup when configured
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.

13 days agofix(deps): update all non-major dependencies (#1755)
renovate[bot] [Thu, 26 Mar 2026 11:42:37 +0000 (12:42 +0100)] 
fix(deps): update all non-major dependencies (#1755)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
13 days agochore: remove test plan from git tracking
Jérôme Benoit [Thu, 26 Mar 2026 00:03:45 +0000 (01:03 +0100)] 
chore: remove test plan from git tracking

13 days agofix: cleanup connector after queued TransactionEvent.Ended replay
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.

2 weeks agotest(webui): harmonize test stubs, remove AAA comments, add composable and StateButto...
Jérôme Benoit [Wed, 25 Mar 2026 22:41:36 +0000 (23:41 +0100)] 
test(webui): harmonize test stubs, remove AAA comments, add composable and StateButton tests

2 weeks agofeat: add server-side refresh notification over WebSocket
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.

2 weeks agofix: post updated message on connectorStatusChanged to fix stale UI cache
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.

2 weeks agorefactor(webui): extract useExecuteAction composable to eliminate duplication
Jérôme Benoit [Wed, 25 Mar 2026 20:55:02 +0000 (21:55 +0100)] 
refactor(webui): extract useExecuteAction composable to eliminate duplication

2 weeks agorefactor(webui): use useChargingStations composable in ChargingStationsView
Jérôme Benoit [Wed, 25 Mar 2026 20:36:53 +0000 (21:36 +0100)] 
refactor(webui): use useChargingStations composable in ChargingStationsView

2 weeks agorefactor(webui): add StateButton, centralize active style, fix refresh lifecycle
Jérôme Benoit [Wed, 25 Mar 2026 20:30:03 +0000 (21:30 +0100)] 
refactor(webui): add StateButton, centralize active style, fix refresh lifecycle

- StateButton: stateless toggle driven by server state (active prop)
- Button: owns .button--active CSS, ToggleButton/StateButton pass :active
- Conditional buttons: show Start/Stop, Open/Close, Lock/Unlock based on state
- refreshChargingStations(): shared composable eliminates 4x duplicated refresh
- executeAction() helper in CSData/CSConnector: DRY action/toast/refresh
- Fix: trigger getChargingStations() on need-refresh event
- Fix: refresh after AddChargingStations, StartTransaction, SetSupervisionUrl
- table-layout: fixed on connectors table to prevent overflow

2 weeks agochore(deps): update dependency typescript to v6 (#1750)
renovate[bot] [Wed, 25 Mar 2026 18:59:13 +0000 (19:59 +0100)] 
chore(deps): update dependency typescript to v6 (#1750)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2 weeks agofix(webui): add table-layout fixed to connectors table to prevent overflow on action...
Jérôme Benoit [Wed, 25 Mar 2026 18:56:25 +0000 (19:56 +0100)] 
fix(webui): add table-layout fixed to connectors table to prevent overflow on action panel open