ocppsim 0.3.0

A terminal OCPP-J charge point simulator.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
# OCPP Support

This page describes the current implementation scope.
It is intentionally conservative: actions are listed as supported only when the
simulator builds or handles protocol-shaped payloads and has focused tests.

## OCPP 1.6

OCPP 1.6 base JSON-schema actions are the complete support target.
Supported behavior includes:

- boot, heartbeat, authorize, status, meter, and data transfer messages,
- local and remote transaction start and stop, including OCPP 1.6
  remote-start pre-authorization when `AuthorizeRemoteTxRequests` is true,
- configuration get and change,
- clear cache,
- availability changes,
- local authorization list version and updates,
- reservation and cancellation,
- connector unlock,
- simplified smart-charging profile set, filtered clear, and composite
  schedule,
- trigger message for implemented message types,
- simulated diagnostics success flows for configured URI schemes,
- OCPP 1.6 Security Whitepaper certificate installation, deletion, listing,
  certificate signing, signed firmware status, log status, security event, and
  extended trigger-message flows.

Security support is intentionally simulator-level.
The transport layer supports security profiles 1 and 2 with HTTP Basic
authentication and profile 3 with configured client certificate/key paths.
OCPP 1.6 `AuthorizationKey` values must be 32 to 40 ASCII hexadecimal
characters.
OCPP 2.0.1 `BasicAuthPassword` values must be 16 to 40 OCPP
`passwordString` characters, and OCPP 2.1 `BasicAuthPassword` values must be
16 to 64 UTF-8 `passwordString` characters.
For OCPP 2.1 this is compatibility support through `SecurityCtrlr`.
The simulator does not implement the full 2.1 `NetworkConfiguration`
component, `ActiveNetworkProfile`, or `SetNetworkProfile` behavior.
Security password values are write-only on readback and trigger reconnect when
changed on an active connection.
Certificate-management and signed-firmware actions keep an in-memory synthetic
certificate store and obvious invalid-value detection, but they do not perform
full PKI validation, OCSP/CRL checks, real CSR generation, firmware binary
verification, or file transfer.
Known password, ID token, and URL-contained credential values are redacted from
trace-frame logs in both directions.
The original OCPP 1.6 `UpdateFirmware` request is rejected with CALLERROR
`NotSupported`; whitepaper firmware tests should use `SignedUpdateFirmware`.

## OCPP 1.6 Security Whitepaper Coverage

The simulator implements the OCPP message surface and state transitions needed
for CSMS interoperability testing, while keeping cryptographic material
synthetic.

- A01 password update: implemented.
  `AuthorizationKey` is write-only, validated, stored in memory, records a
  security event, and reconnects when changed while connected.
- A02/A03 certificate update: simulated.
  `ExtendedTriggerMessage(SignChargePointCertificate)` can enqueue
  `SignCertificate`, `CertificateSigned` installs a synthetic Charge Point
  certificate, and OCPP 2.1 request ids are correlated when provided.
  Real key generation, CSR creation, and certificate-chain validation are not
  implemented.
- A05 security profile upgrade: implemented at simulator level.
  OCPP 1.6 rejects equal or lower values, checks password, Central System root,
  and configured mTLS prerequisites for higher profiles, reconnects after
  accepted upgrades, and falls back to the previous profile when reconnect
  fails.
- M05 install CA certificate: partially implemented.
  `InstallCertificate` enforces the 5500-character request limit, rejects full
  stores, and keeps deterministic synthetic hashes for list/delete flows.
  `AdditionalRootCertificateCheck` keeps a Central System root plus one
  fallback root, but does not cryptographically verify that the new root was
  signed by the old root.
- N01 log upload: simulated.
  `GetLog` validates supported URI schemes, returns a synthetic filename, and
  enqueues log status notifications.
  No file is uploaded.
- L01 signed firmware: simulated.
  `SignedUpdateFirmware` validates supported URI schemes, emits status
  notifications, records simulated invalid certificate/signature events, and
  original `UpdateFirmware` returns CALLERROR `NotSupported`.
  No firmware is downloaded or cryptographically verified.

Security events are recorded in local simulator state and queued for OCPP
`SecurityEventNotification` delivery until the CSMS acknowledges them with a
CALLRESULT.
Events recorded while disconnected, or queued immediately before a security
reconnect, are replayed after the next successful connection.
Events may also appear in a later simulated security-log export.
Retention is capped by `security-event-limit`; sent events are discarded before
unsent events when the cap is reached.

Synthetic certificate hashes are stable simulator identifiers for tests.
They are not cryptographic certificate fingerprints.

Incoming response status tokens are recognized from the checked-in 1.6,
2.0.1, and 2.1 schemas.

### Trigger Message Scope

OCPP 1.6 standard `TriggerMessage` accepts only the standard schema values:
`BootNotification`, `DiagnosticsStatusNotification`,
`FirmwareStatusNotification`, `Heartbeat`, `MeterValues`, and
`StatusNotification`.
OCPP 1.6 security `ExtendedTriggerMessage` accepts the whitepaper values:
`BootNotification`, `FirmwareStatusNotification`, `Heartbeat`,
`LogStatusNotification`, `MeterValues`, `SignChargePointCertificate`, and
`StatusNotification`.

OCPP 2.0.1 `TriggerMessage` accepts `BootNotification`,
`FirmwareStatusNotification`, `Heartbeat`, `LogStatusNotification`,
`MeterValues`, `SignChargingStationCertificate`, `SignV2GCertificate`,
`StatusNotification`, and `TransactionEvent`.
`SignCombinedCertificate` and `PublishFirmwareStatusNotification` are
schema-valid but return `NotImplemented`.

OCPP 2.1 adds `SignV2G20Certificate` to the accepted trigger list and parses
`CustomTrigger`, which currently returns `NotImplemented`.

## OCPP 2.x Support Matrix

OCPP 2.0.1 and OCPP 2.1 support the same common subset today.
For 2.x actions with larger schemas, support is field-level and conservative:
the simulator consumes the identifiers, status fields, variables, local-list
version, firmware location, and simplified smart-charging schedule data needed
for its implemented behavior, while ignoring optional fields that do not
affect that behavior unless strict mode is enabled.

| Action                       | OCPP 2.0.1 | OCPP 2.1   |
| ---------------------------- | ---------- | ---------- |
| `Authorize`                  | Supported  | Supported  |
| `BootNotification`           | Supported  | Supported  |
| `CancelReservation`          | Supported  | Supported  |
| `CertificateSigned`          | Supported  | Supported  |
| `ChangeAvailability`         | Supported  | Supported  |
| `ClearCache`                 | Supported  | Supported  |
| `ClearChargingProfile`       | Supported  | Supported  |
| `DataTransfer`               | Supported  | Supported  |
| `DeleteCertificate`          | Supported  | Supported  |
| `FirmwareStatusNotification` | Supported  | Supported  |
| `GetCompositeSchedule`       | Supported  | Supported  |
| `GetInstalledCertificateIds` | Supported  | Supported  |
| `GetLocalListVersion`        | Supported  | Supported  |
| `GetLog`                     | Supported  | Supported  |
| `GetVariables`               | Supported  | Supported  |
| `Heartbeat`                  | Supported  | Supported  |
| `InstallCertificate`         | Supported  | Supported  |
| `LogStatusNotification`      | Supported  | Supported  |
| `MeterValues`                | Supported  | Supported  |
| `RequestStartTransaction`    | Supported  | Supported  |
| `RequestStopTransaction`     | Supported  | Supported  |
| `ReserveNow`                 | Supported  | Supported  |
| `Reset`                      | Supported  | Supported  |
| `SecurityEventNotification`  | Supported  | Supported  |
| `SendLocalList`              | Supported  | Supported  |
| `SetChargingProfile`         | Supported  | Supported  |
| `SetVariables`               | Supported  | Supported  |
| `SignCertificate`            | Supported  | Supported  |
| `StatusNotification`         | Supported  | Supported  |
| `TransactionEvent`           | Supported  | Supported  |
| `TriggerMessage`             | Supported* | Supported* |
| `UnlockConnector`            | Supported  | Supported  |
| `UpdateFirmware`             | Supported  | Supported  |

All other schema actions are explicitly unsupported until implemented.
The `TriggerMessage` action is field-level support; see the trigger scope above
for version-specific values.

## Unsupported OCPP 2.0.1 Actions

- `ClearDisplayMessage`
- `ClearVariableMonitoring`
- `ClearedChargingLimit`
- `CostUpdated`
- `CustomerInformation`
- `Get15118EVCertificate`
- `GetBaseReport`
- `GetCertificateStatus`
- `GetChargingProfiles`
- `GetDisplayMessages`
- `GetMonitoringReport`
- `GetReport`
- `GetTransactionStatus`
- `NotifyChargingLimit`
- `NotifyCustomerInformation`
- `NotifyDisplayMessages`
- `NotifyEVChargingNeeds`
- `NotifyEVChargingSchedule`
- `NotifyEvent`
- `NotifyMonitoringReport`
- `NotifyReport`
- `PublishFirmware`
- `PublishFirmwareStatusNotification`
- `ReportChargingProfiles`
- `ReservationStatusUpdate`
- `SetDisplayMessage`
- `SetMonitoringBase`
- `SetMonitoringLevel`
- `SetNetworkProfile`
- `SetVariableMonitoring`
- `UnpublishFirmware`

## Unsupported OCPP 2.1 Actions

- `AFRRSignal`
- `AdjustPeriodicEventStream`
- `BatterySwap`
- `ChangeTransactionTariff`
- `ClearDERControl`
- `ClearDisplayMessage`
- `ClearTariffs`
- `ClearVariableMonitoring`
- `ClearedChargingLimit`
- `ClosePeriodicEventStream`
- `CostUpdated`
- `CustomerInformation`
- `Get15118EVCertificate`
- `GetBaseReport`
- `GetCertificateChainStatus`
- `GetCertificateStatus`
- `GetChargingProfiles`
- `GetDERControl`
- `GetDisplayMessages`
- `GetMonitoringReport`
- `GetPeriodicEventStream`
- `GetReport`
- `GetTariffs`
- `GetTransactionStatus`
- `NotifyAllowedEnergyTransfer`
- `NotifyChargingLimit`
- `NotifyCustomerInformation`
- `NotifyDERAlarm`
- `NotifyDERStartStop`
- `NotifyDisplayMessages`
- `NotifyEVChargingNeeds`
- `NotifyEVChargingSchedule`
- `NotifyEvent`
- `NotifyMonitoringReport`
- `NotifyPeriodicEventStream`
- `NotifyPriorityCharging`
- `NotifyReport`
- `NotifySettlement`
- `NotifyWebPaymentStarted`
- `OpenPeriodicEventStream`
- `PublishFirmware`
- `PublishFirmwareStatusNotification`
- `PullDynamicScheduleUpdate`
- `ReportChargingProfiles`
- `ReportDERControl`
- `RequestBatterySwap`
- `ReservationStatusUpdate`
- `SetDERControl`
- `SetDefaultTariff`
- `SetDisplayMessage`
- `SetMonitoringBase`
- `SetMonitoringLevel`
- `SetNetworkProfile`
- `SetVariableMonitoring`
- `UnpublishFirmware`
- `UpdateDynamicSchedule`
- `UsePriorityCharging`
- `VatNumberValidation`

## Configuration Mapping

OCPP 1.6 configuration keys are stored in one backing map.
For OCPP 2.0.1 and OCPP 2.1, `GetVariables` and `SetVariables` expose that map
as component `ChargingStation` or `SecurityCtrlr` variables.
OCPP 2.1 `NetworkConfiguration` variables are not implemented; Basic Auth
password changes use the backwards-compatible `SecurityCtrlr` mapping.

Supported variable attribute types are `Actual` and `Target`.
`MinSet` and `MaxSet` return `NotSupportedAttributeType`.
Unknown components return `UnknownComponent`, and unknown variables return
`UnknownVariable`.
Read-only variables reject writes.

| Key                              | Writable | Notes                                              |
| -------------------------------- | -------- | -------------------------------------------------- |
| `AdditionalRootCertificateCheck` | No       | Read-only SecurityCtrlr capability flag.           |
| `AllowOfflineTxForUnknownId`     | Yes      | Stored as configuration only.                      |
| `AllowSecurityProfileDowngrade`  | Yes      | OCPP 1.6 still rejects profile downgrades.         |
| `AuthorizeRemoteTxRequests`      | Yes      | Controls OCPP 1.6 remote-start authorization.      |
| `AuthorizationKey`               | Yes      | Write-only 1.6 Basic Auth password.                |
| `BasicAuthPassword`              | Yes      | Write-only 2.x Basic Auth password.                |
| `CertificateSignedMaxChainSize`  | No       | Read-only compatibility alias.                     |
| `CertificateStoreMaxLength`      | No       | Maximum in-memory certificate entries.             |
| `CpoName`                        | Yes      | Stored security organization name.                 |
| `HeartbeatInterval`              | Yes      | Boot/config changes can restart heartbeats.        |
| `MaxCertificateChainSize`        | No       | Read-only certificate chain size limit, max 10000. |
| `MeterValueSampleInterval`       | Yes      | Stored as configuration only.                      |
| `NumberOfConnectors`             | No       | Derived from startup configuration.                |
| `OrganizationName`               | Yes      | Alias for stored security organization name.       |
| `SecurityProfile`                | 1.6 only | 2.x reports active profile as read-only.           |
| `SupportedFeatureProfiles`       | No       | Advertises implemented feature families.           |
| `SupportedFileTransferProtocols` | Yes      | Controls file-transfer URI schemes.                |
| `WebSocketPingInterval`          | Yes      | Stored as configuration only.                      |

`SupportedFileTransferProtocols` is enforced for OCPP 1.6 diagnostics,
OCPP 1.6 `GetLog`, OCPP 1.6 `SignedUpdateFirmware`, OCPP 2.x `GetLog`, and
OCPP 2.x `UpdateFirmware`.
The original OCPP 1.6 `UpdateFirmware` request is rejected for whitepaper
conformance before any URI scheme is considered.

## Behavioral Semantics

The simulator validates required fields before mutating state for supported
inbound flows.
Malformed CALL payloads for supported actions receive format-violation
CALLERROR responses instead of falling back to connector zero, empty strings,
or silent no-op behavior.
The wire error code is `FormationViolation` for OCPP 1.6 and
`FormatViolation` for OCPP 2.x.
Malformed OCPP frames that cannot be parsed receive `ProtocolError`.
Inbound CSMS `CALL` and OCPP 2.1 `SEND` message ids are tracked for the active
WebSocket connection.
Duplicate `CALL` ids receive `OccurrenceConstraintViolation` before dispatch,
and duplicate `SEND` ids are logged and dropped without mutating state.

For OCPP 1.6 and OCPP 2.x, station-initiated OCPP messages are held until
`BootNotification` is accepted.
For OCPP 1.6, `Pending` and `Rejected` registration states block
station-initiated requests until a later accepted boot response.
Reconnects send `BootNotification` only when registration is not accepted yet or
the current boot payload differs from the last queued boot payload, and only
after any OCPP 1.6 non-accepted boot retry interval has expired.
Changing the connection URL, charge point identity, protocol, or security
transport settings clears cached registration state so the next connection
sends `BootNotification` even when the boot payload is otherwise unchanged.
Manual `boot` commands respect the retry interval.
Trigger-message boot requests bypass the interval as allowed by OCPP 1.6.
While OCPP 1.6 registration is rejected, inbound CSMS calls are ignored without
an OCPP response.
Inbound `RemoteStartTransaction`, `RemoteStopTransaction`,
`RequestStartTransaction`, and `RequestStopTransaction` requests are rejected
while boot registration is pending, rejected, or awaiting a response.

Transaction starts are accepted only on known, startable connectors.
Unavailable, faulted, reserved, occupied, and finishing connectors reject
starts.
Already-active connectors reject local starts and OCPP 1.6 remote starts.
For OCPP 2.x `RequestStartTransaction`, an active requested EVSE is accepted
with the existing `transactionId` only while the local transaction has not yet
been authorized by `TransactionEventResponse`.
Already-authorized active EVSEs are rejected.
When a remote start omits a connector or EVSE, the first startable connector is
chosen.

For OCPP 1.6, `AuthorizeRemoteTxRequests` defaults to `true`.
In that mode, an accepted `RemoteStartTransaction` queues `Authorize` first.
The simulator only sends `StartTransaction` after the authorization response is
`Accepted`.
Other authorization statuses, including `ConcurrentTx`, are logged and stop the
remote-start attempt.
When `AuthorizeRemoteTxRequests` is set to `false`, the simulator starts the
transaction immediately and then applies the eventual `StartTransaction.conf`
status from the CSMS.

Availability changes to `Inoperative` are scheduled when the target connector
has an active transaction.
The scheduled `Unavailable` state is applied after the stop or transaction-end
event is acknowledged.

Reservations are keyed by reservation ID and duplicate IDs are rejected.
The local authorization list version is stored, but local authorization list
contents are not used to make authorization decisions.

Smart charging is an effective-limit simulation, not a full profile engine.
One profile is stored per connector.
The first supported limit in the stored profile drives connector suspension and
composite schedule output.
Charging profiles supplied with accepted `RemoteStartTransaction` and
`RequestStartTransaction` requests are applied through the same simplified
store.
A connector with no stored profile returns `Rejected` for composite schedule
requests.
OCPP 1.6 `GetCompositeSchedule` rejects invalid `chargingRateUnit` values with
CALLERROR `PropertyConstraintViolation`.
A stored limit of `0` is different from no profile: it is accepted and drives
the connector into a suspended state while the transaction remains active.
`ClearChargingProfile` honors connector or EVSE, profile ID, purpose, and stack
level filters against that simplified store.
It does not model profile stacking, recurrency, validity windows, phase
constraints, sales tariff data, or time-based schedule precedence.

For OCPP 2.0.1 and OCPP 2.1, each local connector is represented as one EVSE
with `connectorId = 1`.
Multiple physical connectors under one EVSE are not modeled.
OCPP 2.x `UnlockConnector` requests for other `connectorId` values return
`UnknownConnector`.

`Reset`, diagnostics, firmware, and log retrieval requests are simulated
success flows.
They acknowledge the request and enqueue the expected status notifications, but
they do not reboot the process, upload files, or download firmware.

## Strict Inbound Validation

Strict mode can be enabled with `--strict`, global `strict = true`, or
per-charge-point `strict = true`.
When enabled, inbound CALL payloads are validated against the checked-in
request schema before simulator dispatch.
Schema-invalid requests return `FormationViolation` on OCPP 1.6 or
`FormatViolation` on OCPP 2.x without mutating simulator state.
Matching inbound CALLRESULT payloads are validated against the checked-in
response schema before response side effects are applied.
Schema-invalid responses are not applied; OCPP 2.1 also sends
`CALLRESULTERROR` with `FormatViolation`.

Without strict mode, supported inbound actions still validate the fields needed
by implemented behavior, but optional fields outside that behavior may be
ignored.

## Schema Source

The canonical schema paths used by tests are under `schemas/`:

- `schemas/1.6`
- `schemas/2.0.1`
- `schemas/2.1`