]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/log
e-mobility-charging-stations-simulator.git
3 hours agorefactor: audit-driven quick wins — fix assert.ok misuse, naming conventions, and...
Jérôme Benoit [Tue, 24 Mar 2026 13:46:17 +0000 (14:46 +0100)] 
refactor: audit-driven quick wins — fix assert.ok misuse, naming conventions, and hardcoded defaults

- 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

5 hours agofix(webui): remove deprecated baseUrl for TypeScript 6 compatibility
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.

6 hours agorefactor(ocpp-server): audit-driven test improvements
Jérôme Benoit [Tue, 24 Mar 2026 11:20:08 +0000 (12:20 +0100)] 
refactor(ocpp-server): audit-driven test improvements

- Extract mock_valid_ws and rate_limit_charge_point fixtures (DRY)
- Replace inline blacklist AuthConfig with existing fixture
- Strengthen log assertions using caplog.records with level checks
- Add edge case tests: empty token in whitelist/blacklist modes
- Add test for unknown transaction event type (case _ branch)
Coverage: 90.18% → 90.98%, 159 → 162 tests.

6 hours agorefactor(ocpp-server): harmonize shutdown tests with project conventions
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.

6 hours agotest(ocpp-server): add graceful shutdown tests covering signal handling
Jérôme Benoit [Tue, 24 Mar 2026 11:03:17 +0000 (12:03 +0100)] 
test(ocpp-server): add graceful shutdown tests covering signal handling

Cover SIGINT/SIGTERM handlers, double-signal force quit, Windows
fallback via call_soon_threadsafe, and shutdown timeout warning.
Coverage: 80% → 90%.

6 hours agofeat(ocpp-server): add graceful shutdown with signal handling
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.

16 hours agotest(mcp): add OCPP schema mapping consistency tests
Jérôme Benoit [Tue, 24 Mar 2026 01:21:55 +0000 (02:21 +0100)] 
test(mcp): add OCPP schema mapping consistency tests

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.

16 hours agochore: release main (#1748) v3.3
Jérôme Benoit [Tue, 24 Mar 2026 01:09:52 +0000 (02:09 +0100)] 
chore: release main (#1748)

* chore: release main

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
16 hours agofix(deps): update all non-major dependencies (#1749)
renovate[bot] [Tue, 24 Mar 2026 01:05:31 +0000 (02:05 +0100)] 
fix(deps): update all non-major dependencies (#1749)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
16 hours agorefactor(mcp): split MCP definitions by spec concern — Resources, Tools, ToolSchemas
Jérôme Benoit [Tue, 24 Mar 2026 00:58:12 +0000 (01:58 +0100)] 
refactor(mcp): split MCP definitions by spec concern — Resources, Tools, ToolSchemas

Rename MCPResourceHandlers.ts to MCPResources.ts (contains only MCP
Resources: station-list, station-by-id, template-list, OCPP schemas).

Extract log tools (readCombinedLog, readErrorLog) and their helpers
(getLogFilePath, tailFile) into MCPTools.ts (MCP Tools per spec).

MCPToolSchemas.ts unchanged (tool schema definitions).

Directory now reflects MCP spec separation of concerns:
- MCPResources.ts  — MCP Resources (spec §Resources)
- MCPTools.ts      — MCP Tools with custom logic (spec §Tools)
- MCPToolSchemas.ts — Tool schema definitions for OCPP commands

16 hours agorefactor(broadcast-channel): extract response status registries from switch/case
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.

16 hours agorefactor(broadcast-channel): extract passthrough() factory, remove 20 identical handlers
Jérôme Benoit [Tue, 24 Mar 2026 00:39:40 +0000 (01:39 +0100)] 
refactor(broadcast-channel): extract passthrough() factory, remove 20 identical handlers

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

Net reduction: -208 lines.

17 hours agorefactor(ocpp): extract buildEmptyMeterValue helper for empty MeterValue construction
Jérôme Benoit [Tue, 24 Mar 2026 00:16:06 +0000 (01:16 +0100)] 
refactor(ocpp): extract buildEmptyMeterValue helper for empty MeterValue construction

Replace 4 inline { sampledValue: [], timestamp: new Date() } constructions
with buildEmptyMeterValue() helper in OCPPServiceUtils and OCPP16ServiceUtils.

17 hours agofeat(ui-server): add MCP transport and deprecate HTTP (#1746)
Jérôme Benoit [Mon, 23 Mar 2026 23:59:59 +0000 (00:59 +0100)] 
feat(ui-server): add MCP transport and deprecate HTTP (#1746)

* feat(types): add MCP application protocol type

* chore(deps): add @modelcontextprotocol/sdk and zod

* refactor(ui-server): deprecate UIHttpServer in favor of MCP transport

* feat(ui-server): add MCP tool zod schemas for all procedures

* feat(ui-server): add UIMCPServer transport and MCP resource handlers

* feat(ui-server): integrate UIMCPServer into UIServerFactory

* test(ui-server): add MCP factory integration tests

* test(ui-server): add UIMCPServer unit tests

* test(ui-server): add MCP endpoint integration tests and fix lint

* refactor(ui-server): extract HttpMethod enum to shared UIServerUtils

* docs: restructure UI Protocol section — MCP first, remove redundant API listing

* fix(ui-server): address PR review — security hardening and schema corrections

- Send 404 + destroy for non-/mcp requests instead of hanging socket
- Add rate limiting (429) matching UIHttpServer behavior
- Add body size limit (createBodySizeLimiter) to prevent DoS
- Register res.on('close') before handleRequest to prevent race
- Return 400 for JSON parse errors, 500 for server errors
- Fix setSupervisionUrl schema: supervisionUrl → url
- Fix stopTransaction schema: transactionIds string[] → transactionId number

* refactor(tests): use HttpMethod enum instead of string literals

* docs: remove redundant MCP discoverability statement

* docs: restructure MCP section for agent config, update uiServer type in config table

* feat(ui-server): log deprecation warning when HTTP transport is used

* fix(ui-server): harmonize log levels and message patterns with existing transports

* test(ui-server): align MCP tests with style guide

- Use createLoggerMocks() for log assertions instead of trivial checks
- Add server.stop() to factory fallback tests to prevent resource leaks
- Replace fragile globalThis.clearTimeout override with t.mock.method

* docs: restore PDU acronym definition in WebSocket Protocol section

* fix(ui-server): use UI protocol version for MCP server version

* fix(ui-server): derive log file paths from Configuration instead of hardcoding

* perf(ui-server): tail-read log files instead of loading entire file into memory

* refactor(ui-server): convert log resources to tools with tail parameter

Follow MCP best practices: resources are for static snapshots,
tools are for parameterized on-demand data.

- Replace log://combined and log://error resources with
  readCombinedLog and readErrorLog tools
- Add tail parameter (default 200, max 5000) following the
  filesystem server head/tail pattern
- Add readOnlyHint annotation per MCP tool spec
- Return totalLines metadata in response for context
- Keep station and template resources (small, static data)

* feat(ui-server): expose OCPP JSON schemas as MCP resource templates

Add schema://ocpp/{version} listing and schema://ocpp/{version}/{command}
resource templates that serve the existing JSON schema files from
src/assets/json-schemas/ocpp/ on demand.

LLM agents can discover available OCPP commands per version and read
the full JSON schema for any command without bloating tools/list.
Schemas are read from disk on demand — no memory duplication with
the AJV validators already loaded by OCPP services.

* feat(ui-server): add version-aware OCPP tool schemas with JSON Schema injection

- Add ocppSchemaMapping linking ProcedureName to JSON Schema files
- 16 OCPP tools now have ocpp16Payload/ocpp20Payload fields with
  version affinity in descriptions
- Intercept tools/list to inject full JSON Schemas from disk
  into inputSchema.properties (no Zod duplication, DRY)
- Add payload flattening: extract versioned payload, spread flat
- Add mutual exclusivity: reject if both payloads provided
- Add pre-flight version check: clear error on version mismatch
- Runtime guard: graceful fallback if SDK internal API changes

* refactor(ui-server): use OCPPVersion enum instead of string literals

* refactor(ui-server): improve MCP code elegance and project rule compliance

- Replace as-unknown-as cast with Reflect.get() for SDK handler access
- Replace generic Error with BaseError in stop/readRequestBody
- Extract createToolErrorResponse/createToolResponse static helpers (DRY)
- Extract closeTransportSafely for duplicate transport cleanup
- Extract registerLogReadTool factory for duplicate log tools (DRY)
- Remove unnecessary String() conversions in resource handlers

* fix(ui-server): fix body size double-counting and schema resource path

- readRequestBody: pass chunk.length (not accumulated total) to
  createBodySizeLimiter — matches UIHttpServer pattern
- getSchemaBaseDir: use correct relative path instead of broken
  resolve().includes('assets') condition (always true)

* refactor(ui-server): consolidate version fallback guards and clarify README version docs

* fix(ui-server): harden MCP schema resources against path traversal and fix transport leak

- Add path traversal guard in schema resource handlers to validate resolved
  paths stay within the OCPP schema base directory
- Close MCP transport on 405 Method Not Allowed responses to prevent leak
- Fix log file path to use direct path when rotation is disabled
- Fix misleading Heartbeat tool description that referenced unsupported
  ocpp payload fields

* fix(ui-server): address remaining review findings and lint warnings

- Reorder stop() to delete-before-reject preventing re-entrant issues
- Use ephemeral port in integration test instead of fixed port 18999
- Document synchronous authenticate() assumption and SDK pattern deviation
- Add 'modelcontextprotocol' to cspell wordlist
- Convert JSDoc to inline comment to fix jsdoc lint warnings

* fix(ui-server): exact MCP path match, pin SDK version, log schema injection

- Use exact pathname match (url.pathname !== '/mcp') instead of
  startsWith to prevent unintended paths from reaching the MCP handler
- Pin @modelcontextprotocol/sdk to ~1.27.1 (patch-only) since the
  OCPP schema injection relies on SDK internals pinned to 1.27.x
- Add startup log confirming successful OCPP JSON schema injection

* test(ui-server): add comprehensive UIMCPServer unit tests

Cover private method logic missing from initial test suite:
- invokeProcedure: service null, dual payload, version mismatch,
  direct response, service error, 30s timeout (mock timers)
- checkVersionCompatibility: OCPP 1.6/2.0/2.0.1 matching, cross-version
  errors, hashIds filtering, all-stations fallback
- readRequestBody: valid JSON, payload too large, invalid JSON, stream error
- loadOcppSchemas: disk loading, cache entry validation

Refactor for elegance and guide compliance:
- Centralize Reflect.get wrappers in TestableUIMCPServer class
- Extract assertToolError() helper to eliminate repeated triplet
- Move createMockChargingStationDataWithVersion() to UIServerTestUtils
- Replace magic number with DEFAULT_MAX_PAYLOAD_SIZE import

* fix(ui-server): per-request McpServer factory, async iterator body reader, transport leak

- Create a new McpServer per HTTP request via createMcpServer() factory
  to fix concurrency bug: McpServer.connect() overwrites a single
  internal _transport field, causing cross-talk under concurrent requests.
  OCPP schema cache and UI service are pre-loaded at startup; tool
  registration is ~12µs per request (negligible).

- Replace event-listener readRequestBody with for-await-of async
  iterator pattern. Single settlement guaranteed by language semantics,
  eliminating the double-reject bug on payload-too-large.

- Close transport on mcpServer.connect() failure to prevent resource leak.

- Clean up both transport and McpServer on response close via unified
  cleanup callback.

* fix: align StatusNotification field name with OCPP 2.0.1 schema, fix asset paths

- Use 'connectorStatus' (OCPP 2.0.1 schema field name) instead of
  'status' (non-standard) in OCPP20RequestService.buildRequestPayload
  and both call sites in OCPP20IncomingRequestService

- Fix esbuild-relative asset paths for OCPP JSON schemas and MCP
  resource handlers — import.meta.url resolves to dist/start.js,
  not the original source tree depth

* refactor(ocpp): align payload builders to object-param API, fix StatusNotification field names

- Refactor buildStatusNotificationRequest from positional params to
  object-based StatusNotificationRequest input. Builder accepts both
  'status' (internal/OCPP 1.6) and 'connectorStatus' (OCPP 2.0.1)
  with consistent fallback order (connectorStatus ?? status).

- Refactor buildTransactionEvent from 3 overloads to single
  object-based OCPP20TransactionEventRequest input, removing
  positional param complexity and non-null assertions.

- Refactor sendAndSetConnectorStatus from positional params to
  object-based StatusNotificationRequest input. Callers pass
  version-correct field names: 'status' in OCPP 1.6 code,
  'connectorStatus' in OCPP 2.0 code, either in common code.

- Extract getSchemaBaseDir() as protected method on UIMCPServer
  for test overridability, replacing fragile symlink hack.

- Migrate all call sites (28 sendAndSetConnectorStatus, 60+
  buildTransactionEvent) and their corresponding tests.

* build: externalize @modelcontextprotocol/sdk and zod from esbuild bundle

Add @modelcontextprotocol/* and zod to esbuild external list for
consistency with all other production dependencies (ajv, ws, winston,
etc.) which are already externalized. Reduces bundle size and avoids
bundling the SDK's transitive dependency tree.

* fix(ui-server): fix SonarCloud quality gate — localeCompare sort, reduce cognitive complexity

- Add localeCompare to schema file sort in MCPResourceHandlers to
  ensure locale-aware alphabetical ordering (SonarCloud bug)

- Extract sendErrorResponse helper from handleMcpRequest to reduce
  cognitive complexity from 16 to below threshold (SonarCloud smell)

* chore: update .serena/project.yml with new default config fields

* refactor(ocpp): buildMeterValue resolves connectorId/evseId from transactionId

- Refactor buildMeterValue signature from (station, connectorId,
  transactionId, interval) to (station, transactionId, interval).
  connectorId and evseId are resolved internally from the unique
  transactionId via getConnectorIdByTransactionId/getEvseIdByTransactionId.

- Refactor getSampledValueTemplate to accept optional evseId. When
  provided, EVSE-level MeterValues templates take priority; falls back
  to merging connector-level templates from all EVSE connectors.

- Add MeterValues field to EvseStatus and EvseTemplate types to support
  EVSE-level meter value template definitions.

- Refactor handleMeterValues in BroadcastChannel from if/else to
  switch/case on OCPP version with explicit default error.

- Simplify OCPP20IncomingRequestService fallback MeterValues (no
  transaction = static empty meter value, skip buildMeterValue).

- Add buildMeterValue unit tests covering OCPP 1.6/2.0 resolution,
  unknown transactionId throw, EVSE-level template priority, and
  connector template merge fallback.

- Add TEST_TRANSACTION_ID_STRING constant for OCPP 2.0 tests, fix
  BroadcastChannel test to use string transactionId for OCPP 2.0.1.

* docs: add MCP Protocol to ToC, fix HTTP Protocol link, document EVSE-level MeterValues

- Add MCP Protocol entry to table of contents
- Fix HTTP Protocol anchor to match 'deprecated' heading
- Document EVSE-level MeterValues templates in Evses section examples
  with priority explanation (EVSE-level overrides connector-level)

* fix(ocpp): version-aware Authorize response mapping, complete cross-version types

- Fix commandResponseToResponseStatus for Authorize: use switch/case
  on OCPP version. OCPP 1.6 checks idTagInfo.status, OCPP 2.0 checks
  idTokenInfo.status. Previously only checked idTagInfo (1.6 field),
  causing MCP to report 'failure' for successful OCPP 2.0 authorizations.

- Make AuthorizeResponse and AuthorizeRequest cross-version union types
  (OCPP16 | OCPP20) consistent with AuthorizationStatus pattern.

- Make isIdTagRemoteAuthorized version-aware: sends idTag for OCPP 1.6,
  idToken for OCPP 2.0, and checks the version-correct response field.

- Use version-specific casts (OCPP16AuthorizeResponse,
  OCPP20AuthorizeResponse) in version-switched code paths instead of
  agnostic union type.

* refactor(ocpp): harmonize version switch/case in auth functions

- Refactor isIdTagAuthorizedUnified and isIdTagAuthorized from if/else
  on OCPP version to switch/case with explicit VERSION_16, VERSION_20/201
  cases and separate default fallback.

- Remove unnecessary optional chaining on stationInfo inside
  version-switched cases where stationInfo is guaranteed non-null.

- Separate VERSION_16 from default in all auth switch/case blocks
  for spec-compliant version handling.

* fix(ocpp): buildMeterValue from transactionId, log date locale fix, MeterValues EVSE templates

- Refactor buildMeterValue to resolve connectorId/evseId from
  transactionId internally. Returns empty MeterValue when transactionId
  is undefined (MCP pass-through with provided meterValue).

- Fix log file date resolution: use local date instead of UTC to match
  Winston DailyRotateFile naming convention.

- Add optional date parameter to readCombinedLog/readErrorLog MCP tools
  for accessing rotated log files by date (YYYY-MM-DD).

- Add MeterValues field to EvseStatus/EvseTemplate types for EVSE-level
  meter value template definitions. getSampledValueTemplate checks
  EVSE-level templates first, falls back to merging connector templates.

- Refactor handleMeterValues to switch/case on OCPP version with
  explicit default error.

- Make AuthorizeRequest/AuthorizeResponse cross-version union types.
  Fix commandResponseToResponseStatus and isIdTagRemoteAuthorized with
  version-aware switch/case for OCPP 1.6 (idTagInfo) vs 2.0 (idTokenInfo).

- Add integration tests for readCombinedLog tool (default date, explicit
  date, missing file error). Add buildMeterValue unit tests.

29 hours agochore(deps): lock file maintenance (#1747)
renovate[bot] [Mon, 23 Mar 2026 12:04:34 +0000 (13:04 +0100)] 
chore(deps): lock file maintenance (#1747)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
30 hours agochore(deps): update dependency vite to v8 (#1717)
renovate[bot] [Mon, 23 Mar 2026 11:15:16 +0000 (12:15 +0100)] 
chore(deps): update dependency vite to v8 (#1717)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
46 hours agochore: release main (#1743) v3.2
Jérôme Benoit [Sun, 22 Mar 2026 18:35:32 +0000 (19:35 +0100)] 
chore: release main (#1743)

* chore: release main

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
47 hours agofix(ocpp2): implement StopTxOnInvalidId and MaxEnergyOnInvalidId per E05 (#1745)
Jérôme Benoit [Sun, 22 Mar 2026 18:26:00 +0000 (19:26 +0100)] 
fix(ocpp2): implement StopTxOnInvalidId and MaxEnergyOnInvalidId per E05 (#1745)

* fix(ocpp2): implement StopTxOnInvalidId and MaxEnergyOnInvalidId per E05

Implement the full deauthorization decision tree per OCPP 2.0.1 spec:
- StopTxOnInvalidId=false: transaction continues, no termination
- StopTxOnInvalidId=true + MaxEnergyOnInvalidId>0: defer termination
  until energy limit reached (checked in periodic meter values callback)
- StopTxOnInvalidId=true + MaxEnergyOnInvalidId=0: immediate suspension
  and termination

Also includes:
- Deduplicate transactionSetInterval/transactionTxUpdatedSetInterval
  into single transactionMeterValuesSetInterval field
- Add transactionDeauthorized/transactionDeauthorizedEnergyWh to
  ConnectorStatus for deauth state tracking (cleared in resetConnectorStatus)
- Extract readVariableValue/readVariableAsBoolean/readVariableAsInteger
  helpers using convertToInt and convertToBoolean utilities
- Fix buildEvsesStatus test that was missing evse-to-connector wiring

* refactor(ocpp2): address PR review comments

- Add logger.warn in readVariableAsInteger catch for diagnostic
- Replace unsafe 'as string' cast with .toString() in periodic callback
- Add tests for StopTxOnInvalidId=false and deauth state tracking

* chore: update webui.png

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* test: add resetConnectorStatus unit tests to Helpers.test.ts

Verify all 18 transaction fields are properly cleaned, TX_PROFILE
charging profiles matching the transaction are removed, and
non-transaction fields are preserved.

---------

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
2 days agofix(ocpp2): align MeterValues implementation with OCPP 2.0.1 spec (#1744)
Jérôme Benoit [Sun, 22 Mar 2026 15:36:32 +0000 (16:36 +0100)] 
fix(ocpp2): align MeterValues implementation with OCPP 2.0.1 spec (#1744)

* fix(ocpp2): use AlignedDataInterval for standalone MeterValues

Add getAlignedDataInterval() helper to OCPP20ServiceUtils that reads
AlignedDataCtrlr.Interval from the variable registry (default 900s).

Replace getTxUpdatedInterval() with getAlignedDataInterval() in the
broadcast channel handleMeterValues OCPP 2.0 branch. Standalone
MeterValuesRequest is non-transaction data per OCPP 2.0.1 spec and
should use the aligned data interval, not the tx-updated interval.

* fix(ocpp2): include meter value in TransactionEvent Started

Add buildTransactionBeginMeterValues() to OCPP20ServiceUtils following
the buildFinalMeterValues() pattern. Builds an OCPP20MeterValue with
Transaction.Begin context and Energy.Active.Import.Register measurand.

Wire it into both TransactionEvent(Started) call sites:
- OCPPServiceUtils.startTransactionOnConnector (ATG/broadcast channel)
- OCPP20IncomingRequestService RequestStartTransaction event listener

This aligns OCPP 2.0 with the OCPP 1.6 beginEndMeterValues behavior
per OCPP 2.0.1 spec SampledDataTxStartedMeasurands requirement.

* test(ocpp2): add tests for buildTransactionBeginMeterValues

Test Transaction.Begin context, energy register value, default to 0
when undefined, and empty array when energy is negative.

* refactor(ocpp2): address PR review comments

- Extract buildEnergyMeterValues private helper to eliminate DRY
  violation between buildTransactionBeginMeterValues and
  buildFinalMeterValues
- Add AlignedDataInterval to OCPP20RequiredVariableName enum replacing
  raw string literal in getAlignedDataInterval
- Clarify zero-energy test name to document that 0 Wh is a valid
  Transaction.Begin reading
- Add meterValue assertions to RequestStartTransaction test verifying
  Transaction.Begin context and Energy.Active.Import.Register measurand

* refactor(ocpp2): extract readVariableAsIntervalMs to eliminate DRY

getAlignedDataInterval and getTxUpdatedInterval were structurally
identical. Extract the shared variable-reading logic into a private
readVariableAsIntervalMs helper that accepts component name, variable
name, and default seconds. Both public methods become one-liner
delegates.

* refactor(ocpp2): extract terminateTransaction and resolveActiveTransaction

requestDeauthorizeTransaction and requestStopTransaction shared
identical transaction termination logic (build final meter values,
send TransactionEvent Ended, stop periodic, reset connector status).

Extract resolveActiveTransaction for the shared precondition check
and transactionId string resolution, and terminateTransaction for
the shared Ended event + cleanup workflow. Both public methods now
focus only on their unique behavior.

* fix(test): use enum constants instead of string literals in RequestStartTransaction test

Replace 'Transaction.Begin' and 'Energy.Active.Import.Register' string
literals with OCPP20ReadingContextEnumType.TRANSACTION_BEGIN and
OCPP20MeasurandEnumType.ENERGY_ACTIVE_IMPORT_REGISTER to match
codebase conventions.

* refactor(test): replace string literals with enum constants in OCPP 2.0 tests

Replace hardcoded string literals with their corresponding OCPP 2.0.1
enum values across test files for type safety and consistency:

- RequestStopTransaction: Transaction.End, Energy.Active.Import.Register
- SchemaValidation: Immediate, OnIdle, Heartbeat, BootNotification
- enforceMessageLimits: TooManyElements, TooLargeElement
- CertificateManager: Accepted, Failed, NotFound
- ChangeAvailability: UnknownEvse
- GetBaseReport: Accepted (SetVariableStatusEnumType)
- CertificateSigned: InternalError
- ServiceUtils-TransactionEvent: TransactionEvent command name

* fix(test): replace bogus mock return values with correctly typed empty responses

requestDeauthorizeTransaction mocks returned { status: 'Accepted' }
but OCPP20TransactionEventResponse has no status field. Replace with
properly typed empty response objects since the return value is not
asserted in these tests.

* refactor(ocpp2): align method names with OCPP 2.0.1 spec terminology

Rename methods to match OCPP 2.0.1 TransactionEvent terminology:
- buildTransactionBeginMeterValues -> buildTransactionStartedMeterValues
- buildFinalMeterValues -> buildTransactionEndedMeterValues
- beginMeterValues variable -> startedMeterValues
- finalMeterValues variable -> endedMeterValues

The spec uses Started/Updated/Ended for TransactionEvent types, not
Begin/Final.

* refactor(test): replace 'Operative' string literal with enum constants

Use OCPP20OperationalStatusEnumType.Operative in OCPP 2.0 test files
and the cross-version AvailabilityType.Operative in MessageChannelUtils
test to match ConnectorStatus.availability typed field.

2 days agofix(deps): update all non-major dependencies (#1742)
renovate[bot] [Sun, 22 Mar 2026 13:52:31 +0000 (14:52 +0100)] 
fix(deps): update all non-major dependencies (#1742)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2 days agofix(ocpp2): build meter values payload in broadcast channel for OCPP 2.0.x
Jérôme Benoit [Sun, 22 Mar 2026 11:40:27 +0000 (12:40 +0100)] 
fix(ocpp2): build meter values payload in broadcast channel for OCPP 2.0.x

The OCPP 2.0 branch in handleMeterValues was passing the raw broadcast
channel payload through to requestHandler without constructing the
required evseId and meterValue fields. Build the payload using
buildMeterValue and resolve evseId from connectorId, matching the
pattern used by the OCPP 1.6 branch.

2 days ago[autofix.ci] apply automated fixes
autofix-ci[bot] [Sat, 21 Mar 2026 20:35:45 +0000 (20:35 +0000)] 
[autofix.ci] apply automated fixes

2 days agochore: release main (#1733)
Jérôme Benoit [Sat, 21 Mar 2026 20:32:53 +0000 (21:32 +0100)] 
chore: release main (#1733)

2 days agorefactor(ocpp2): use enum values instead of string literals in variable registry
Jérôme Benoit [Sat, 21 Mar 2026 20:29:59 +0000 (21:29 +0100)] 
refactor(ocpp2): use enum values instead of string literals in variable registry

Replace all string literals that have corresponding TypeScript enums:
- OCPP20OperationalStatusEnumType for AvailabilityState defaultValue/enumeration
- OCPP20ChargingRateUnitEnumType for ChargingScheduleAllowedChargingRateUnit
  defaultValue, enumeration, and description

2 days agorevert(ocpp2): re-comment Available→Available self-transitions
Jérôme Benoit [Sat, 21 Mar 2026 20:20:07 +0000 (21:20 +0100)] 
revert(ocpp2): re-comment Available→Available self-transitions

Self-transitions are not allowed per OCPP 2.0.1 spec. The boot
sequence warning needs a different fix (skip StatusNotification
when connector status unchanged).

2 days agofix(ocpp2): add AvailabilityState defaults and allow self-transitions
Jérôme Benoit [Sat, 21 Mar 2026 20:15:55 +0000 (21:15 +0100)] 
fix(ocpp2): add AvailabilityState defaults and allow self-transitions

- Add defaultValue using OCPP20OperationalStatusEnumType.Operative
  enum for ChargingStation AvailabilityState (was missing, causing
  'Missing required configuration key mapping' error at auth time)
- Replace string literals with OCPP20OperationalStatusEnumType enum
  values in AvailabilityState enumeration arrays
- Allow Available→Available self-transitions in OCPP20Constants for
  both ChargingStation and Connector status tables (required by
  boot sequence StatusNotification per spec Part 2 §4.1 step 5)

2 days agofix(lifecycle): clear auth service on template reload and station reset
Jérôme Benoit [Sat, 21 Mar 2026 19:26:19 +0000 (20:26 +0100)] 
fix(lifecycle): clear auth service on template reload and station reset

Auth service instance was persisting across template reloads and
station resets, causing stale adapters if OCPP version changed.

- Add OCPPAuthServiceFactory.clearInstance() before initialize()
  in template file change handler
- Add OCPPAuthServiceFactory.clearInstance() before initialize()
  in reset() method

2 days agofix(auth): replace phantom spec references in source code comments
Jérôme Benoit [Sat, 21 Mar 2026 19:18:54 +0000 (20:18 +0100)] 
fix(auth): replace phantom spec references in source code comments

- G03.FR.01 → remove (was Change Availability, not auth)
- R10 → C10.FR.08 (cache expiration behavior)
- R16, R5 → C10.FR.08 (TTL reset 'since last used')
- R2 → C10.FR.07 (evict non-valid entries first)
- R17 → C13.FR.01 (local auth list priority over cache)

2 days agotest(auth): fix OCPP spec references and remove duplicated tests
Jérôme Benoit [Sat, 21 Mar 2026 19:11:34 +0000 (20:11 +0100)] 
test(auth): fix OCPP spec references and remove duplicated tests

Replace incorrect G03/G04 (Change Availability) prefixes with correct
OCPP 2.0.1 Authorization section codes (C10/C11/C12/C13/C15).
Remove spec prefixes from internal tests with no direct spec mapping.

- C10.FR.01: cache all statuses (was G03.FR.01.T4)
- C10.FR.07: eviction mechanism (was G03.FR.01.T5)
- C10.FR.08: TTL/expiry behavior (was G03.FR.01.T6/T7)
- C11: cache invalidation (was G03.FR.01.004)
- C12: cache miss behavior (was G03.FR.01.002)
- C13.FR.01: local auth list priority (was G03.FR.01.T8)
- C15: offline authorization (was G03.FR.02)
- Remove 5 duplicated cache unit tests from integration suite
- Update TEST_STYLE_GUIDE.md examples

2 days agotest(auth): strengthen assertion quality and edge case coverage
Jérôme Benoit [Sat, 21 Mar 2026 18:41:46 +0000 (19:41 +0100)] 
test(auth): strengthen assertion quality and edge case coverage

- G03.FR.01 cache tests now verify status and TTL, not just cache key
- Add stats increment verification after success and failure auth
- Add cache error resilience test (cache.set throws)
- Add idTag boundary tests for exactly 19, 20, 21 characters
- Rename misleading 'concurrent operations' test to 'sequential batch'

2 days agorefactor(auth): remove ocppVersion from UnifiedIdentifier
Jérôme Benoit [Sat, 21 Mar 2026 18:29:50 +0000 (19:29 +0100)] 
refactor(auth): remove ocppVersion from UnifiedIdentifier

Version info is now sourced from adapter.ocppVersion since each
station has a single adapter. Eliminates redundant version stamping
on every identifier.

- Remove ocppVersion field from UnifiedIdentifier interface
- CertificateAuthStrategy uses this.adapter.ocppVersion
- Adapters no longer stamp version on created identifiers
- Fix CertificateAuthStrategy OCPP 1.6 test to use 1.6 adapter
  instead of relying on missing certificateHashData

2 days agorefactor(auth): replace adapter Map with single adapter per station
Jérôme Benoit [Sat, 21 Mar 2026 18:01:48 +0000 (19:01 +0100)] 
refactor(auth): replace adapter Map with single adapter per station

Each charging station has exactly one OCPP version, making the
Map<OCPPVersion, OCPPAuthAdapter> unnecessary indirection. Simplify
to a single adapter field across the auth module.

- AuthComponentFactory: createAdapter() returns single OCPPAuthAdapter
- RemoteAuthStrategy: setAdapter()/clearAdapter() replace map ops
- CertificateAuthStrategy: readonly adapter field, no map
- OCPPAuthServiceImpl: single adapter, initializeAdapter() singular
- Tests updated to match new single-adapter API

2 days agofix(auth): address audit findings in OCPP auth abstraction layer
Jérôme Benoit [Sat, 21 Mar 2026 17:39:09 +0000 (18:39 +0100)] 
fix(auth): address audit findings in OCPP auth abstraction layer

- Read AuthCtrlr.LocalAuthorizeOffline variable instead of hardcoding true
- Delegate testConnectivity() to actual adapter availability checks
- Remove duplicate mapOCPP20AuthStatus(), use canonical mapOCPP20AuthorizationStatus
- Map strategies by name instead of fragile priority numbers
- Make connectorId truly optional in OCPP20AuthAdapter.authorizeRemote()
- Use ES2022 Error cause chain in AuthenticationError

3 days agofix(webui): use table-layout fixed so table shrinks with container when action panel...
Jérôme Benoit [Sat, 21 Mar 2026 17:03:40 +0000 (18:03 +0100)] 
fix(webui): use table-layout fixed so table shrinks with container when action panel opens

Replace min-width: 1280px + table-layout: auto with table-layout: fixed.
Auto layout ignores width: 100% and expands based on content, causing
the table to overflow behind the action panel. Fixed layout respects
the container width and distributes columns equally. Add overflow:
hidden on charging-stations-container as belt-and-suspenders clip.

3 days agofix(webui): remove white-space nowrap on buttons to prevent table overflow
Jérôme Benoit [Sat, 21 Mar 2026 16:56:43 +0000 (17:56 +0100)] 
fix(webui): remove white-space nowrap on buttons to prevent table overflow

The nowrap prevented button text from wrapping in narrow table columns,
causing the table to overflow its container when the action panel was
open. Buttons in the toolbar still fit without wrapping due to flex
sizing.

3 days agofix(webui): prevent action panel flex grow and allow table container to shrink
Jérôme Benoit [Sat, 21 Mar 2026 16:23:56 +0000 (17:23 +0100)] 
fix(webui): prevent action panel flex grow and allow table container to shrink

Use ID selector on #action-container for higher specificity (1-1-0)
over Container.vue scoped .container (0-2-0), add flex: none to prevent
growing. Add min-width: 0 and remove width: 100% on charging stations
container to allow flex shrink below table content width.

3 days agorefactor(webui): css quality overhaul with scoped styles, class selectors, design...
Jérôme Benoit [Sat, 21 Mar 2026 15:46:55 +0000 (16:46 +0100)] 
refactor(webui): css quality overhaul with scoped styles, class selectors, design tokens

- add scoped to all 12 Vue component style blocks
- move body/app global styles to index.html
- replace all 33 ID CSS selectors with class selectors
- add :deep() for parent-child table style propagation
- add spacing scale and typography tokens to all themes
- replace magic number percentages with spacing variables
- add :focus-visible styles for buttons and select
- replace hardcoded form widths with max-width constraints
- use gap for flex toolbar spacing
- remove dead CSS

3 days agofix(ocpp2.0): add proper response handlers for certificate commands + handler coverag...
Jérôme Benoit [Fri, 20 Mar 2026 20:39:36 +0000 (21:39 +0100)] 
fix(ocpp2.0): add proper response handlers for certificate commands + handler coverage tests

Replace emptyResponseHandler with proper logging handlers for
Get15118EVCertificate, GetCertificateStatus, and SignCertificate
responses. Add handler registration coverage tests for both OCPP 1.6
and 2.0: every RequestCommand must have a response handler, every
IncomingRequestCommand must have an incoming request handler.

3 days agofeat(ocpp2.0): implement Authorize request, fix double TransactionEvent(Started)
Jérôme Benoit [Fri, 20 Mar 2026 20:07:05 +0000 (21:07 +0100)] 
feat(ocpp2.0): implement Authorize request, fix double TransactionEvent(Started)

OCPP20AuthAdapter.authorizeRemote() was incorrectly sending a
TransactionEvent(Started) as a proxy for authorization, causing a
duplicate Started event when ATG subsequently called
startTransactionOnConnector(). Implement the proper OCPP 2.0.1
Authorize request/response flow, harmonizing the auth+start sequence
with OCPP 1.6: Authorize first, then TransactionEvent(Started).

3 days agofix(ocpp2.0): guard BroadcastChannel MeterValues for both VERSION_20 and VERSION_201
Jérôme Benoit [Fri, 20 Mar 2026 19:10:38 +0000 (20:10 +0100)] 
fix(ocpp2.0): guard BroadcastChannel MeterValues for both VERSION_20 and VERSION_201

The early return in handleMeterValues only checked VERSION_201, missing
VERSION_20. A station configured with ocppVersion '2.0' would fall
through to the OCPP 1.6 path and call convertToInt on a UUID string.

3 days agofix(ocpp2.0): pass real transactionId to buildMeterValue for energy accumulation
Jérôme Benoit [Fri, 20 Mar 2026 19:05:22 +0000 (20:05 +0100)] 
fix(ocpp2.0): pass real transactionId to buildMeterValue for energy accumulation

buildMeterValue was called with transactionId=0 for OCPP 2.0 stations,
but transaction IDs are UUID strings in 2.0.1. The energy lookup
compared 'uuid-string' === 0, always returning 0 Wh. Pass the actual
connectorStatus.transactionId and widen the parameter type to
number | string | undefined.

3 days agorefactor(webui): restore native table layout to fix column overlap on action panel...
Jérôme Benoit [Fri, 20 Mar 2026 19:00:23 +0000 (20:00 +0100)] 
refactor(webui): restore native table layout to fix column overlap on action panel open

Replace display:flex overrides on <table>/<tr>/<td> with native HTML table
layout. Add overflow-x:auto wrapper with min-width floor so columns scroll
horizontally instead of compressing and overlapping when the action panel
reduces available width.

3 days agofix(auth): log actual station OCPP version in RemoteAuthStrategy
Jérôme Benoit [Fri, 20 Mar 2026 18:49:23 +0000 (19:49 +0100)] 
fix(auth): log actual station OCPP version in RemoteAuthStrategy

Deduplicate adapter validation in initialize() to avoid logging the
same adapter twice for VERSION_20/VERSION_201 aliases. Add ocppVersion
to AuthConfiguration so strategies log the station's configured version
instead of internal map keys.

3 days agofix(ocpp2.0): align VARIABLE_REGISTRY spec conformance and log severity
Jérôme Benoit [Fri, 20 Mar 2026 18:23:38 +0000 (19:23 +0100)] 
fix(ocpp2.0): align VARIABLE_REGISTRY spec conformance and log severity

Distinguish required vs optional variables per OCPP 2.0.1 spec
(dm_components_vars.csv). Missing required variables log as error,
missing optional ones as warning. Tag 58 spec-required entries with
required: true and 6 non-spec entries with vendorSpecific: true.

4 days agofix(deps): update all non-major dependencies (#1739)
renovate[bot] [Fri, 20 Mar 2026 17:10:41 +0000 (18:10 +0100)] 
fix(deps): update all non-major dependencies (#1739)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
4 days agorefactor: build version-agnostic OCPP transaction primitives in service layer (#1741)
Jérôme Benoit [Fri, 20 Mar 2026 17:07:17 +0000 (18:07 +0100)] 
refactor: build version-agnostic OCPP transaction primitives in service layer (#1741)

* refactor: add StopTransactionResult type and OCPP 2.0 reason mapping

* refactor: extract OCPP 1.6 stopTransactionOnConnector to OCPP16ServiceUtils

* refactor: add unified stopTransactionOnConnector and stopRunningTransactions to OCPPServiceUtils

Add two version-dispatching functions to OCPPServiceUtils:

- stopTransactionOnConnector: dispatches to OCPP16ServiceUtils or
  OCPP20ServiceUtils via dynamic import, returns StopTransactionResult
- stopRunningTransactions: sequential for OCPP 1.6, parallel (Promise.all)
  for OCPP 2.0, includes transactionPending check for OCPP 2.0

Both use dynamic imports to avoid circular dependencies. stopRunningTransactions
is exposed as OCPPServiceUtils.stopRunningTransactions class member.
stopTransactionOnConnector is exported as standalone function only (class member
omitted due to OCPP16ServiceUtils override type conflict).

Includes 6 tests covering both OCPP versions and error cases.

* refactor: simplify ChargingStation and ATG to use OCPPServiceUtils unified methods

- ChargingStation.stopRunningTransactions: delegate to standalone function from OCPPServiceUtils
- Remove ChargingStation.stopRunningTransactionsOCPP20 private method (logic now in standalone function)
- Remove OCPP20ReasonEnumType import from ChargingStation (no longer needed)
- AutomaticTransactionGenerator.stopTransaction: call stopTransactionOnConnector standalone function
- Update ATG return type to Promise<StopTransactionResult | undefined>
- Use result.accepted instead of stopResponse.idTagInfo?.status === AuthorizationStatus.ACCEPTED
- Remove TODO comment from ATG.stopTransaction

* refactor: remove stopTransactionOnConnector from ChargingStation public API

* refactor: remove stopTransactionOnConnector from ChargingStation public API

- Remove ChargingStation.stopTransactionOnConnector public method
- Remove unused StopTransactionRequest, StopTransactionResponse, buildTransactionEndMeterValue, OCPP16ServiceUtils imports from ChargingStation
- Update OCPP16IncomingRequestService.handleRequestUnlockConnector to call OCPP16ServiceUtils.stopTransactionOnConnector directly
- Update test mocks in RemoteStopUnlock tests to target OCPP16ServiceUtils
- Fix OCPPServiceUtils-StopTransaction test: use args-based pattern for command detection, add proper JSDoc, fix type issues

* refactor(ocpp2.0): deduplicate stop pattern via stopAllTransactions

- Add OCPP20ServiceUtils.stopAllTransactions() — single factored function for parallel
  EVSE iteration + requestStopTransaction, supports optional evseId for single-EVSE scope
- terminateAllTransactions delegates to stopAllTransactions(station, ResetCommand, reason)
- terminateEvseTransactions delegates to stopAllTransactions(station, ResetCommand, reason, evseId)
- stopRunningTransactions OCPP 2.0 path delegates to stopAllTransactions(station, trigger, stopped)
- Eliminates 3x duplicated iteration+parallel-stop pattern

* refactor: add startTransactionOnConnector and flushQueuedTransactionMessages abstractions

- Add startTransactionOnConnector to OCPPServiceUtils (version dispatch via dynamic imports)
  OCPP 1.6: sends START_TRANSACTION via new OCPP16ServiceUtils.startTransactionOnConnector
  OCPP 2.0: sends TransactionEvent(Started) via OCPP20ServiceUtils.sendTransactionEvent
  Returns StartTransactionResult { accepted: boolean }
- Add flushQueuedTransactionMessages to OCPPServiceUtils (OCPP 1.6: no-op, OCPP 2.0: flushes queue)
- Migrate ATG startTransaction to use startTransactionOnConnector (fixes OCPP 2.0 ATG start)
- Migrate ATG handleStartTransactionResponse to handleStartTransactionResult (uses unified type)
- Remove ATG dependency on AuthorizationStatus, RequestCommand, StartTransactionRequest/Response
- Remove ChargingStation.flushQueuedTransactionEvents private method
- Remove version check in ChargingStation boot handler (line 2304)
- Add StartTransactionResult type to types barrel

* refactor: extract periodic meter values to OCPP service layer

- Add OCPP16ServiceUtils.startPeriodicMeterValues/stopPeriodicMeterValues
- Add OCPP20ServiceUtils.startPeriodicMeterValues/stopPeriodicMeterValues
- Add OCPPServiceUtils.startPeriodicMeterValues/stopPeriodicMeterValues (version dispatch)
- Remove startMeterValues, stopMeterValues, startTxUpdatedInterval, stopTxUpdatedInterval,
  restartMeterValues from ChargingStation.ts
- Migrate all callers to use versioned ServiceUtils methods
- Fix test referencing removed startTxUpdatedInterval method
- ChargingStation.ts: -130 lines of version-specific meter values logic removed

* fix: update tests for renamed APIs and removed ChargingStation methods

- AutomaticTransactionGenerator.test.ts: handleStartTransactionResponse -> handleStartTransactionResult, use StartTransactionResult { accepted } instead of StartTransactionResponse
- ChargingStation-Transactions.test.ts: test already uses OCPP16ServiceUtils.stopPeriodicMeterValues
- OCPP20ServiceUtils-TransactionEvent.test.ts: startTxUpdatedInterval -> startPeriodicMeterValues
- StationHelpers.ts: remove stopMeterValues, startMeterValues, startTxUpdatedInterval, stopTxUpdatedInterval, restartMeterValues from mock (no longer on ChargingStation)
- OCPP16ServiceUtils.stopPeriodicMeterValues: add missing delete after clearInterval

* fix: correct startPeriodicMeterValues test to verify no-transaction guard instead of version guard

* fix: guard undefined evseId and avoid throw in shutdown paths

- stopTransactionOnConnector: guard getEvseIdByConnectorId returning undefined, return { accepted: false } with warn log
- stopRunningTransactions: replace throw with warn log in default branch (shutdown path must not crash)

* fix: deduplicate test coverage and address review findings

- Remove ChargingStation-StopRunningTransactions.test.ts (duplicated coverage with OCPPServiceUtils-StopTransaction.test.ts)
- Move error handling test to OCPPServiceUtils-StopTransaction.test.ts
- Guard undefined evseId in stopTransactionOnConnector (review finding)
- Replace throw with warn in stopRunningTransactions default branch (review finding)

* fix: generate transactionId for OCPP 2.0 start and align offline stop acceptance

- startTransactionOnConnector OCPP 2.0: generate UUID transactionId and reset seqNo when
  connector has no transactionId (ATG path)
- stopTransactionOnConnector OCPP 2.0: treat missing idTokenInfo as accepted (offline queued
  events return undefined idTokenInfo, consistent with startTransactionOnConnector)

* fix: map Other reason correctly and use static generateUUID import

- mapStopReasonToOCPP20: add explicit Other -> Other/AbnormalCondition mapping
  instead of falling through to Local/StopAuthorized
- startTransactionOnConnector: use statically imported generateUUID instead of
  unnecessary dynamic import (utils/index.js already imported at top of file)

* test: add coverage for startTransactionOnConnector, flushQueuedTransactionMessages, and mapStopReasonToOCPP20

- startTransactionOnConnector: OCPP 1.6 accepted, OCPP 2.0 accepted, OCPP 2.0 UUID generation
- flushQueuedTransactionMessages: OCPP 1.6 no-op, OCPP 2.0 flush queued events
- mapStopReasonToOCPP20: Other, undefined, Remote mappings

* refactor: remove stopRunningTransactions indirection in ChargingStation

Call stopRunningTransactions(this, reason) directly instead of through
a private method that only delegates.

4 days agofix(ocpp2.0): make stopRunningTransactions version-aware for OCPP 2.0
Jérôme Benoit [Thu, 19 Mar 2026 17:59:42 +0000 (18:59 +0100)] 
fix(ocpp2.0): make stopRunningTransactions version-aware for OCPP 2.0

4 days agorefactor(ocpp2.0): parameterize requestStopTransaction triggerReason and stoppedReason
Jérôme Benoit [Thu, 19 Mar 2026 17:49:02 +0000 (18:49 +0100)] 
refactor(ocpp2.0): parameterize requestStopTransaction triggerReason and stoppedReason

4 days agofix(ocpp2.0): reset transaction sequence number before new transaction per E01.FR.07
Jérôme Benoit [Thu, 19 Mar 2026 17:41:30 +0000 (18:41 +0100)] 
fix(ocpp2.0): reset transaction sequence number before new transaction per E01.FR.07

4 days agofix(ocpp2.0): inject offline:true in sendTransactionEvent offline path per E04.FR.03
Jérôme Benoit [Thu, 19 Mar 2026 17:29:44 +0000 (18:29 +0100)] 
fix(ocpp2.0): inject offline:true in sendTransactionEvent offline path per E04.FR.03

5 days agorefactor(webui): harmonize barrel usage in types and composables
Jérôme Benoit [Thu, 19 Mar 2026 15:27:49 +0000 (16:27 +0100)] 
refactor(webui): harmonize barrel usage in types and composables

Add OCPP16AvailabilityType, OCPP16ChargePointStatus, and
OCPP16RegistrationStatus to the types barrel. Redirect all direct
module imports in tests to use barrels (types/, composables/).

5 days agofix: merge duplicate node:process imports in Utils.test.ts
Jérôme Benoit [Thu, 19 Mar 2026 15:21:43 +0000 (16:21 +0100)] 
fix: merge duplicate node:process imports in Utils.test.ts

5 days agofix: merge duplicate type imports from same barrel module
Jérôme Benoit [Thu, 19 Mar 2026 15:18:42 +0000 (16:18 +0100)] 
fix: merge duplicate type imports from same barrel module

Consolidate split import type statements from types/index.js into
single imports in OCPP16TestUtils.ts and OCPP20IncomingRequestService-
MasterPass.test.ts.

5 days agorefactor: harmonize barrel usage across all test files
Jérôme Benoit [Thu, 19 Mar 2026 15:11:03 +0000 (16:11 +0100)] 
refactor: harmonize barrel usage across all test files

Redirect all direct module imports (utils/Logger, utils/Constants,
worker/WorkerTypes, types/*, charging-station/ChargingStation) to
their respective barrel index.js in test files. Unit tests of the
module itself retain direct imports per convention.

5 days agofix: use exception barrel instead of direct module imports
Jérôme Benoit [Thu, 19 Mar 2026 14:58:59 +0000 (15:58 +0100)] 
fix: use exception barrel instead of direct module imports

Redirect OCPPError imports from exception/OCPPError.js to the barrel
exception/index.js in auth services and OCPP20 test utils.

5 days agofix(ocpp): keep StopTransactionRequest as 1.6 wire type, narrow reason via indexed...
Jérôme Benoit [Thu, 19 Mar 2026 14:53:24 +0000 (15:53 +0100)] 
fix(ocpp): keep StopTransactionRequest as 1.6 wire type, narrow reason via indexed access

Revert the Omit-based widening of StopTransactionRequest — it's a 1.6
wire protocol message and should not accept OCPP 2.0 reason values.
Use StopTransactionRequest['reason'] indexed access type for narrowing
in ChargingStation, avoiding any version-specific OCPP16* import.

5 days agofix(ocpp): remove type re-export from services barrel
Jérôme Benoit [Thu, 19 Mar 2026 14:42:59 +0000 (15:42 +0100)] 
fix(ocpp): remove type re-export from services barrel

Move OCPP20TransactionEventEnumType and OCPP20TriggerReasonEnumType
imports in ChargingStation.ts from the services barrel (ocpp/index.ts)
to the types barrel (types/index.ts) where they belong.

5 days agorefactor(ocpp): consolidate cross-stack types and harmonize barrel imports
Jérôme Benoit [Thu, 19 Mar 2026 14:24:42 +0000 (15:24 +0100)] 
refactor(ocpp): consolidate cross-stack types and harmonize barrel imports

Consolidate OCPP types with common semantics across 1.6 and 2.0 stacks
(AuthorizationStatus, StopTransactionReason, MessageTrigger, DataTransfer,
TriggerMessageStatus, UnlockStatus, AvailabilityStatus, HeartbeatRequest/
Response, StatusNotificationResponse, FirmwareStatusNotificationResponse).

Harmonize all imports across src/ and tests/ to use the barrel
(types/index.ts) instead of direct version-specific type paths, matching
the pattern already established by the OCPP 1.6 handlers.

5 days agochore(ocpp-server): add .coverage to .gitignore
Jérôme Benoit [Thu, 19 Mar 2026 11:59:29 +0000 (12:59 +0100)] 
chore(ocpp-server): add .coverage to .gitignore

5 days agotest(ocpp-server): add coverage threshold (fail_under=83%)
Jérôme Benoit [Thu, 19 Mar 2026 11:58:01 +0000 (12:58 +0100)] 
test(ocpp-server): add coverage threshold (fail_under=83%)

5 days agotest(ui): raise coverage thresholds to match current levels
Jérôme Benoit [Thu, 19 Mar 2026 11:55:08 +0000 (12:55 +0100)] 
test(ui): raise coverage thresholds to match current levels

statements: 87→91, branches: 85→89, functions: 80→83, lines: 87→91

5 days agotest(webui): add comprehensive unit test suite (#1738)
Jérôme Benoit [Thu, 19 Mar 2026 11:39:02 +0000 (12:39 +0100)] 
test(webui): add comprehensive unit test suite (#1738)

* test(webui): add test infrastructure and setup

* test(webui): add Utils composable tests

* test(webui): refactor and expand UIClient tests

* test(webui): add action modal component tests

* test(webui): fix JSDoc warnings in mount factory functions

* test(webui): add ChargingStationsView tests

* [autofix.ci] apply automated fixes

* test(webui): finalize coverage and verify quality gates

* test(webui): harmonize test infrastructure — extract ButtonStub, unify toast mock, DRY error tests

* test(webui): add missing coverage for timeout, server switching, authorize errors, WS states

* test(webui): raise coverage thresholds to match achieved 93%/91%/85%/93%

* test(webui): address PR review — unify mock cleanup, improve MockWebSocket fidelity, fix types

* test(webui): adapt tests for new OCPP Version column

* test(webui): remove MockWebSocket auto-open, robustify component lookups, add open assertion

* test(webui): init MockWebSocket readyState to CONNECTING per WebSocket spec

* fix(webui): use window.localStorage for Node 22+ jsdom compatibility

* fix(webui): disable Node 25+ native webstorage to prevent jsdom localStorage conflict

* test(webui): await router.isReady() in App mount test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
5 days agorefactor(ocpp2): harmonize and condense audit comments to match existing FR style
Jérôme Benoit [Thu, 19 Mar 2026 11:29:15 +0000 (12:29 +0100)] 
refactor(ocpp2): harmonize and condense audit comments to match existing FR style

5 days agofix(ocpp2): audit TransactionEvent — state ownership, deauthorization, meter values
Jérôme Benoit [Thu, 19 Mar 2026 11:17:44 +0000 (12:17 +0100)] 
fix(ocpp2): audit TransactionEvent — state ownership, deauthorization, meter values

- Fix periodic TransactionEvent(Updated) to include meter values via buildMeterValue
- Replace non-UUID temp transactionId with generateUUID in OCPP20AuthAdapter
- Refactor state ownership: response handler is sole authority for transactionStarted,
  StatusNotification(Occupied), and TxUpdatedInterval start
- Add transactionPending flag to prevent duplicate RequestStartTransaction race conditions
- Add requestDeauthorizeTransaction per E05.FR.09/FR.10/E06.FR.04: sends
  Updated(Deauthorized, SuspendedEVSE) then Ended(Deauthorized, DeAuthorized)
- Fix rejection check to cover all non-Accepted idTokenInfo statuses
- Extract buildFinalMeterValues helper to eliminate DRY violation
- Skip Occupied/TxUpdatedInterval setup when idToken is rejected in same response
- Remove cleanup from Ended response handler (owned by caller)
- Add tests for getTxUpdatedInterval, requestDeauthorizeTransaction, Updated-failure path

5 days agochore(deps): update dependency vue-tsc to v3 (#1740)
renovate[bot] [Thu, 19 Mar 2026 09:34:33 +0000 (10:34 +0100)] 
chore(deps): update dependency vue-tsc to v3 (#1740)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
5 days agofix(ocpp2): handle transaction lifecycle in TransactionEvent response
Jérôme Benoit [Thu, 19 Mar 2026 00:08:33 +0000 (01:08 +0100)] 
fix(ocpp2): handle transaction lifecycle in TransactionEvent response

Adapt the OCPP 1.6 transaction lifecycle pattern to OCPP 2.0: manage
connector state (transactionStarted, transactionId, StatusNotification,
meter intervals) in handleResponseTransactionEvent for both Started
and Ended events, matching handleResponseStartTransaction and
handleResponseStopTransaction in OCPP 1.6.

5 days agofeat(ui): add SAP Horizon theme from official theming-base-content
Jérôme Benoit [Wed, 18 Mar 2026 23:47:16 +0000 (00:47 +0100)] 
feat(ui): add SAP Horizon theme from official theming-base-content

Map SAP Horizon palette to semantic tokens using values from
SAP/theming-base-content sap_horizon css_variables.css.

5 days agofix(ui): use theme text color on toggle pressed state for readability
Jérôme Benoit [Wed, 18 Mar 2026 23:44:23 +0000 (00:44 +0100)] 
fix(ui): use theme text color on toggle pressed state for readability

White text on light Surface backgrounds was illegible in Catppuccin
Latte. Using --color-text adapts to both light and dark themes.

5 days agodocs(ui): document theme configuration and available themes
Jérôme Benoit [Wed, 18 Mar 2026 23:35:02 +0000 (00:35 +0100)] 
docs(ui): document theme configuration and available themes

5 days agofeat(ui): add Catppuccin Latte light theme
Jérôme Benoit [Wed, 18 Mar 2026 23:32:29 +0000 (00:32 +0100)] 
feat(ui): add Catppuccin Latte light theme

Map Catppuccin Latte palette to semantic tokens following the official
style guide: Base for background, Mantle/Crust for secondary panes,
Surface 0/1 for hover/active, Blue for buttons/links, Lavender for
accent, Base for text-on-button (On Accent per guide).

5 days agofix(ui): remove redundant text color selectors that override toast styles
Jérôme Benoit [Wed, 18 Mar 2026 23:27:55 +0000 (00:27 +0100)] 
fix(ui): remove redundant text color selectors that override toast styles

The h1-h3/p/li selectors were unnecessary (body color is inherited)
and caused vue-toast-notification text to appear grey instead of white.

5 days agofeat(ui): add configurable theme support
Jérôme Benoit [Wed, 18 Mar 2026 23:23:29 +0000 (00:23 +0100)] 
feat(ui): add configurable theme support

Add theme field to ConfigurationData. Theme CSS files are loaded
dynamically from assets/themes/ at startup. Falls back to
tokyo-night-storm when not configured or theme not found.

Move theme.css to assets/themes/tokyo-night-storm.css.

5 days agofeat(ui): apply Tokyo Night Storm theme with semantic CSS tokens
Jérôme Benoit [Wed, 18 Mar 2026 23:14:13 +0000 (00:14 +0100)] 
feat(ui): apply Tokyo Night Storm theme with semantic CSS tokens

Add theme.css with two-layer token system: primitive tokens from
the official Tokyo Night Storm palette, semantic tokens mapping UI
roles to primitives. All components use semantic tokens exclusively.

Replace all hardcoded colors across 13 Vue components. Theme native
HTML elements (button, input, select, a, headings) globally. Toggle
button pressed state uses palette-semantic active bg + accent border
+ inset shadow for clear visual distinction.

Remove dead code: simulatorButtonClass computed and associated CSS
classes that duplicated global button styles.

5 days agofeat(ui): add OCPP version column to charging stations table
Jérôme Benoit [Wed, 18 Mar 2026 22:25:38 +0000 (23:25 +0100)] 
feat(ui): add OCPP version column to charging stations table

Display ocppVersion from stationInfo between Registration Status and
Template columns.

5 days agofix: use truncateId consistently for all user identifiers in logs
Jérôme Benoit [Wed, 18 Mar 2026 22:21:10 +0000 (23:21 +0100)] 
fix: use truncateId consistently for all user identifiers in logs

Replace 16 bare idTag/identifier.value references and 4 manual
substring(0,8) truncations with truncateId() across OCPP 1.6
ResponseService, IncomingRequestService, auth adapters, strategies,
and helpers.

User identifiers (RFID tags, auth tokens) are now consistently
truncated in all log output to prevent sensitive data exposure.

5 days agofix: preserve EVSE and connector IDs in configuration persistence
Jérôme Benoit [Wed, 18 Mar 2026 22:00:00 +0000 (23:00 +0100)] 
fix: preserve EVSE and connector IDs in configuration persistence

Serialization (buildConnectorsStatus, buildEvsesStatus) now saves
[id, status] tuples instead of flat arrays, preserving EVSE and
connector IDs per OCPP 2.0.1 §7.

Deserialization detects both formats transparently: new tuple format
uses explicit IDs, legacy flat array format falls back to array index.

Add checkEvsesConfiguration template validation enforcing §7.2
connector numbering (EVSE 0: connector 0 only, EVSE ≥1: connectors
start at 1).

Add tests for ID preservation across serialization for both connectors
and EVSEs.

5 days agofix: prevent tests from polluting production log files
Jérôme Benoit [Wed, 18 Mar 2026 20:33:51 +0000 (21:33 +0100)] 
fix: prevent tests from polluting production log files

Set NODE_ENV=test via cross-env in all three test scripts (test,
test:debug, test:coverage). Logger checks NODE_ENV and sets silent
mode, preventing file writes to logs/combined.log and logs/error.log
during test runs.

5 days agotest: move truncateId tests from InMemoryAuthCache to Utils
Jérôme Benoit [Wed, 18 Mar 2026 20:07:13 +0000 (21:07 +0100)] 
test: move truncateId tests from InMemoryAuthCache to Utils

truncateId is a general utility function in src/utils/, not a cache
feature. Its tests belong in the utils test file.

5 days agofix(ocpp): replace this.constructor.name with moduleName in base class logs
Jérôme Benoit [Wed, 18 Mar 2026 19:53:19 +0000 (20:53 +0100)] 
fix(ocpp): replace this.constructor.name with moduleName in base class logs

Minification mangles class names, causing logs like 'ln.responseHandler'
instead of 'OCPP20ResponseService.responseHandler' in production builds.

Add abstract moduleName property to OCPPResponseService and
OCPPIncomingRequestService base classes, implemented by all four
subclasses using their file-level moduleName constant.

5 days agorefactor(test): remove duplicate certificate passthrough tests from broadcast channel
Jérôme Benoit [Wed, 18 Mar 2026 19:04:12 +0000 (20:04 +0100)] 
refactor(test): remove duplicate certificate passthrough tests from broadcast channel

These 3 tests duplicated coverage already provided by
OCPP20RequestService-ISO15118.test.ts which tests the same code path
through the full requestHandler pipeline.

Add JSDoc descriptions to buildTransactionEvent implementation to
satisfy jsdoc/require-param-description lint rule.

5 days agotest(ocpp): add call chain integration tests for both OCPP stacks
Jérôme Benoit [Wed, 18 Mar 2026 18:49:02 +0000 (19:49 +0100)] 
test(ocpp): add call chain integration tests for both OCPP stacks

Verify the single-path contract: requestHandler(minimal params) →
buildRequestPayload(constructs) → sendMessage(complete payload).

OCPP 2.0: StatusNotification, TransactionEvent (with default resolution
for triggerReason, transactionId, connectorId from evse), Heartbeat,
and rawPayload bypass.

OCPP 1.6: StatusNotification (errorCode added by builder),
StartTransaction (meterStart/timestamp enrichment), StopTransaction
(meterStop/timestamp enrichment), Heartbeat.

Remove deleted TransactionContextFixtures from TEST_STYLE_GUIDE.

5 days agorefactor(ocpp2): extract buildTransactionEvent as standalone function, remove dead...
Jérôme Benoit [Wed, 18 Mar 2026 18:32:25 +0000 (19:32 +0100)] 
refactor(ocpp2): extract buildTransactionEvent as standalone function, remove dead context code

Extract buildTransactionEvent from OCPP20ServiceUtils static method to
exported standalone function, consistent with buildStatusNotificationRequest
and buildMeterValue.

Remove unused context overload from buildTransactionEvent and
sendTransactionEvent — all production callers pass triggerReason directly.

Remove dead code: OCPP20TransactionContext interface (not in OCPP 2.0.1
specs), selectTriggerReason method, TransactionContextFixtures, and
associated tests.

6 days agorefactor(ocpp): add rawPayload bypass, resolve minimal params in buildRequestPayload...
Jérôme Benoit [Wed, 18 Mar 2026 16:59:56 +0000 (17:59 +0100)] 
refactor(ocpp): add rawPayload bypass, resolve minimal params in buildRequestPayload, fix test types

Add rawPayload option to RequestParams for offline queue replay to
explicitly bypass buildRequestPayload instead of heuristic detection.

Make buildRequestPayload resolve missing TransactionEvent fields from
station context (connectorId from evse, transactionId generation,
triggerReason defaults) so the broadcast channel passthrough works.

Remove pre-built payload guard from OCPP 1.6 STATUS_NOTIFICATION.

Replace Record<string, unknown> downgrades in tests with proper OCPP
types (Partial<OCPP20TransactionEventRequest>, RequestParams).

6 days agorefactor(ocpp): make buildRequestPayload the authoritative builder for all commands
Jérôme Benoit [Wed, 18 Mar 2026 16:13:49 +0000 (17:13 +0100)] 
refactor(ocpp): make buildRequestPayload the authoritative builder for all commands

buildRequestPayload now calls the centralized builders for
TRANSACTION_EVENT (via buildTransactionEvent) and STATUS_NOTIFICATION
(via buildStatusNotificationRequest) in both OCPP versions, matching
the existing pattern for START_TRANSACTION/STOP_TRANSACTION in 1.6.

Callers pass minimal params (eventType, connectorId, status, etc.)
and buildRequestPayload constructs the complete spec-compliant payload.

sendTransactionEvent's offline path builds directly for queueing since
the queue stores pre-built payloads sent as-is on reconnect.

6 days agorefactor(ocpp): use buildStatusNotificationRequest helper in TriggerMessage handlers
Jérôme Benoit [Wed, 18 Mar 2026 15:03:31 +0000 (16:03 +0100)] 
refactor(ocpp): use buildStatusNotificationRequest helper in TriggerMessage handlers

Replace inline StatusNotification payload construction in both OCPP 1.6
and 2.0 TriggerMessage handlers with the centralized
buildStatusNotificationRequest helper. Export the helper from
OCPPServiceUtils to make it available.

This eliminates 5 inline duplications of the same payload structure
that risked diverging from the single source of truth.

6 days agorefactor(ocpp): harmonize buildRequestPayload switch structure across versions
Jérôme Benoit [Wed, 18 Mar 2026 14:49:05 +0000 (15:49 +0100)] 
refactor(ocpp): harmonize buildRequestPayload switch structure across versions

Group passthrough cases into fall-through blocks in both OCPP 1.6 and
2.0 buildRequestPayload, giving both files a symmetric structure:
grouped passthroughs, heartbeat empty object, enrichment cases, default
error.

6 days agofix(ocpp2): revert UI transaction handlers to simple passthrough
Jérôme Benoit [Wed, 18 Mar 2026 14:35:41 +0000 (15:35 +0100)] 
fix(ocpp2): revert UI transaction handlers to simple passthrough

Remove handleUIStartTransaction and handleUIStopTransaction which
duplicated connector state management with incomplete initialization
(missing energy register, groupIdToken, StatusNotification, error
rollback) and bypassed authorization checks.

Restore handleTransactionEvent as a simple requestHandler passthrough,
consistent with all other broadcast channel command handlers.

6 days agorefactor(ocpp2): remove redundant getTxUpdatedInterval wrapper
Jérôme Benoit [Wed, 18 Mar 2026 14:24:06 +0000 (15:24 +0100)] 
refactor(ocpp2): remove redundant getTxUpdatedInterval wrapper

Call OCPP20ServiceUtils.getTxUpdatedInterval() directly from
OCPP20IncomingRequestService instead of through a trivial private
wrapper that was left over from the centralization in PR #1734.

6 days agorefactor(ocpp2): consolidate dual-path request architecture into single path
Jérôme Benoit [Wed, 18 Mar 2026 14:16:54 +0000 (15:16 +0100)] 
refactor(ocpp2): consolidate dual-path request architecture into single path

Remove 8 unused dedicated request methods (requestFirmwareStatusNotification,
requestGet15118EVCertificate, requestGetCertificateStatus, etc.) that bypassed
buildRequestPayload via direct sendMessage calls. All production callers
already used requestHandler exclusively, making these methods dead code.

Move SignCertificate CSR generation logic into buildRequestPayload, making
it the authoritative payload construction layer — symmetric with OCPP 1.6.
This also adds isRequestCommandSupported check and AJV schema validation
to the SignCertificate flow that the dedicated method bypassed.

Refactor 6 test files to test through requestHandler (production path)
instead of the removed dedicated methods.

6 days agorefactor(ocpp2): centralize payload construction and eliminate duplication
Jérôme Benoit [Wed, 18 Mar 2026 13:44:59 +0000 (14:44 +0100)] 
refactor(ocpp2): centralize payload construction and eliminate duplication

Remove redundant timestamp injection from buildRequestPayload() for
StatusNotification and TransactionEvent — centralized builders already
provide timestamps and AJV schema validation catches any omission.

Extract buildStationInfoReportData() helper to deduplicate station info
report data construction between FullInventory and SummaryInventory in
buildReportData().

Normalize TriggerMessage Heartbeat to use OCPP20Constants.OCPP_RESPONSE_EMPTY
for consistency with buildRequestPayload().

6 days agofeat(ui): add OCPP 2.0.x command support to Web UI (#1734)
Jérôme Benoit [Wed, 18 Mar 2026 13:34:49 +0000 (14:34 +0100)] 
feat(ui): add OCPP 2.0.x command support to Web UI (#1734)

* feat(ui): add OCPP 2.0.x types and sync ProcedureName enum

- Add OCPP 2.0.x-specific procedures to ProcedureName enum:
  TRANSACTION_EVENT, GET_15118_EV_CERTIFICATE, GET_CERTIFICATE_STATUS,
  LOG_STATUS_NOTIFICATION, NOTIFY_CUSTOMER_INFORMATION, NOTIFY_REPORT,
  SECURITY_EVENT_NOTIFICATION, SIGN_CERTIFICATE

- Add OCPP 2.0.x type definitions:
  - OCPP20IdTokenEnumType (8 values)
  - OCPP20TransactionEventEnumType (Ended, Started, Updated)
  - OCPP20IdTokenType interface
  - OCPP20TransactionEventRequest interface

- Update ConnectorStatus.transactionId to support both number (OCPP 1.6)
  and string/UUID (OCPP 2.0.x)

Wave 1 complete.

* feat(ui): add UIClient transaction methods with OCPP version support

- Add transactionEvent() method for OCPP 2.0.x TransactionEvent requests
- Add isOCPP20x() static helper for version detection
- Add startTransactionForVersion() helper that routes to appropriate
  method based on OCPP version (1.6 vs 2.0.x)
- Add stopTransactionForVersion() helper for version-aware stop
- Add comprehensive unit tests (16 tests passing)

Wave 2 complete.

* feat(ui): add version-aware StartTransaction form with OCPP 2.0.x support

- Modify StartTransaction.vue to detect OCPP version from station info
- Show connector ID for OCPP 1.6, EVSE ID input for OCPP 2.0.x
- Hide Authorize checkbox for OCPP 2.0.x stations (v-if)
- Use startTransactionForVersion() helper for version-aware API calls
- Add loading state while fetching station info
- Show appropriate form fields based on OCPP version
- All 16 tests passing

Wave 3 complete.

* fix(webui): use enums instead of string literals for OCPP 2.0.x types

- Replace 'ISO14443' string with OCPP20IdTokenEnumType.ISO14443

- Fix test mocks to use Protocol.UI and ResponseStatus.SUCCESS enums

- Export OCPP20IdTokenEnumType from types index

* style(webui): fix import ordering in UIClient.ts

* [autofix.ci] apply automated fixes

* chore: remove tsbuildinfo and add to gitignore

* fix(webui): address PR review comments

- Add ResponseStatus import and use enum instead of string

- Use UIClient.isOCPP20x() helper instead of manual comparison

- Remove redundant showAuthorize computed, use !isOCPP20x directly

- Fix authorizeIdTag checkbox binding (remove true-value/false-value)

- Initialize evseId from props.connectorId

- Separate error handling for authorize vs startTransaction

- Add validation for transactionId type in stopTransactionForVersion

* [autofix.ci] apply automated fixes

* chore: move tsbuildinfo gitignore to ui/web subdirectory

- Remove *.tsbuildinfo from root .gitignore

- Add *.tsbuildinfo to ui/web/.gitignore with proper comment

* ci(webui): add TypeScript type checking to CI

- Add vue-tsc dev dependency to ui/web

- Add typecheck script to package.json

- Add typecheck step to build-dashboard job in CI

* fix(webui): fix vue-tsc typecheck and improve Vue.js best practices

- Break recursive JsonObject/JsonType chain causing TS2589 in vue-tsc
- Fix CSConnector to use stopTransactionForVersion with ocppVersion prop
- Replace getCurrentInstance() anti-pattern with useToast()/useRouter()
- Make isOCPP20x a computed instead of manually-synced ref
- Deduplicate handleStartTransaction (remove ~30 lines of duplication)
- Add null guards for watch() on potentially undefined global refs

* [autofix.ci] apply automated fixes

* refactor(webui): align namespace with simulator and improve API design

- Merge startTransactionForVersion/stopTransactionForVersion into
  startTransaction/stopTransaction with optional ocppVersion param
- Make transactionEvent private (implementation detail, not public API)
- Revert UITransactionEventPayload to OCPP20TransactionEventRequest
  to match backend naming convention
- Pass ocppVersion via route param instead of re-fetching all stations
- Remove convertToBoolean no-op and loading state
- Flip negated v-if condition for SonarCloud compliance
- Factor test setup, remove duplicate coverage, add missing test case
- Net result: -90 lines, cleaner API surface

* [autofix.ci] apply automated fixes

* refactor(webui): move tests from __tests__ to tests/unit for consistency

Align test file location with existing project convention (tests/unit/)
instead of Jest-style __tests__ directory.

* feat(webui): integrate OCPP 2.0 EVSE 3-tier model across web UI

- Add OCPP20EVSEType matching spec EVSEType {id, connectorId?}
- Replace flat evseId with proper evse object in TransactionEventRequest
- CSData: preserve EVSE→Connector mapping instead of flattening
- CSConnector: display 'evseId/connectorId' for OCPP 2.0 stations
- Route: pass evseId and ocppVersion as query params (not sentinels)
- StartTransaction: read EVSE context from query, display EVSE/Connector
- UIClient.startTransaction: accept evseId, build spec-compliant evse object
- Tests: exhaustive decision tree coverage (18 tests, all branches)

* [autofix.ci] apply automated fixes

* refactor(webui): improve API elegance and fix cross-version concerns

- Refactor startTransaction/stopTransaction to use named options object
  instead of positional params for better readability and grouping
- Fix ToggleButton ID collision: include evseId for multi-EVSE uniqueness
- Normalize idTag validation as cross-version concern (empty→undefined)
- Rename getConnectorStatuses→getConnectorEntries to match semantics
- Extract toggleButtonId as computed to avoid string duplication

* feat: entry-based serialization for EVSE/Connector/ATG data

Introduce ConnectorEntry, EvseEntry, and ATGStatusEntry types at the
UI serialization boundary to preserve Map keys (evseId, connectorId)
that were previously lost during Map-to-Array conversion.

Backend:
- Add buildConnectorEntries/buildEvseEntries using .entries()
- Keep buildConnectorsStatus/buildEvsesStatus unchanged for config persistence
- Remove EvseStatusWorkerType and OutputFormat enum
- ATG statuses serialized with connectorId at the UI boundary only
- ConnectorStatus and EvseStatus types remain pure (no identity fields)

Frontend:
- CSData uses explicit IDs from Entry types (no more index-based mapping)
- ATG status lookup by connectorId instead of array index
- Filter connector 0 in both OCPP 1.6 and 2.0 paths
- Both connectors and evses optional in ChargingStationData

* [autofix.ci] apply automated fixes

* fix(webui): use data presence instead of protocol version for EVSE display

EVSE/Connector display depends on whether the station has EVSEs (data),
not on the OCPP version (protocol). A station could use EVSEs regardless
of OCPP version.

* refactor: extract buildATGStatusEntries for consistent Entry builder pattern

Align ATG status serialization with ConnectorEntry/EvseEntry pattern:
dedicated builder function instead of inline transformation.

* refactor: harmonize Entry naming pattern across codebase

Rename ATGStatusEntry/buildATGStatusEntries to ATGEntry/buildATGEntries
to match ConnectorEntry/EvseEntry naming convention.

* refactor: define ATGConfiguration type and harmonize across workspaces

Extract inline ATG type into named ATGConfiguration interface, matching
the ATG*/Connector*/Evse* Entry pattern in both backend and frontend.

* test: add missing Entry builder tests and non-sequential ID coverage

- Add buildATGEntries tests (entries with IDs, non-sequential, no ATG, no status)
- Add non-sequential connector ID test for buildConnectorEntries (keys 0,3,7)
- Add non-sequential evseId/connectorId test for buildEvseEntries (3/2,5)
- These tests verify the core invariant of the Entry pattern: Map keys are
  preserved regardless of their sequence

* refactor: organize tests by concern and replace throw with graceful failure

- Group backend tests: config persistence builders then UI Entry builders
- Replace throw Error in stopTransaction with ResponsePayload FAILURE
  to avoid unhandled rejections in UI components

* docs: harmonize quality gate ordering (typecheck before lint) across codebase

Align CI workflows, READMEs, and copilot-instructions to consistently
run typecheck before lint in all three sub-projects.

* refactor(ocpp2): centralize TransactionEvent payload building

- requestStopTransaction delegates to sendTransactionEvent instead of
  building the OCPP payload inline, eliminating duplication
- All TransactionEvent paths now converge through sendTransactionEvent
  → buildTransactionEvent as the single payload construction point
- handleTransactionEvent (UI) dispatches Started/Ended to proper flows
  with connector state initialization and lifecycle management
- Remove unused imports (secondsToMilliseconds, Constants)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
6 days agochore(deps): lock file maintenance (#1729)
renovate[bot] [Wed, 18 Mar 2026 12:14:24 +0000 (13:14 +0100)] 
chore(deps): lock file maintenance (#1729)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
6 days agochore(deps): update pnpm/action-setup action to v5 (#1737)
renovate[bot] [Wed, 18 Mar 2026 12:09:37 +0000 (13:09 +0100)] 
chore(deps): update pnpm/action-setup action to v5 (#1737)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
6 days agochore(deps): update dependency eslint-plugin-perfectionist to ^5.7.0 (#1736)
renovate[bot] [Wed, 18 Mar 2026 12:09:01 +0000 (13:09 +0100)] 
chore(deps): update dependency eslint-plugin-perfectionist to ^5.7.0 (#1736)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
6 days agofeat(ocpp2): fix authorization conformance gaps (C10, C12, C01, C09) (#1735)
Jérôme Benoit [Wed, 18 Mar 2026 10:44:58 +0000 (11:44 +0100)] 
feat(ocpp2): fix authorization conformance gaps (C10, C12, C01, C09) (#1735)

* feat(ocpp2): auto-update auth cache on TransactionEventResponse (C10.FR.01/04/05, C12.FR.06)

* feat(ocpp2): check MasterPassGroupId in start transaction (C12.FR.09)

* feat(ocpp2): add groupId-based stop transaction authorization (C01.FR.03, C09.FR.03/07)

* fix(ocpp2): address PR review findings

- C12.FR.09: compare groupIdToken not idToken
- C09.FR.03: remove inner isIdTokenAuthorized check
- Guard updateCacheEntry on authorizationCacheEnabled
- Fix MasterPass test to mock VariableManager

* style(tests): align test naming with style guide

* fix: merge duplicate AuthTypes.js imports in auth barrel

* fix(tests): add required JSDoc to GroupIdStop test helper

* style(ocpp2): harmonize log levels, remove spec refs from log messages, use truncateId

* style(auth): harmonize log prefixes, levels, and identifier truncation

* refactor(auth): use moduleName constant for log prefixes in OCPPAuthServiceImpl

* refactor(auth): use moduleName constant across all auth files

* fix(tests): skip flaky RequestStopTransaction test on all Node 22 platforms

* refactor(auth): harmonize log prefixes in auth adapters

* refactor: move truncateId to utils and truncate identifiers in OCPP20 logs

* style(ocpp2): remove spec ref from statusInfo additionalInfo

* style(ocpp2): truncate idToken in statusInfo additionalInfo

* test(ocpp2): improve test coverage and remove duplicates in auth conformance tests

7 days agodocs(ocpp-server): add typecheck and test_coverage to README and reorder dev sections
Jérôme Benoit [Tue, 17 Mar 2026 17:18:43 +0000 (18:18 +0100)] 
docs(ocpp-server): add typecheck and test_coverage to README and reorder dev sections

7 days agodocs: update suggested commands and task completion checklist
Jérôme Benoit [Tue, 17 Mar 2026 17:02:39 +0000 (18:02 +0100)] 
docs: update suggested commands and task completion checklist

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
7 days agochore: release main (#1732)
Jérôme Benoit [Tue, 17 Mar 2026 13:25:26 +0000 (14:25 +0100)] 
chore: release main (#1732)

* chore: release main

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
7 days agodocs: remove redundant common pitfalls from code style conventions
Jérôme Benoit [Tue, 17 Mar 2026 13:11:08 +0000 (14:11 +0100)] 
docs: remove redundant common pitfalls from code style conventions

7 days agodocs: update openspec config with current project structure and conventions
Jérôme Benoit [Tue, 17 Mar 2026 12:53:56 +0000 (13:53 +0100)] 
docs: update openspec config with current project structure and conventions