* fix(ocpp/1.6): correct GetDiagnostics log directory resolution
`handleRequestGetDiagnostics` called `resolve()` with the comma operator
by accident:
resolve((fileURLToPath(import.meta.url), '../', dirname(logFile)))
The extra parentheses wrap a comma-operator expression that evaluates to
`dirname(logFile)` only, so `readdirSync` was invoked with a
directory resolved from CWD instead of relative to the module URL. When
the process CWD is not the project root (e.g. a systemd service, a docker
container that mounts logs elsewhere, a background worker with a chdir'd
parent), the log-file discovery scanned the wrong directory and produced
an incomplete diagnostics archive.
Align with the sibling call at line 1183 which already uses the intended
pattern:
resolve(dirname(fileURLToPath(import.meta.url)), '../', diagnosticsArchive)
Both call sites now resolve paths relative to the module's parent
directory. Gates pass (typecheck / lint).
* fix(physics): use sqrt(3) for line-to-line voltage derivation
Two sites derived the line-to-line nominal voltage from Math.sqrt(numberOfPhases) * V_LN:
- src/charging-station/ocpp/OCPPServiceUtils.ts:1255
- src/charging-station/meter-values/CoherentMeterValueBuilder.ts:282
The ratio V_LL / V_LN in a balanced 3-phase Y system is a fixed sqrt(3),
which comes from the 30-degree phase separation between line and neutral
voltages (V_LL = 2 * V_LN * sin(60 deg) = sqrt(3) * V_LN). It is NOT a
function of the phase count.
Both call sites are currently reachable only when numberOfPhases === 3
(one guarded explicitly at CoherentMeterValueBuilder.ts:281; the other
implicitly via the phaseLineToLineVoltageMeterValues + phase-rotation
plumbing that only supports 3-phase). Numerically the emitted value is
unchanged, but the formula was a trap: any future relaxation of the
3-phase guard would silently emit sqrt(2) * V_LN at N=2, which is
physically meaningless.
Replace both call sites with Math.sqrt(3) and add a code comment stating
the physics derivation so the constant cannot be re-parameterized on the
phase count.
Gates pass (typecheck / test, 2955 pass / 0 fail).
* refactor(auth): standardize on OCPP 2.0.1 terminology in auth subsystem
The recently-added auth subsystem used bare 'OCPP 2.0' throughout its
comments and JSDoc while the rest of the codebase (README, AGENTS.md,
all other source files) uses 'OCPP 2.0.1' as the canonical spec version
and 'OCPP 2.0.x' as the family. The auth subsystem also used non-existent
forms 'OCPP 2.0+' and 'OCPP 2.0/2.1' that misrepresented the supported
spec range: OCPP 2.1 is not implemented.
Bulk-replace across src/charging-station/ocpp/auth/:
- 'OCPP 2.0+' -> 'OCPP 2.0.1'
- 'OCPP 2.0/2.1' -> 'OCPP 2.0.1'
- bare 'OCPP 2.0' -> 'OCPP 2.0.1' (negative lookahead on '.digit' so
existing 'OCPP 2.0.1' and 'OCPP 2.0.x' occurrences are preserved)
65 occurrences updated across 5 files. Files touched:
- adapters/OCPP20AuthAdapter.ts (31)
- types/AuthTypes.ts (21)
- strategies/CertificateAuthStrategy.ts (7)
- utils/AuthValidators.ts (5)
- strategies/RemoteAuthStrategy.ts (1)
Zero code behavior change; comment/JSDoc content only.
Gates pass (typecheck / lint).
* refactor(ocpp/1.6): harmonize 'Central System' capitalization for logs and docs
Two mismatches surfaced against OCPP 2.0 counterparts:
1. `csmsName` field values in OCPP16IncomingRequestService.ts:176 and
OCPP16ResponseService.ts:129 held the lowercase two-word form
'central system'. The abstract base classes interpolate this field
into runtime error messages, producing 'not registered on the central
system' for OCPP 1.6 versus 'not registered on the CSMS' for OCPP
2.0. Two spec-correct forms are involved (OCPP 1.6 uses 'Central
System'; OCPP 2.0.1 uses 'CSMS' for 'Charging Station Management
System'), so keep the spec-correct term per version but capitalize
the 1.6 value to match OCPP 1.6 spec convention.
2. JSDoc prose across OCPP 1.6 files ('sends X to the central system',
'response from the central system', etc.) mixed the lowercase form
with the capitalized 'Central System (CS)' used in the module-level
docstring of OCPP16IncomingRequestService.ts. Normalize to the
capitalized form throughout src/charging-station/ocpp/1.6/.
Zero code behavior change; only logged strings and comment prose shift
casing. Gates pass (typecheck / lint).
* refactor: apply numeric-literal underscore separators to 5-digit-plus constants
Numeric-literal style was inconsistent: OCPP20Constants.ts uses
underscore separators for readability (e.g. `30_000`, `5_000`),
while src/utils/Constants.ts and other constants files used bare
literals (`60000`, `30000`, `
1048576`).
Apply underscore separators uniformly to 5+ digit numeric literals
across the constants files, matching the OCPP20Constants.ts precedent:
- src/utils/Constants.ts: `60000` -> `60_000` (6 sites),
`30000` -> `30_000`, `
281474976710655` -> `281_474_976_710_655`,
`
2147483647` -> `2_147_483_647`.
- src/charging-station/ocpp/OCPPConstants.ts:
`OCPP_WEBSOCKET_TIMEOUT_MS = 60000` -> `60_000`.
- src/charging-station/ui-server/UIServerSecurity.ts:
`DEFAULT_MAX_PAYLOAD_SIZE_BYTES =
1048576` -> `1_048_576`,
`DEFAULT_RATE_WINDOW_MS = 60000` -> `60_000`,
`DEFAULT_MAX_TRACKED_IPS = 10000` -> `10_000`.
4-digit values (1000, 3600, 5000, 8080) are intentionally left unchanged;
they include port literals (`DEFAULT_UI_SERVER_PORT = 8080`) where the
underscore form is unusual. AGENTS.md numeric-literal style is a
readability convention rather than an enforced rule; applying it only
above the 5-digit threshold matches the existing OCPP20Constants.ts
pattern.
Zero code behavior change. Gates pass (typecheck / lint / test, 2955
pass / 0 fail).
* chore: expose WILDCARD_HOSTS + document Authorize in OCPP 2.0.x README table
Two low-risk harmonization findings from the from-zero audit.
1. README OCPP 2.0.x commands table missing 'Authorize' (Lane 5 M2)
The 'Authorize' command is fully implemented for OCPP 2.0.x:
- OCPP20RequestCommand.AUTHORIZE registered
- OCPP20RequestService.ts / OCPP20ResponseService.ts handlers wired
- OCPP20ServiceUtils.ts sending helper
but the README '#### C. Authorization' section listed only 'ClearCache'.
Add ':white_check_mark: Authorize' alongside 'ClearCache' so the docs
match the actual implementation surface.
2. Extract WILDCARD_HOSTS set (Lane 4 M20)
AbstractUIServer.ts:1325 inlined the three literals '', '0.0.0.0', '::'
as a triple '===' chain to detect wildcard host configuration, while
UIServerAccessPolicy.ts:23 already held the same three values in a
module-scoped 'WILDCARD_HOSTS' set. Two independent definitions of
the same domain concept.
Export WILDCARD_HOSTS (typed 'ReadonlySet<string>') from
UIServerAccessPolicy.ts, import it in AbstractUIServer.ts, and
replace the inline OR chain with 'WILDCARD_HOSTS.has(configuredHost)'.
Zero behavior change. Gates pass (typecheck / lint).
* fix(ocpp/1.6): return Accepted for DataTransfer with matching vendor and messageId
Per OCPP 1.6 §4.3, the DataTransfer response statuses are:
- `UnknownVendorId` when the vendorId is not recognized
- `UnknownMessageId` when the vendorId is recognized but the messageId
is not
- `Accepted` when both vendor and message are recognized
`handleRequestDataTransfer` previously returned `UnknownMessageId` for
*any* non-null messageId, even when the vendorId matched the station's
configured `chargePointVendor`:
if (vendorId !== chargingStation.stationInfo?.chargePointVendor) {
return ... UNKNOWN_VENDOR_ID
}
if (messageId != null) {
return ... UNKNOWN_MESSAGE_ID // wrong: any non-null messageId
}
That rejected every legitimate DataTransfer with a messageId, regardless
of whether the messageId would have been supported. The simulator does
not maintain a per-vendor messageId registry (it has no way to know
which custom messageIds a real charge point would accept), so the
spec-correct behaviour is to accept any messageId once the vendor
matches.
Drop the erroneous `messageId != null` branch and return `Accepted`
whenever the vendor matches; the `UnknownVendorId` path is unchanged.
Add a source comment citing OCPP 1.6 §4.3 to prevent regression of the
buggy check.
Test update: the existing 'should return UnknownMessageId for matching
vendor with messageId' test asserted the old buggy behaviour. Rewritten
as 'should return Accepted for matching vendor with messageId (no
messageId registry per §4.3)' to lock in the spec-correct outcome.
Gates pass (typecheck / test, 2955 pass / 0 fail).
* fix(ocpp/1.6): emit FirmwareStatusNotification(Installed) after Installing
Per OCPP 1.6 §4.5, the Charge Point SHALL notify the CSMS of firmware
update progress via FirmwareStatusNotification. `updateFirmwareSimulation`
already emitted the intermediate statuses (Downloading -> Downloaded ->
Installing) but never signalled successful completion — after emitting
`Installing`, the simulation went straight to the optional reset step
(if configured) or returned, leaving the CSMS with no confirmation
that installation actually finished.
Insert an `Installed` status emission between the InstallationFailed
early-return branch and the optional reset:
sleep(...)
requestHandler(FIRMWARE_STATUS_NOTIFICATION, { status: Installed })
stationInfo.firmwareStatus = Installed
if (reset === true) { sleep(...); reset() }
Behaviour on the failure path is unchanged: the InstallationFailed
branch still returns early without emitting `Installed`. Behaviour
when `reset` is disabled is unchanged apart from the additional
notification (which is the whole point of the fix).
Gates pass (typecheck / test, 2935 pass / 0 fail).
* fix(ocpp/1.6): return Failed (not NotSupported) when LocalAuthList is disabled or manager missing
Per OCPP 1.6 §5.15, the SendLocalList response statuses have distinct
semantics:
- NotSupported: the LocalAuthListManagement feature profile is not
implemented by the Charge Point
- Failed: the feature is implemented but the specific update failed
(disabled, unavailable, or otherwise unable to apply the change)
`handleRequestSendLocalList` correctly returned NotSupported when the
LocalAuthListManagement profile is absent (line 1534). But two
subsequent guards also returned NotSupported when:
- `LocalAuthListEnabled` config is false (feature supported but disabled)
- `getLocalAuthListManager()` returns null (feature supported but manager
not wired)
Both scenarios describe a Charge Point that supports the feature — the
LocalAuthListManagement profile is present — but cannot apply this
particular update. Per spec, that is Failed, not NotSupported.
Change both guards to return
`OCPP16Constants.OCPP_SEND_LOCAL_LIST_RESPONSE_FAILED`. The profile-
absent guard (line 1534) is unchanged — it correctly reports
NotSupported when the feature is not implemented at all.
Test updates: two existing tests locked in the old NotSupported result.
Renamed and updated to assert Failed with an inline reference to §5.15
so the spec-correct outcome is regression-locked.
Gates pass (typecheck / test, 2945 pass / 0 fail).
* chore(auth): remove OCPPAuthServiceImpl from public barrel
`OCPPAuthServiceImpl` is the concrete implementation of the
`OCPPAuthService` interface. External code should construct instances
through `OCPPAuthServiceFactory` (which internally uses the class)
rather than instantiating it directly. Exporting the concrete class
from the auth barrel published an implementation detail that:
- Adds public API surface with no consumer benefit
- Encourages callers to bypass the factory's per-station singleton
- Complicates future refactoring of the concrete class
Grep across src/ and ui/ confirms zero consumers of
`OCPPAuthServiceImpl` via the barrel (`ocpp/auth/index.js`); the
factory imports it via the direct file path within the same subtree.
Two test files (`OCPP20ResponseService-CacheUpdate.test.ts`,
`OCPP20ServiceUtils-AuthCache.test.ts`) did import it via the barrel;
routed to the direct path so they still exercise the concrete class
where explicitly needed.
Also correct the module-level JSDoc from 'OCPP 1.6 and 2.0' to
'OCPP 1.6 and 2.0.1' to match the canonical spec-version convention
used throughout the codebase.
Gates pass (typecheck / lint / test, 2955 pass / 0 fail).
* refactor: extend OCPP 2.0.1 terminology to non-auth paths and compress physics comment
Two round-3 review findings from PR #1960 self-review addressed together.
1. Round-3 High: terminology scope creep
Prior commit
dbc3f3ff bulk-replaced OCPP 2.0 -> OCPP 2.0.1 in
src/charging-station/ocpp/auth/ only (65 occurrences). Identical drift
existed across the rest of the OCPP 2.0.x code paths, including the
invalid OCPP 2.0+ form that
dbc3f3ff had explicitly corrected in auth/
but left intact in ~10 sites of OCPP20IncomingRequestService JSDoc.
After
dbc3f3ff, auth/ said OCPP 2.0.1 while the rest of the OCPP 2.0.x
subtree still said OCPP 2.0 / OCPP 2.0+ — the terminology divergence
was worse, not better.
Apply the same three-pass perl regex (strip +, collapse /2.1,
negative-lookahead on .digit for bare 2.0) to:
- src/charging-station/ocpp/2.0/**/*.ts (56 occurrences)
- src/charging-station/ocpp/OCPPServiceUtils.ts (3)
- src/charging-station/ui-server/UIMCPServer.ts (2)
- ui/common/tests/payloadBuilders.test.ts (2)
63 total substitutions. Zero code behavior change; comment/JSDoc/test
description content only. Zero remaining bare OCPP 2.0 refs under the
scanned scope.
2. Round-3 Low: physics comment verbosity
The sqrt(3) physics anchor comment added in commit
34a574f9 spanned 8
lines with tangential explanations. Compress to 3 lines that keep the
essential physics anchor (V_LL = sqrt(3) * V_LN, 30-degree phase
separation, 3-phase-only constraint).
Documented as still-deferred:
- Narrative comment at OCPP16IncomingRequestService.ts:276 — kept under
M5 bulk cleanup deferral.
- OCPP 2.0.x handleRequestDataTransfer UnknownVendorId design — a
different intentional choice, not the same bug as OCPP 1.6 C3.
All gates green (format / typecheck / lint / build / test) across root,
ui/cli, ui/web. Circular-deps baseline of 61 preserved.
* chore: complete OCPP 2.0.1 terminology sweep and drop redundant physics comment line
Round-4 review findings from PR #1960 self-review addressed together.
1. Terminology sweep completion (Low)
The round-3 extension (commit
e03368ff) covered
src/charging-station/ocpp/2.0/**, OCPPServiceUtils.ts, UIMCPServer.ts,
and payloadBuilders.test.ts, but the audit's terminology finding
applied to the whole codebase. Four bare 'OCPP 2.0' refs survived in
charging-station/ files outside ocpp/2.0/:
- src/charging-station/ConfigurationKeyUtils.ts:
user-facing warning 'use OCPP 2.0 variable ... instead'
- src/charging-station/meter-values/CoherentMeterValueBuilder.ts:
code comment 'Narrow the OCPP 2.0 SampledValueTemplate.unit ...'
- src/charging-station/TemplateSchema.ts (2 sites):
JSDoc references to 'OCPP 2.0 unit-of-measure descriptor' and
'OCPP 2.0 namespaced keys'
Apply the same negative-lookahead perl regex; 4 substitutions, zero
code behaviour change. The user-facing warning in ConfigurationKeyUtils
now cites the spec version consistently with the rest of the codebase.
2. Physics comment redundancy (Info)
The compressed sqrt(3) anchor comment from commit
e03368ff sat
directly below a preexisting one-liner ('Line-to-line voltage is only
defined for 3-phase AC') that duplicated the L-L === 3-phase constraint
already stated in the compressed block ('Defined only for numberOfPhases
=== 3'). Delete the preexisting redundant line; the compressed anchor
carries the full physics rationale (V_LL = sqrt(3) * V_LN, 30-degree
phase separation, 3-phase-only constraint).
Test files (~15 refs of 'OCPP 2.0' as describe/it group labels) are
intentionally left as-is: those are test-grouping labels rather than
spec-version references, and renaming them would break dev-side test
regex filters without functional benefit.
Gates green (format / typecheck / lint / build / test) across root;
ui/cli and ui/web untouched. Circular-deps baseline of 61 preserved.
#### C. Authorization
+- :white_check_mark: Authorize
- :white_check_mark: ClearCache
#### D. LocalAuthorizationListManagement
const resolved = OCPP2_PARAMETER_KEY_MAP.get(entry.key)
if (resolved != null) {
logger.warn(
- `${chargingStation.logPrefix()} Template uses OCPP 1.6 key '${entry.key}', use OCPP 2.0 variable '${resolved}' instead`
+ `${chargingStation.logPrefix()} Template uses OCPP 1.6 key '${entry.key}', use OCPP 2.0.1 variable '${resolved}' instead`
)
}
}
.catchall(z.unknown())
/**
- * UnitOfMeasure — OCPP 2.0 unit-of-measure descriptor.
+ * UnitOfMeasure — OCPP 2.0.1 unit-of-measure descriptor.
*/
const UnitOfMeasureSchema = z
.object({
/**
* ConfigurationKey — OCPP configuration key entry.
- * `key` is z.string() (open set: vendor-specific and OCPP 2.0 namespaced keys are valid).
+ * `key` is z.string() (open set: vendor-specific and OCPP 2.0.1 namespaced keys are valid).
*/
const ConfigurationKeySchema = z.looseObject({
key: z.string(),
case MeterValueMeasurand.VOLTAGE:
if (family === 'Neutral') return 0
if (family === 'LineToLine') {
- // Line-to-line voltage is only defined for 3-phase AC
- // (V_LL = sqrt(3) * V_LN); 1-phase has no L-L pair, and
- // `numberOfPhases === 2` is unsupported by contract
- // (`Helpers.getPhaseRotationValue` branches only on {0, 1, 3}).
- // Return `undefined` on any non-3-phase configuration so the
- // caller can log-and-skip rather than emit a physically
- // meaningless sqrt(2) * V_LN value.
+ // V_LL = sqrt(3) * V_LN in a balanced 3-phase Y system (30-degree
+ // phase separation). Defined only for numberOfPhases === 3;
+ // 1-phase has no L-L pair, 2-phase is unsupported by contract.
if (numberOfPhases !== 3) return undefined
- return Math.sqrt(numberOfPhases) * sample.voltageV
+ return Math.sqrt(3) * sample.voltageV
}
return sample.voltageV
default:
)
continue
}
- // Narrow the OCPP 2.0 `SampledValueTemplate.unit` open-string branch
+ // Narrow the OCPP 2.0.1 `SampledValueTemplate.unit` open-string branch
// to the closed `MeterValueUnit` union for the Map lookup below; any
// string outside the enum returns `undefined` from the Map and falls
// through to divider = 1 (unit-scale emission).
*/
export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
- protected readonly csmsName = 'central system'
+ protected readonly csmsName = 'Central System'
protected readonly incomingRequestHandlers: Map<IncomingRequestCommand, IncomingRequestHandler>
protected readonly moduleName = moduleName
chargingStation: ChargingStation,
commandPayload: OCPP16DataTransferRequest
): OCPP16DataTransferResponse {
- const { messageId, vendorId } = commandPayload
+ const { vendorId } = commandPayload
try {
if (vendorId !== chargingStation.stationInfo?.chargePointVendor) {
return OCPP16Constants.OCPP_DATA_TRANSFER_RESPONSE_UNKNOWN_VENDOR_ID
}
- if (messageId != null) {
- return OCPP16Constants.OCPP_DATA_TRANSFER_RESPONSE_UNKNOWN_MESSAGE_ID
- }
+ // OCPP 1.6 §4.3: `UnknownMessageId` is reserved for the case where the
+ // vendor is known but the messageId is not recognized by the Charge
+ // Point. The simulator does not maintain a per-vendor messageId
+ // registry, so any messageId (including undefined) is accepted when
+ // the vendor matches.
return OCPP16Constants.OCPP_DATA_TRANSFER_RESPONSE_ACCEPTED
} catch (error) {
const errorResponse: OCPP16DataTransferResponse =
return OCPP16Constants.OCPP_RESPONSE_EMPTY
}
const logFiles = readdirSync(
- resolve((fileURLToPath(import.meta.url), '../', dirname(logFile)))
+ resolve(dirname(fileURLToPath(import.meta.url)), '../', dirname(logFile))
)
.filter(file => file.endsWith(extname(logFile)))
.map(file => join(dirname(logFile), file))
}
/**
- * Handles OCPP 1.6 GetLocalListVersion request from central system.
+ * Handles OCPP 1.6 GetLocalListVersion request from Central System.
* Returns the version number of the local authorization list.
* @param chargingStation - The charging station instance processing the request
* @returns GetLocalListVersionResponse with list version
}
/**
- * Handles OCPP 1.6 RemoteStartTransaction request from central system
+ * Handles OCPP 1.6 RemoteStartTransaction request from Central System
* Initiates charging transaction on specified or available connector
* @param chargingStation - The charging station instance processing the request
* @param commandPayload - RemoteStartTransaction request payload with connector and ID tag
try {
const authService = OCPPAuthServiceFactory.getInstance(chargingStation)
if (!chargingStation.getLocalAuthListEnabled()) {
- return OCPP16Constants.OCPP_SEND_LOCAL_LIST_RESPONSE_NOT_SUPPORTED
+ return OCPP16Constants.OCPP_SEND_LOCAL_LIST_RESPONSE_FAILED
}
const manager = authService.getLocalAuthListManager()
if (manager == null) {
- return OCPP16Constants.OCPP_SEND_LOCAL_LIST_RESPONSE_NOT_SUPPORTED
+ return OCPP16Constants.OCPP_SEND_LOCAL_LIST_RESPONSE_FAILED
}
if (commandPayload.listVersion <= 0) {
return OCPP16Constants.OCPP_SEND_LOCAL_LIST_RESPONSE_FAILED
chargingStation.stationInfo.firmwareUpgrade.failureStatus
return
}
+ await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay + 1)))
+ await chargingStation.ocppRequestService.requestHandler<
+ OCPP16FirmwareStatusNotificationRequest,
+ OCPP16FirmwareStatusNotificationResponse
+ >(chargingStation, OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, {
+ status: OCPP16FirmwareStatus.Installed,
+ })
+ if (chargingStation.stationInfo != null) {
+ chargingStation.stationInfo.firmwareStatus = OCPP16FirmwareStatus.Installed
+ }
if (chargingStation.stationInfo?.firmwareUpgrade?.reset === true) {
await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay + 1)))
await chargingStation.reset(OCPP16StopTransactionReason.REBOOT)
/**
* OCPP 1.6 Request Service
*
- * Handles outgoing OCPP 1.6 requests from the charging station to the central system.
+ * Handles outgoing OCPP 1.6 requests from the charging station to the Central System.
* This service is responsible for:
* - Building and validating request payloads according to OCPP 1.6 specification
* - Managing request-response cycles with proper error handling
* It performs the following operations:
* - Validates that the requested command is supported by the charging station
* - Builds and validates the request payload according to OCPP 1.6 schemas
- * - Sends the request to the central system with proper error handling
+ * - Sends the request to the Central System with proper error handling
* - Processes responses with comprehensive logging and error recovery
*
* The method ensures type safety through generic type parameters while maintaining
* backward compatibility with the OCPP 1.6 specification.
* @template RequestType - The expected type of the request parameters
- * @template ResponseType - The expected type of the response from the central system
+ * @template ResponseType - The expected type of the response from the Central System
* @param chargingStation - The charging station instance making the request
* @param commandName - The OCPP 1.6 command to execute (e.g., 'StartTransaction', 'StopTransaction')
* @param commandParams - Optional parameters specific to the command being executed
* @param params - Optional request parameters for controlling request behavior
- * @returns Promise resolving to the typed response from the central system
+ * @returns Promise resolving to the typed response from the Central System
* @throws {OCPPError} When the command is not supported or validation fails
*/
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
>
protected readonly bootNotificationRequestCommand = OCPP16RequestCommand.BOOT_NOTIFICATION
- protected readonly csmsName = 'central system'
+ protected readonly csmsName = 'Central System'
protected readonly moduleName = moduleName
protected payloadValidatorFunctions: Map<OCPP16RequestCommand, ValidateFunction<JsonType>>
}
const logMsg = `${chargingStation.logPrefix()} ${moduleName}.handleResponseBootNotification: Charging station in '${
payload.status
- }' state on the central system`
+ }' state on the Central System`
payload.status === RegistrationStatusEnumType.REJECTED
? logger.warn(logMsg)
: logger.info(logMsg)
}
/**
- * Sends a StartTransaction request to the central system for the given connector.
+ * Sends a StartTransaction request to the Central System for the given connector.
* @param chargingStation - Target charging station
* @param connectorId - Connector identifier to start the transaction on
* @param idTag - Optional RFID tag for the transaction
- * @returns Start transaction response from the central system
+ * @returns Start transaction response from the Central System
*/
public static async startTransactionOnConnector (
chargingStation: ChargingStation,
}
/**
- * Sends a StopTransaction request to the central system for the given connector.
+ * Sends a StopTransaction request to the Central System for the given connector.
* @param chargingStation - Target charging station
* @param connectorId - Connector identifier with the active transaction
* @param reason - Optional stop transaction reason
- * @returns Stop transaction response from the central system
+ * @returns Stop transaction response from the Central System
*/
public static async stopTransactionOnConnector (
chargingStation: ChargingStation,
*/
export interface TestableOCPP16IncomingRequestService {
/**
- * Handles OCPP 1.6 CancelReservation request from central system.
+ * Handles OCPP 1.6 CancelReservation request from Central System.
* Cancels an existing reservation on the charging station.
*/
handleRequestCancelReservation: (
) => Promise<GenericResponse>
/**
- * Handles OCPP 1.6 ChangeAvailability request from central system.
+ * Handles OCPP 1.6 ChangeAvailability request from Central System.
* Changes availability status of a connector or the entire station.
*/
handleRequestChangeAvailability: (
) => Promise<OCPP16ChangeAvailabilityResponse>
/**
- * Handles OCPP 1.6 ChangeConfiguration request from central system.
+ * Handles OCPP 1.6 ChangeConfiguration request from Central System.
* Changes the value of a configuration key.
*/
handleRequestChangeConfiguration: (
handleRequestClearCache: (chargingStation: ChargingStation) => ClearCacheResponse
/**
- * Handles OCPP 1.6 ClearChargingProfile request from central system.
+ * Handles OCPP 1.6 ClearChargingProfile request from Central System.
* Clears charging profiles matching the specified criteria.
*/
handleRequestClearChargingProfile: (
) => OCPP16ClearChargingProfileResponse
/**
- * Handles OCPP 1.6 DataTransfer request from central system.
+ * Handles OCPP 1.6 DataTransfer request from Central System.
* Processes vendor-specific data transfer messages.
*/
handleRequestDataTransfer: (
) => OCPP16DataTransferResponse
/**
- * Handles OCPP 1.6 GetCompositeSchedule request from central system.
+ * Handles OCPP 1.6 GetCompositeSchedule request from Central System.
* Returns the composite charging schedule for a connector.
*/
handleRequestGetCompositeSchedule: (
) => OCPP16GetCompositeScheduleResponse
/**
- * Handles OCPP 1.6 GetConfiguration request from central system.
+ * Handles OCPP 1.6 GetConfiguration request from Central System.
* Returns configuration keys and their values.
*/
handleRequestGetConfiguration: (
) => GetConfigurationResponse
/**
- * Handles OCPP 1.6 GetDiagnostics request from central system.
+ * Handles OCPP 1.6 GetDiagnostics request from Central System.
* Uploads diagnostics data to the specified location.
*/
handleRequestGetDiagnostics: (
) => OCPP16GetLocalListVersionResponse
/**
- * Handles OCPP 1.6 RemoteStartTransaction request from central system.
+ * Handles OCPP 1.6 RemoteStartTransaction request from Central System.
* Initiates charging transaction on specified or available connector.
*/
handleRequestRemoteStartTransaction: (
) => Promise<GenericResponse>
/**
- * Handles OCPP 1.6 RemoteStopTransaction request from central system.
+ * Handles OCPP 1.6 RemoteStopTransaction request from Central System.
* Stops an ongoing transaction by transaction ID.
*/
handleRequestRemoteStopTransaction: (
) => GenericResponse
/**
- * Handles OCPP 1.6 ReserveNow request from central system.
+ * Handles OCPP 1.6 ReserveNow request from Central System.
* Creates a reservation on a connector for a specific ID tag.
*/
handleRequestReserveNow: (
) => Promise<OCPP16ReserveNowResponse>
/**
- * Handles OCPP 1.6 Reset request from central system.
+ * Handles OCPP 1.6 Reset request from Central System.
* Performs immediate or scheduled reset of the charging station.
*/
handleRequestReset: (
) => OCPP16SendLocalListResponse
/**
- * Handles OCPP 1.6 SetChargingProfile request from central system.
+ * Handles OCPP 1.6 SetChargingProfile request from Central System.
* Sets or updates a charging profile on a connector.
*/
handleRequestSetChargingProfile: (
) => SetChargingProfileResponse
/**
- * Handles OCPP 1.6 TriggerMessage request from central system.
+ * Handles OCPP 1.6 TriggerMessage request from Central System.
* Triggers the station to send a specific message type.
*/
handleRequestTriggerMessage: (
) => OCPP16TriggerMessageResponse
/**
- * Handles OCPP 1.6 UnlockConnector request from central system.
+ * Handles OCPP 1.6 UnlockConnector request from Central System.
* Unlocks a connector and optionally stops any ongoing transaction.
*/
handleRequestUnlockConnector: (
) => Promise<UnlockConnectorResponse>
/**
- * Handles OCPP 1.6 UpdateFirmware request from central system.
+ * Handles OCPP 1.6 UpdateFirmware request from Central System.
* Initiates firmware download and installation simulation.
*/
handleRequestUpdateFirmware: (
}
/**
- * Interface for OCPP 2.0 Certificate Manager operations
+ * Interface for OCPP 2.0.1 Certificate Manager operations
* Used for type-safe access to certificate management functionality
*/
export interface OCPP20CertificateManagerInterface {
}
/**
- * OCPP 2.0 Certificate Manager
+ * OCPP 2.0.1 Certificate Manager
*
- * Provides certificate management operations for OCPP 2.0 charging stations:
+ * Provides certificate management operations for OCPP 2.0.1 charging stations:
* - Store/delete certificates
* - Compute certificate hashes
* - Validate certificate format
static readonly FIRMWARE_STATUS_DELAY_MS = 2000
static readonly FIRMWARE_VERIFY_DELAY_MS = 500
/**
- * Default timeout in milliseconds for async OCPP 2.0 handler operations
+ * Default timeout in milliseconds for async OCPP 2.0.1 handler operations
* (e.g., certificate file I/O). Prevents handlers from hanging indefinitely.
*/
static readonly HANDLER_TIMEOUT_MS = 30_000
}
/**
- * Handles OCPP 2.0 CertificateSigned request from central system
+ * Handles OCPP 2.0.1 CertificateSigned request from central system
* Receives signed certificate chain from CSMS and stores it in the charging station
* Triggers websocket reconnect for ChargingStationCertificate type to use the new certificate
* @param chargingStation - The charging station instance processing the request
}
/**
- * Handles OCPP 2.0 DeleteCertificate request from central system
+ * Handles OCPP 2.0.1 DeleteCertificate request from central system
* Deletes a certificate matching the provided hash data from the charging station
* Per M04.FR.06: ChargingStationCertificate cannot be deleted via DeleteCertificateRequest
* @param chargingStation - The charging station instance processing the request
}
/**
- * Handles OCPP 2.0 GetInstalledCertificateIds request from central system
+ * Handles OCPP 2.0.1 GetInstalledCertificateIds request from central system
* Returns list of installed certificates matching the optional filter types
* @param chargingStation - The charging station instance processing the request
* @param commandPayload - GetInstalledCertificateIds request payload with optional certificate type filter
}
/**
- * Handles OCPP 2.0 RequestStartTransaction request from central system
+ * Handles OCPP 2.0.1 RequestStartTransaction request from central system
* Initiates charging transaction on specified EVSE with enhanced authorization
* @param chargingStation - The charging station instance processing the request
* @param commandPayload - RequestStartTransaction request payload with EVSE, ID token and profiles
return buildRejectedResponse(
ReasonCodeEnumType.TxStarted,
`Connector ${connectorId.toString()} has a pending transaction not yet authorized`,
- // safe: OCPP 2.0 paths always store generateUUID() output here (see line ~2740)
+ // safe: OCPP 2.0.1 paths always store generateUUID() output here (see line ~2740)
connectorStatus.transactionId as UUIDv4
)
}
}
/**
- * Terminates all active transactions on the charging station using OCPP 2.0 TransactionEventRequest
+ * Terminates all active transactions on the charging station using OCPP 2.0.1 TransactionEventRequest
* @param chargingStation - The charging station instance
* @param reason - The reason for transaction termination
*/
}
/**
- * Terminates all active transactions on the specified EVSE using OCPP 2.0 TransactionEventRequest
+ * Terminates all active transactions on the specified EVSE using OCPP 2.0.1 TransactionEventRequest
* @param chargingStation - The charging station instance
* @param evseId - The EVSE identifier to terminate transactions on
* @param reason - The reason for transaction termination
}
/**
- * OCPP 2.0+ Incoming Request Service - handles and processes all incoming requests
- * from the Central System (CSMS) to the Charging Station using OCPP 2.0+ protocol.
+ * OCPP 2.0.1 Incoming Request Service - handles and processes all incoming requests
+ * from the Central System (CSMS) to the Charging Station using OCPP 2.0.1 protocol.
*
* This service class is responsible for:
- * - **Request Reception**: Receiving and routing OCPP 2.0+ incoming requests from CSMS
- * - **Payload Validation**: Validating incoming request payloads against OCPP 2.0+ JSON schemas
- * - **Request Processing**: Executing business logic for each OCPP 2.0+ request type
+ * - **Request Reception**: Receiving and routing OCPP 2.0.1 incoming requests from CSMS
+ * - **Payload Validation**: Validating incoming request payloads against OCPP 2.0.1 JSON schemas
+ * - **Request Processing**: Executing business logic for each OCPP 2.0.1 request type
* - **Response Generation**: Creating and sending appropriate responses back to CSMS
- * - **Enhanced Features**: Supporting advanced OCPP 2.0+ features like variable management
+ * - **Enhanced Features**: Supporting advanced OCPP 2.0.1 features like variable management
*
- * Supported OCPP 2.0+ Incoming Request Types:
+ * Supported OCPP 2.0.1 Incoming Request Types:
* - **Transaction Management**: RequestStartTransaction, RequestStopTransaction
* - **Configuration Management**: SetVariables, GetVariables, GetBaseReport
* - **Security Operations**: CertificatesSigned, SecurityEventNotification
* - **Display Management**: SetDisplayMessage, ClearDisplayMessage
* - **Customer Management**: ClearCache, SendLocalList
*
- * Key OCPP 2.0+ Enhancements:
+ * Key OCPP 2.0.1 Enhancements:
* - **Variable Model**: Advanced configuration through standardized variable system
* - **Enhanced Security**: Improved authentication and authorization mechanisms
* - **Rich Messaging**: Support for display messages and customer information
* - **Flexible Charging**: Enhanced charging profile management and scheduling
*
* Architecture Pattern:
- * This class extends OCPPIncomingRequestService and implements OCPP 2.0+-specific
+ * This class extends OCPPIncomingRequestService and implements OCPP 2.0.1-specific
* request handling logic. It integrates with the OCPP20VariableManager for advanced
* configuration management and maintains backward compatibility concepts while
* providing next-generation OCPP features.
*
* Validation Workflow:
* 1. Incoming request received and parsed
- * 2. Payload validated against OCPP 2.0+ JSON schema
+ * 2. Payload validated against OCPP 2.0.1 JSON schema
* 3. Request routed to appropriate handler method
* 4. Business logic executed with variable model integration
* 5. Response payload validated and sent back to CSMS
* @see {@link validateIncomingRequestPayload} Request payload validation method
- * @see {@link handleRequestStartTransaction} Example OCPP 2.0+ request handler
+ * @see {@link handleRequestStartTransaction} Example OCPP 2.0.1 request handler
* @see {@link OCPP20VariableManager} Variable management integration
*/
})
/**
- * Builds an OCPP 2.0 sampled value from a template and measurement data.
+ * Builds an OCPP 2.0.1 sampled value from a template and measurement data.
* @param sampledValueTemplate - The sampled value template to use.
* @param value - The measured value.
* @param context - The reading context.
* @param phase - The phase of the measurement.
* @param signingConfig - Optional signing configuration for generating signedMeterValue.
- * @returns The built OCPP 2.0 sampled value with signing metadata.
+ * @returns The built OCPP 2.0.1 sampled value with signing metadata.
*/
export function buildOCPP20SampledValue (
sampledValueTemplate: SampledValueTemplate,
const moduleName = 'OCPP20ResponseService'
/**
- * OCPP 2.0+ Response Service - handles and processes all outgoing request responses
- * from the Charging Station to the Central System Management System (CSMS) using OCPP 2.0+ protocol.
+ * OCPP 2.0.1 Response Service - handles and processes all outgoing request responses
+ * from the Charging Station to the Central System Management System (CSMS) using OCPP 2.0.1 protocol.
*
* This service class is responsible for:
* - **Response Reception**: Receiving responses to requests sent from the Charging Station
- * - **Payload Validation**: Validating response payloads against OCPP 2.0+ JSON schemas
+ * - **Payload Validation**: Validating response payloads against OCPP 2.0.1 JSON schemas
* - **Response Processing**: Processing CSMS responses and updating station state
* - **Variable Management**: Handling variable-based configuration responses
- * - **Enhanced State Management**: Managing OCPP 2.0+ advanced state and feature coordination
+ * - **Enhanced State Management**: Managing OCPP 2.0.1 advanced state and feature coordination
*
- * Supported OCPP 2.0+ Response Types:
+ * Supported OCPP 2.0.1 Response Types:
* - **Authentication**: Authorize responses with enhanced authorization mechanisms
* - **Transaction Management**: TransactionEvent responses for flexible transaction handling
* - **Status Updates**: BootNotification, StatusNotification, NotifyReport responses
* - **Security**: Responses to security-related operations and certificate management
* - **Heartbeat**: Enhanced heartbeat response processing with additional metadata
*
- * Key OCPP 2.0+ Features:
- * - **Variable Model Integration**: Seamless integration with OCPP 2.0+ variable system
+ * Key OCPP 2.0.1 Features:
+ * - **Variable Model Integration**: Seamless integration with OCPP 2.0.1 variable system
* - **Enhanced Transaction Model**: Support for flexible transaction event handling
* - **Security Framework**: Advanced security response processing and validation
* - **Rich Data Model**: Support for complex data structures and enhanced messaging
* - **Backward Compatibility**: Maintains compatibility concepts while extending functionality
*
* Architecture Pattern:
- * This class extends OCPPResponseService and implements OCPP 2.0+-specific response
- * processing logic. It works closely with OCPP20VariableManager and other OCPP 2.0+
+ * This class extends OCPPResponseService and implements OCPP 2.0.1-specific response
+ * processing logic. It works closely with OCPP20VariableManager and other OCPP 2.0.1
* components to provide comprehensive protocol support with enhanced features.
*
* Response Validation Workflow:
* 1. Response received from CSMS for the corresponding request
- * 2. Response payload validated against OCPP 2.0+ JSON schema
+ * 2. Response payload validated against OCPP 2.0.1 JSON schema
* 3. Response routed to appropriate handler based on original request type
* 4. Charging station state and variable model updated based on response content
- * 5. Enhanced follow-up actions triggered based on OCPP 2.0+ capabilities
+ * 5. Enhanced follow-up actions triggered based on OCPP 2.0.1 capabilities
* @see {@link validateResponsePayload} Response payload validation method
* @see {@link handleResponse} Response processing methods
* @see {@link OCPP20VariableManager} Variable management integration
/**
* @param chargingStation - Target charging station for EVSE resolution
* @param commandParams - Status notification parameters
- * @returns Formatted OCPP 2.0 StatusNotification request payload
+ * @returns Formatted OCPP 2.0.1 StatusNotification request payload
*/
public static buildStatusNotificationRequest (
chargingStation: ChargingStation,
* Build meter values for the start of a transaction.
* @param chargingStation - Target charging station
* @param transactionId - Transaction identifier
- * @returns Array of OCPP 2.0 meter values at transaction begin
+ * @returns Array of OCPP 2.0.1 meter values at transaction begin
*/
static buildTransactionStartedMeterValues (
chargingStation: ChargingStation,
}
/**
- * OCPP 2.0 Incoming Request Service validator configurations
+ * OCPP 2.0.1 Incoming Request Service validator configurations
* @returns Array of validator configuration tuples
*/
public static createIncomingRequestPayloadConfigs = (): [
][] => createPayloadConfigs(OCPP20ServiceUtils.incomingRequestSchemaNames, 'Request.json')
/**
- * Configuration for OCPP 2.0 Incoming Request Response validators
+ * Configuration for OCPP 2.0.1 Incoming Request Response validators
* @returns Array of validator configuration tuples
*/
public static createIncomingRequestResponsePayloadConfigs = (): [
][] => createPayloadConfigs(OCPP20ServiceUtils.incomingRequestSchemaNames, 'Response.json')
/**
- * Factory options for OCPP 2.0 payload validators
+ * Factory options for OCPP 2.0.1 payload validators
* @param moduleName - Name of the OCPP module
* @param methodName - Name of the method/command
- * @returns Factory options object for OCPP 2.0 validators
+ * @returns Factory options object for OCPP 2.0.1 validators
*/
public static createPayloadOptions = (moduleName: string, methodName: string) =>
PayloadValidatorOptions(
)
/**
- * OCPP 2.0 Request Service validator configurations
+ * OCPP 2.0.1 Request Service validator configurations
* @returns Array of validator configuration tuples
*/
public static createRequestPayloadConfigs = (): [
][] => createPayloadConfigs(OCPP20ServiceUtils.outgoingRequestSchemaNames, 'Request.json')
/**
- * OCPP 2.0 Response Service validator configurations
+ * OCPP 2.0.1 Response Service validator configurations
* @returns Array of validator configuration tuples
*/
public static createResponsePayloadConfigs = (): [
} else {
transactionId = connectorStatus.transactionId.toString()
logger.warn(
- `${chargingStation.logPrefix()} ${moduleName}.resolveActiveTransaction: Non-string transaction ID ${transactionId} converted to string for OCPP 2.0`
+ `${chargingStation.logPrefix()} ${moduleName}.resolveActiveTransaction: Non-string transaction ID ${transactionId} converted to string for OCPP 2.0.1`
)
}
return { connectorStatus, transactionId }
/**
- * Testable wrapper for OCPP 2.0 RequestService
+ * Testable wrapper for OCPP 2.0.1 RequestService
*
* This module provides type-safe testing utilities for OCPP20RequestService.
* It enables mocking of the protected sendMessage method and provides access
/**
- * Testable wrapper for OCPP 2.0 ResponseService
+ * Testable wrapper for OCPP 2.0.1 ResponseService
*
* This module provides type-safe access to private handler methods of
* OCPP20ResponseService for testing purposes. It replaces ad hoc
/**
- * Testable interface for OCPP 2.0 IncomingRequestService
+ * Testable interface for OCPP 2.0.1 IncomingRequestService
*
* This module provides type-safe access to private handler methods for testing purposes.
* It replaces `as any` casts with a properly typed interface, enabling:
) => OCPP20DataTransferResponse
/**
- * Handles OCPP 2.0 DeleteCertificate request from central system.
+ * Handles OCPP 2.0.1 DeleteCertificate request from central system.
* Deletes a certificate matching the provided hash data from the charging station.
*/
handleRequestDeleteCertificate: (
) => Promise<OCPP20DeleteCertificateResponse>
/**
- * Handles OCPP 2.0 GetBaseReport request.
+ * Handles OCPP 2.0.1 GetBaseReport request.
* Returns device model report based on the requested report base type.
*/
handleRequestGetBaseReport: (
) => OCPP20GetBaseReportResponse
/**
- * Handles OCPP 2.0 GetInstalledCertificateIds request from central system.
+ * Handles OCPP 2.0.1 GetInstalledCertificateIds request from central system.
* Returns list of installed certificates matching the optional filter types.
*/
handleRequestGetInstalledCertificateIds: (
) => OCPP20GetTransactionStatusResponse
/**
- * Handles OCPP 2.0 GetVariables request.
+ * Handles OCPP 2.0.1 GetVariables request.
* Returns values for requested variables from the device model.
*/
handleRequestGetVariables: (
) => OCPP20GetVariablesResponse
/**
- * Handles OCPP 2.0 InstallCertificate request from central system.
+ * Handles OCPP 2.0.1 InstallCertificate request from central system.
* Installs a certificate of the specified type in the charging station.
*/
handleRequestInstallCertificate: (
) => Promise<OCPP20InstallCertificateResponse>
/**
- * Handles OCPP 2.0 Reset request.
+ * Handles OCPP 2.0.1 Reset request.
* Performs immediate or scheduled reset of charging station or specific EVSE.
*/
handleRequestReset: (
) => OCPP20SetNetworkProfileResponse
/**
- * Handles OCPP 2.0 SetVariables request.
+ * Handles OCPP 2.0.1 SetVariables request.
* Sets values for requested variables in the device model.
*/
handleRequestSetVariables: (
) => OCPP20SetVariablesResponse
/**
- * Handles OCPP 2.0 RequestStartTransaction request from central system.
+ * Handles OCPP 2.0.1 RequestStartTransaction request from central system.
* Initiates charging transaction on specified EVSE with enhanced authorization.
*/
handleRequestStartTransaction: (
) => Promise<OCPP20RequestStartTransactionResponse>
/**
- * Handles OCPP 2.0 RequestStopTransaction request from central system.
+ * Handles OCPP 2.0.1 RequestStopTransaction request from central system.
* Validates and returns Accepted/Rejected. Actual stop is performed by event listener.
*/
handleRequestStopTransaction: (
status: TriggerMessageStatus.REJECTED,
})
- static readonly OCPP_WEBSOCKET_TIMEOUT_MS = 60000
-
+ static readonly OCPP_WEBSOCKET_TIMEOUT_MS = 60_000
static readonly UNKNOWN_OCPP_COMMAND = 'unknown OCPP command' as
IncomingRequestCommand | RequestCommand
signingConfig: SampledValueSigningConfig | undefined
/**
* Passed by reference; the closure assigned to `buildVersionedSampledValue`
- * mutates its `publicKeyIncluded` flag when a signed OCPP 2.0 SampledValue
+ * mutates its `publicKeyIncluded` flag when a signed OCPP 2.0.1 SampledValue
* is emitted. Callers rely on the reference identity to detect the mutation.
*/
signingState: { publicKeyIncluded: boolean }
* @param chargingStation - Target charging station.
* @param transactionId - Active transaction identifier.
* @param context - Optional MeterValue reading context (drives signing
- * configuration for OCPP 2.0).
+ * configuration for OCPP 2.0.1).
* @returns The dispatch bundle.
*/
const createVersionedSampledValueDispatcher = (
? ((phase + 1) % chargingStation.getNumberOfPhases()).toString()
: chargingStation.getNumberOfPhases().toString()
const lineToLineLabel = `L${phase.toString()}-L${nextPhase}` as MeterValuePhase
- const lineToLineNominalVoltage = roundTo(
- Math.sqrt(chargingStation.getNumberOfPhases()) * chargingStation.getVoltageOut(),
- 2
- )
+ // `V_LL = sqrt(3) * V_LN` in a balanced 3-phase Y system; the
+ // sqrt(3) factor comes from the 30-degree phase separation, not
+ // from the phase count itself. Emitting L-L values makes physical
+ // sense only for `numberOfPhases === 3`; single-phase has no L-L
+ // pair, and `numberOfPhases === 2` is unsupported by contract.
+ const lineToLineNominalVoltage = roundTo(Math.sqrt(3) * chargingStation.getVoltageOut(), 2)
addPhaseVoltageToMeterValue(
chargingStation,
connectorId,
* @param connectorId - Connector ID to look up templates for
* @param measurandsKey - Configuration key containing the list of sampled measurands
* @param measurand - Meter value measurand to match
- * @param evseId - Optional EVSE ID for OCPP 2.0 template lookup
+ * @param evseId - Optional EVSE ID for OCPP 2.0.1 template lookup
* @param phase - Optional phase to match in the template
* @returns Matching sampled value template, or undefined if not found
*/
const moduleName = 'OCPP20AuthAdapter'
/**
- * OCPP 2.0 Authentication Adapter
+ * OCPP 2.0.1 Authentication Adapter
*
- * Handles authentication for OCPP 2.0/2.1 charging stations by translating
- * between auth types and OCPP 2.0 specific types and protocols.
+ * Handles authentication for OCPP 2.0.1 charging stations by translating
+ * between auth types and OCPP 2.0.1 specific types and protocols.
*/
export class OCPP20AuthAdapter implements OCPPAuthAdapter<OCPP20IdTokenType> {
readonly ocppVersion = OCPPVersion.VERSION_201
constructor (private readonly chargingStation: ChargingStation) {}
/**
- * Perform remote authorization using OCPP 2.0 Authorize request.
+ * Perform remote authorization using OCPP 2.0.1 Authorize request.
* @param identifier - Identifier containing the IdToken to authorize
* @param connectorId - EVSE/connector ID for the authorization context
* @param transactionId - Optional existing transaction ID for ongoing transactions
- * @returns Authorization result with status, method, and OCPP 2.0 specific metadata
+ * @returns Authorization result with status, method, and OCPP 2.0.1 specific metadata
*/
async authorizeRemote (
identifier: Identifier,
try {
logger.debug(
- `${this.chargingStation.logPrefix()} ${moduleName}.${methodName}: Authorizing identifier '${truncateId(identifier.value)}' via OCPP 2.0 Authorize`
+ `${this.chargingStation.logPrefix()} ${moduleName}.${methodName}: Authorizing identifier '${truncateId(identifier.value)}' via OCPP 2.0.1 Authorize`
)
const isRemoteAuth = this.isRemoteAvailable()
return {
additionalInfo: {
connectorId,
- error: 'Invalid token format for OCPP 2.0',
+ error: 'Invalid token format for OCPP 2.0.1',
transactionId,
},
isOffline: false,
}
/**
- * Convert identifier to OCPP 2.0 IdToken
- * @param identifier - Identifier to convert to OCPP 2.0 format
- * @returns OCPP 2.0 IdTokenType with mapped type and additionalInfo
+ * Convert identifier to OCPP 2.0.1 IdToken
+ * @param identifier - Identifier to convert to OCPP 2.0.1 format
+ * @returns OCPP 2.0.1 IdTokenType with mapped type and additionalInfo
*/
convertFromIdentifier (identifier: Identifier): OCPP20IdTokenType {
- // Map type back to OCPP 2.0 type
+ // Map type back to OCPP 2.0.1 type
const ocpp20Type = mapToOCPP20TokenType(identifier.type)
- // Convert additionalInfo back to OCPP 2.0 format
+ // Convert additionalInfo back to OCPP 2.0.1 format
const additionalInfo: AdditionalInfoType[] | undefined = identifier.additionalInfo
? Object.entries(identifier.additionalInfo)
.filter(([key]) => key.startsWith('info_'))
}
/**
- * Convert OCPP 2.0 IdToken to identifier
- * @param identifier - OCPP 2.0 IdToken or raw string identifier
+ * Convert OCPP 2.0.1 IdToken to identifier
+ * @param identifier - OCPP 2.0.1 IdToken or raw string identifier
* @param additionalData - Optional metadata to include in the identifier
* @returns Identifier with normalized type and metadata
*/
}
/**
- * Convert authorization result to OCPP 2.0 response format
+ * Convert authorization result to OCPP 2.0.1 response format
* @param result - Authorization result to convert
- * @returns OCPP 2.0 RequestStartStopStatusEnumType for transaction responses
+ * @returns OCPP 2.0.1 RequestStartStopStatusEnumType for transaction responses
*/
convertToOCPP20Response (result: AuthorizationResult): RequestStartStopStatusEnumType {
return mapToOCPP20Status(result.status)
}
/**
- * Create authorization request from OCPP 2.0 context
- * @param idTokenOrString - OCPP 2.0 IdToken or raw string identifier
+ * Create authorization request from OCPP 2.0.1 context
+ * @param idTokenOrString - OCPP 2.0.1 IdToken or raw string identifier
* @param connectorId - Optional EVSE/connector ID for the request
* @param transactionId - Optional transaction ID for ongoing transactions
* @param context - Optional context string (e.g., 'start', 'stop', 'remote_start')
}
/**
- * @returns Configuration schema object for OCPP 2.0 authorization settings
+ * @returns Configuration schema object for OCPP 2.0.1 authorization settings
*/
getConfigurationSchema (): JsonObject {
return {
minimum: 1,
type: 'number',
},
- // OCPP 2.0 specific variables
+ // OCPP 2.0.1 specific variables
authorizeRemoteStart: {
description: 'Enable remote authorization via RequestStartTransaction',
type: 'boolean',
}
/**
- * @returns Always undefined — OCPP 2.0 defines capacity via LocalAuthListCtrlr.Storage (bytes), not entry count
+ * @returns Always undefined — OCPP 2.0.1 defines capacity via LocalAuthListCtrlr.Storage (bytes), not entry count
*/
getMaxLocalAuthListEntries (): number | undefined {
return undefined
isOnline: this.chargingStation.inAcceptedState(),
localAuthEnabled: true, // Configuration dependent
ocppVersion: this.ocppVersion,
- remoteAuthEnabled: true, // Always available in OCPP 2.0
+ remoteAuthEnabled: true, // Always available in OCPP 2.0.1
stationId: this.chargingStation.stationInfo?.chargingStationId,
supportsIdTokenTypes: [
OCPP20IdTokenEnumType.Central,
}
/**
- * Check if remote authorization is available for OCPP 2.0
+ * Check if remote authorization is available for OCPP 2.0.1
* @returns True if remote authorization is available and enabled
*/
isRemoteAvailable (): boolean {
}
/**
- * Check if identifier is valid for OCPP 2.0
- * @param identifier - Identifier to validate against OCPP 2.0 rules
- * @returns True if identifier meets OCPP 2.0 format requirements (max 36 chars, valid type)
+ * Check if identifier is valid for OCPP 2.0.1
+ * @param identifier - Identifier to validate against OCPP 2.0.1 rules
+ * @returns True if identifier meets OCPP 2.0.1 format requirements (max 36 chars, valid type)
*/
isValidIdentifier (identifier: Identifier): boolean {
- // OCPP 2.0 idToken validation
+ // OCPP 2.0.1 idToken validation
if (!identifier.value || typeof identifier.value !== 'string') {
return false
}
- // Check length (OCPP 2.0 spec: max 36 characters)
+ // Check length (OCPP 2.0.1 spec: max 36 characters)
if (isEmpty(identifier.value) || identifier.value.length > 36) {
return false
}
- // OCPP 2.0 supports multiple identifier types
+ // OCPP 2.0.1 supports multiple identifier types
const validTypes = [
IdentifierType.ID_TAG,
IdentifierType.CENTRAL,
}
/**
- * Validate adapter configuration for OCPP 2.0
+ * Validate adapter configuration for OCPP 2.0.1
* @param config - Authentication configuration to validate
- * @returns Promise resolving to true if configuration is valid for OCPP 2.0 operations
+ * @returns Promise resolving to true if configuration is valid for OCPP 2.0.1 operations
*/
validateConfiguration (config: AuthConfiguration): boolean {
try {
/**
* OCPP Authentication System
*
- * Authentication layer for OCPP 1.6 and 2.0 protocols.
+ * Authentication layer for OCPP 1.6 and 2.0.1 protocols.
* This module provides a consistent API for handling authentication
* across different OCPP versions, with support for multiple authentication
* strategies including local lists, remote authorization, and certificate-based auth.
OCPPAuthService,
} from './interfaces/OCPPAuthService.js'
export { OCPPAuthServiceFactory } from './services/OCPPAuthServiceFactory.js'
-export { OCPPAuthServiceImpl } from './services/OCPPAuthServiceImpl.js'
export {
type AuthConfiguration,
AuthContext,
const CERTIFICATE_VERIFY_DELAY_MS = 100
/**
- * Certificate-based authentication strategy for OCPP 2.0+
+ * Certificate-based authentication strategy for OCPP 2.0.1
*
* This strategy handles PKI-based authentication using X.509 certificates.
- * It's primarily designed for OCPP 2.0 where certificate-based authentication
+ * It's primarily designed for OCPP 2.0.1 where certificate-based authentication
* is supported and can provide higher security than traditional ID token auth.
*
* Priority: 3 (lowest - used as fallback or for high-security scenarios)
const adapter = this.adapter
- // For OCPP 2.0, we can use certificate-based validation
+ // For OCPP 2.0.1, we can use certificate-based validation
if (this.adapter.ocppVersion === OCPPVersion.VERSION_201) {
const result = await this.validateCertificateWithOCPP20(request, adapter, config)
this.updateStatistics(result, startTime)
return false
}
- // Only supported in OCPP 2.0+
+ // Only supported in OCPP 2.0.1
if (this.adapter.ocppVersion === OCPPVersion.VERSION_16) {
return false
}
}
/**
- * Validate certificate using OCPP 2.0 mechanisms
+ * Validate certificate using OCPP 2.0.1 mechanisms
* @param request - Authorization request with certificate identifier
- * @param adapter - OCPP 2.0 adapter for protocol-specific operations
+ * @param adapter - OCPP 2.0.1 adapter for protocol-specific operations
* @param config - Authentication configuration settings
* @returns Authorization result indicating certificate validation outcome
*/
)
}
} catch (error) {
- logger.error(`${moduleName}: OCPP 2.0 certificate validation error:`, error)
+ logger.error(`${moduleName}: OCPP 2.0.1 certificate validation error:`, error)
return this.createFailureResult(
AuthorizationStatus.INVALID,
'Certificate validation error',
INVALID = 'Invalid',
- // OCPP 2.0 specific
+ // OCPP 2.0.1 specific
NO_CREDIT = 'NoCredit',
NOT_ALLOWED_TYPE_EVSE = 'NotAllowedTypeEVSE',
export enum IdentifierType {
BIOMETRIC = 'Biometric',
- // OCPP 2.0 types (mapped from OCPP20IdTokenEnumType)
+ // OCPP 2.0.1 types (mapped from OCPP20IdTokenEnumType)
CENTRAL = 'Central',
// Future extensibility
CERTIFICATE = 'Certificate',
certificateValidationStrict?: boolean
/**
- * Disable post-authorize behavior for non-Accepted cached/local list tokens (OCPP 2.0).
+ * Disable post-authorize behavior for non-Accepted cached/local list tokens (OCPP 2.0.1).
* When true, non-Accepted tokens from cache or local list are accepted locally without
* triggering a remote AuthorizationRequest (C10.FR.03, C12.FR.05, C14.FR.03).
* When false, non-Accepted cached/local tokens trigger re-authorization via remote.
/** Authentication context */
readonly context: AuthContext
- /** EVSE ID for OCPP 2.0 */
+ /** EVSE ID for OCPP 2.0.1 */
readonly evseId?: number
/** Identifier to authenticate */
}
/**
- * Certificate hash data for PKI-based authentication (OCPP 2.0+)
+ * Certificate hash data for PKI-based authentication (OCPP 2.0.1)
*/
export interface CertificateHashData {
/** Hash algorithm used (SHA256, SHA384, SHA512, etc.) */
* Identifier that works across OCPP versions
*/
export interface Identifier {
- /** Additional info for OCPP 2.0 tokens */
+ /** Additional info for OCPP 2.0.1 tokens */
readonly additionalInfo?: Record<string, string>
/** Certificate hash data for PKI-based authentication */
readonly certificateHashData?: CertificateHashData
- /** Group identifier for group-based authorization (OCPP 2.0) */
+ /** Group identifier for group-based authorization (OCPP 2.0.1) */
readonly groupId?: string
/** Parent ID for hierarchical authorization (OCPP 1.6) */
}
/**
- * Check if identifier type is OCPP 2.0 compatible
+ * Check if identifier type is OCPP 2.0.1 compatible
* @param type - Identifier type to check
- * @returns True if OCPP 2.0 type
+ * @returns True if OCPP 2.0.1 type
*/
export const isOCPP20Type = (type: IdentifierType): boolean => {
return Object.values(OCPP20IdTokenEnumType).includes(type as unknown as OCPP20IdTokenEnumType)
* This allows the authentication system to work seamlessly across OCPP 1.6 and 2.0.
* @remarks
* **Edge cases and limitations:**
- * - OCPP 2.0 specific statuses (NOT_AT_THIS_LOCATION, NOT_AT_THIS_TIME, PENDING, UNKNOWN)
+ * - OCPP 2.0.1 specific statuses (NOT_AT_THIS_LOCATION, NOT_AT_THIS_TIME, PENDING, UNKNOWN)
* map to INVALID when converting to OCPP 1.6
- * - OCPP 2.0 IdToken types have more granularity than OCPP 1.6 IdTag
- * - Certificate-based auth (IdentifierType.CERTIFICATE) is only available in OCPP 2.0+
- * - When mapping to OCPP 2.0, unsupported types default to Local
+ * - OCPP 2.0.1 IdToken types have more granularity than OCPP 1.6 IdTag
+ * - Certificate-based auth (IdentifierType.CERTIFICATE) is only available in OCPP 2.0.1
+ * - When mapping to OCPP 2.0.1, unsupported types default to Local
*/
/**
}
/**
- * Maps OCPP 2.0 authorization status enum to authorization status
- * @param status - OCPP 2.0 authorization status
+ * Maps OCPP 2.0.1 authorization status enum to authorization status
+ * @param status - OCPP 2.0.1 authorization status
* @returns Authorization status
* @example
* ```typescript
}
/**
- * Maps OCPP 2.0 token type to identifier type
- * @param type - OCPP 2.0 token type
+ * Maps OCPP 2.0.1 token type to identifier type
+ * @param type - OCPP 2.0.1 token type
* @returns Identifier type
* @example
* ```typescript
}
/**
- * Maps authorization status to OCPP 2.0 RequestStartStopStatus
+ * Maps authorization status to OCPP 2.0.1 RequestStartStopStatus
* @param status - Authorization status
- * @returns OCPP 2.0 RequestStartStopStatus
+ * @returns OCPP 2.0.1 RequestStartStopStatus
* @example
* ```typescript
* const ocpp20Status = mapToOCPP20Status(AuthorizationStatus.ACCEPTED)
}
/**
- * Maps identifier type to OCPP 2.0 token type
+ * Maps identifier type to OCPP 2.0.1 token type
* @param type - Identifier type
- * @returns OCPP 2.0 token type
+ * @returns OCPP 2.0.1 token type
* @example
* ```typescript
* const ocpp20Type = mapToOCPP20TokenType(IdentifierType.CENTRAL)
const MAX_IDTAG_LENGTH = 20
/**
- * Maximum length for OCPP 2.0 IdToken
+ * Maximum length for OCPP 2.0.1 IdToken
*/
const MAX_IDTOKEN_LENGTH = 36
}
/**
- * Sanitize IdToken for OCPP 2.0 (max 36 characters)
+ * Sanitize IdToken for OCPP 2.0.1 (max 36 characters)
* @param idToken - Raw IdToken input to sanitize (may be any type)
- * @returns Trimmed and truncated IdToken string conforming to OCPP 2.0 length limit, or empty string for non-string input
+ * @returns Trimmed and truncated IdToken string conforming to OCPP 2.0.1 length limit, or empty string for non-string input
*/
function sanitizeIdToken (idToken: unknown): string {
// Return empty string for non-string input
// Check length constraints based on identifier type
switch (typedIdentifier.type) {
case IdentifierType.BIOMETRIC:
- // Fallthrough intentional: all these OCPP 2.0 types share the same validation
+ // Fallthrough intentional: all these OCPP 2.0.1 types share the same validation
case IdentifierType.CENTRAL:
case IdentifierType.CERTIFICATE:
case IdentifierType.E_MAID:
case IdentifierType.MAC_ADDRESS:
case IdentifierType.MOBILE_APP:
case IdentifierType.NO_AUTHORIZATION:
- // OCPP 2.0 types - use IdToken max length
+ // OCPP 2.0.1 types - use IdToken max length
return (
isNotEmptyString(typedIdentifier.value) &&
typedIdentifier.value.length <= MAX_IDTOKEN_LENGTH
resolveUIServerAccess,
type UIServerAccessCache,
type UIServerAccessDecision,
+ WILDCARD_HOSTS,
} from './UIServerAccessPolicy.js'
import {
createRateLimiter,
const allowedHosts = accessPolicy?.allowedHosts ?? []
const trustedProxies = accessPolicy?.trustedProxies ?? []
const requireTls = accessPolicy?.requireTlsForNonLoopback ?? true
- const isWildcard =
- configuredHost === '' || configuredHost === '0.0.0.0' || configuredHost === '::'
+ const isWildcard = WILDCARD_HOSTS.has(configuredHost)
if (isWildcard && isEmpty(allowedHosts)) {
logger.warn(
if (ocpp16Payload != null && ocpp20Payload != null) {
return UIMCPServer.createToolErrorResponse(
- 'Cannot provide both ocpp16Payload and ocpp20Payload. Use ocpp16Payload for OCPP 1.6 stations or ocpp20Payload for OCPP 2.0 stations.'
+ 'Cannot provide both ocpp16Payload and ocpp20Payload. Use ocpp16Payload for OCPP 1.6 stations or ocpp20Payload for OCPP 2.0.1 stations.'
)
}
)
} catch {
logger.warn(
- `${this.logPrefix(moduleName, 'loadOcppSchemas')} Failed to load OCPP 2.0 schema for ${procedureName}`
+ `${this.logPrefix(moduleName, 'loadOcppSchemas')} Failed to load OCPP 2.0.1 schema for ${procedureName}`
)
}
}
'x-forwarded-proto',
] as const
const SECURE_FORWARDED_PROTOCOLS = new Set(['https', 'wss'])
-const WILDCARD_HOSTS = new Set(['', '0.0.0.0', '::'])
+export const WILDCARD_HOSTS: ReadonlySet<string> = new Set(['', '0.0.0.0', '::'])
/**
* Reasons a UI server access decision is denied.
resetTime: number
}
-export const DEFAULT_MAX_PAYLOAD_SIZE_BYTES = 1048576
+export const DEFAULT_MAX_PAYLOAD_SIZE_BYTES = 1_048_576
export const DEFAULT_RATE_LIMIT = 100
-export const DEFAULT_RATE_WINDOW_MS = 60000
+export const DEFAULT_RATE_WINDOW_MS = 60_000
export const DEFAULT_MAX_STATIONS = 100
-export const DEFAULT_MAX_TRACKED_IPS = 10000
+export const DEFAULT_MAX_TRACKED_IPS = 10_000
export const DEFAULT_COMPRESSION_THRESHOLD_BYTES = 1024
export class PayloadTooLargeError extends BaseError {
static readonly DEFAULT_AUTH_CACHE_RATE_LIMIT_MAX_REQUESTS = 10
- static readonly DEFAULT_AUTH_CACHE_RATE_LIMIT_WINDOW_MS = 60000
-
+ static readonly DEFAULT_AUTH_CACHE_RATE_LIMIT_WINDOW_MS = 60_000
static readonly DEFAULT_AUTH_CACHE_TTL_SECONDS = 3600
- static readonly DEFAULT_BOOT_NOTIFICATION_INTERVAL_MS = 60000
-
+ static readonly DEFAULT_BOOT_NOTIFICATION_INTERVAL_MS = 60_000
static readonly DEFAULT_CIRCULAR_BUFFER_CAPACITY = 386
/** Default coherent MeterValues ramp-up duration in milliseconds. Non-positive values disable the ramp. */
static readonly DEFAULT_HASH_ALGORITHM = 'sha384'
- static readonly DEFAULT_HEARTBEAT_INTERVAL_MS = 60000
-
+ static readonly DEFAULT_HEARTBEAT_INTERVAL_MS = 60_000
static readonly DEFAULT_LOG_STATISTICS_INTERVAL_SECONDS = 60
- static readonly DEFAULT_MESSAGE_BUFFER_FLUSH_INTERVAL_MS = 60000
-
+ static readonly DEFAULT_MESSAGE_BUFFER_FLUSH_INTERVAL_MS = 60_000
static readonly DEFAULT_MESSAGE_TIMEOUT_SECONDS = 30
- static readonly DEFAULT_METER_VALUES_INTERVAL_MS = 60000
-
+ static readonly DEFAULT_METER_VALUES_INTERVAL_MS = 60_000
static readonly DEFAULT_PERFORMANCE_DIRECTORY = 'performance'
static readonly DEFAULT_PERFORMANCE_RECORDS_DB_NAME = 'e-mobility-charging-stations-simulator'
static readonly ENV_SIMULATOR_COLD_START = 'SIMULATOR_COLD_START'
- static readonly MAX_RANDOM_INTEGER = 281474976710655 // 2^48 - 1 (randomInit() limit)
+ static readonly MAX_RANDOM_INTEGER = 281_474_976_710_655 // 2^48 - 1 (randomInit() limit)
// Node.js setInterval/setTimeout maximum safe delay value (2^31-1 ms ≈ 24.8 days)
// Values exceeding this limit cause Node.js to reset the delay to 1ms
- static readonly MAX_SETINTERVAL_DELAY_MS = 2147483647
-
+ static readonly MAX_SETINTERVAL_DELAY_MS = 2_147_483_647
/** Milliseconds per day; equal to `24 * MS_PER_HOUR`. */
static readonly MS_PER_DAY = DAY_IN_MS
/** State of Charge maximum percentage (upper bound for SoC measurand emission). */
static readonly SOC_MAXIMUM_PERCENT = 100
- static readonly STOP_CHARGING_STATIONS_TIMEOUT_MS = 60000
-
- static readonly STOP_MESSAGE_SEQUENCE_TIMEOUT_MS = 30000
-
+ static readonly STOP_CHARGING_STATIONS_TIMEOUT_MS = 60_000
+ static readonly STOP_MESSAGE_SEQUENCE_TIMEOUT_MS = 30_000
/** Divider between base units (A) and centi units (cA). */
static readonly UNIT_DIVIDER_CENTI = 100
assert.strictEqual(response.status, OCPP16UpdateStatus.FAILED)
})
- await it('should return NotSupported when manager is undefined', () => {
+ await it('should return Failed when manager is undefined (feature supported but unavailable per §5.15)', () => {
const { station, testableService } = context
enableLocalAuthListProfile(context)
setupMockAuthService(station, undefined)
const response = testableService.handleRequestSendLocalList(station, request)
- assert.strictEqual(response.status, OCPP16UpdateStatus.NOT_SUPPORTED)
+ assert.strictEqual(response.status, OCPP16UpdateStatus.FAILED)
})
await it('should accept Full update with empty list to clear all entries', () => {
assert.strictEqual(response.status, OCPP16UpdateStatus.FAILED)
})
- await it('should return NotSupported when LocalAuthListEnabled is false', () => {
+ await it('should return Failed when LocalAuthListEnabled is false (feature supported but disabled per §5.15)', () => {
const { station, testableService } = context
enableLocalAuthListProfile(context)
upsertConfigurationKey(station, OCPP16StandardParametersKey.LocalAuthListEnabled, 'false')
const response = testableService.handleRequestSendLocalList(station, request)
- assert.strictEqual(response.status, OCPP16UpdateStatus.NOT_SUPPORTED)
+ assert.strictEqual(response.status, OCPP16UpdateStatus.FAILED)
})
await it('should return VersionMismatch for differential update with version <= current', () => {
assert.strictEqual(typeof response.status, 'string')
})
- await it('should return UnknownMessageId for matching vendor with messageId', () => {
+ await it('should return Accepted for matching vendor with messageId (no messageId registry per §4.3)', () => {
// Arrange
const { station, testableService } = context
const matchingVendor = 'test-vendor-match'
// Assert
assert.notStrictEqual(response, undefined)
- assert.strictEqual(response.status, OCPP16DataTransferStatus.UNKNOWN_MESSAGE_ID)
+ assert.strictEqual(response.status, OCPP16DataTransferStatus.ACCEPTED)
assert.strictEqual(typeof response.status, 'string')
})
})
AuthorizationStatus,
IdentifierType,
OCPPAuthServiceFactory,
- OCPPAuthServiceImpl,
} from '../../../../src/charging-station/ocpp/auth/index.js'
+import { OCPPAuthServiceImpl } from '../../../../src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.js'
import { OCPPVersion } from '../../../../src/types/index.js'
import { standardCleanup } from '../../../helpers/TestLifecycleHelpers.js'
import {
import {
AuthorizationStatus,
OCPPAuthServiceFactory,
- OCPPAuthServiceImpl,
} from '../../../../src/charging-station/ocpp/auth/index.js'
+import { OCPPAuthServiceImpl } from '../../../../src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.js'
import {
OCPP20AuthorizationStatusEnumType,
OCPP20IdTokenEnumType,
assert.deepStrictEqual(result, { idTag: 'RFID123' })
})
- await it('should build idToken payload for OCPP 2.0', () => {
+ await it('should build idToken payload for OCPP 2.0.1', () => {
const result = buildAuthorizePayload('RFID123', OCPPVersion.VERSION_20)
assert.deepStrictEqual(result, {
idToken: { idToken: 'RFID123', type: OCPP20IdTokenEnumType.ISO14443 },
assert.strictEqual((result as Record<string, unknown>).errorCode, undefined)
})
- await it('should build OCPP 2.0 payload with connectorStatus when evseId omitted', () => {
+ await it('should build OCPP 2.0.1 payload with connectorStatus when evseId omitted', () => {
const result = buildStatusNotificationPayload(
connectorId,
OCPP20ConnectorStatusEnumType.OCCUPIED,