EVSE Role Guide
In the EVSE role ChargeLink is the charger-side communication controller (SECC). It advertises itself through SDP on UDP 15118, accepts the vehicle's TCP connection (plain or TLS), frames V2GTP, decodes EXI and answers the protocol sequence. This page explains the listener modes, the lifecycle files, the TLS adapters and the day-to-day commands that apply to every protocol. Protocol-specific steps are in the runbooks.
Listener modes
| Mode | Command shape | Sockets | Use |
|---|---|---|---|
| Dry-run | evse start --dry-run --protocol P --profile-id ID | none | Validate profile and configuration; prints the activation catalog with the exact listener and EVCC commands for every protocol. |
| Timed listener | evse start --protocol P --profile-id ID --host :: ... | UDP 15118, TCP | Listener that stops after --max-runtime-ms (default 500 ms). Useful for port and firewall checks. |
| External-EVCC session | evse start --external-evcc-session ... | UDP 15118, TCP | Keeps listening until the runtime limit or an operator stop; serves the reference responses (or the plant-coupled runtime for ISO 15118-20 DC EIM). |
| Plant-coupled runtime | as above plus --plant-grpc-endpoint, --requested-power-kw, --target-voltage-v and CHARGELINK_ISO20_RUNTIME_PROFILE | UDP 15118, TCP, gRPC client | ISO 15118-20 DC EIM with dynamic responses; started by the VeriStand owner host. |
--foreground is accepted for compatibility with earlier scripts and only recorded; the listener always runs in the foreground of the shell that started it. Use a dedicated PowerShell window per listener and stop it with evse stop from another window or Ctrl+C.
Network options
| Option | Meaning |
|---|---|
--host :: | Bind address. Use :: (all IPv6 interfaces) for an external peer, ::1 for same-PC tests. |
--udp-port 15118 | SDP port. 15118 is the ISO 15118 value; change it only for isolated experiments. |
--tcp-port 50118 | V2GTP port advertised in the SDP response. 0 auto-allocates from 49152–65535. |
--advertise-ipv6 fe80::...%N | The link-local address placed in the SDP response. Must be an address of the bench adapter with its zone index. |
--interface-index N | Windows interface index of the bench adapter; selects the multicast scope for SDP. |
--max-runtime-ms, --heartbeat-interval-ms | Runtime limit and heartbeat period. With --external-evcc-session use a long limit (for example 1800000 ms) and 1000 ms heartbeats. |
--run-id | Your run identifier. Without it ChargeLink generates cl-evse-<unix_ms>. |
--exi-mode chargelink-exi | The native codec. Leave at the default. |
--can-backend, --can-channel, --can-bitrate | Recorded in the session metadata for DC-CAN profiles; no CAN driver is started. |
TLS adapters
| Selection | Adapter | Versions | Client authentication | Use with |
|---|---|---|---|---|
--tls --tls-cert --tls-key --tls-cafile --require-ca | rustls (default) | ISO 15118-20: TLS 1.3 only with the named groups secp521r1 and x448 and the ISO 15118-20 cipher suites (--iso20-curve-profile, --allow-legacy-tls-named-groups); other protocols: 1.2 and 1.3 | Mutual when --require-ca; mandatory for ISO 15118-20 | ISO 15118-20; ISO 15118-2 peers that support TLS 1.3 or plain rustls 1.2 |
--tls --external-evcc-windows-tls --tls-pfx F --tls-pfx-password-env VAR | Windows SChannel | TLS 1.2 only | none | ISO 15118-2 external EVCCs that require TLS 1.2 with ECDSA through the Windows stack |
--tls --external-evcc-dev-tls | rustls, tolerant SNI | TLS 1.2 only | none | Engineering interoperability with development EVCC simulators; never production |
any of the above plus --allow-engineering-tls-identity | as selected | as selected | as selected | Required when the server identity comes from evse tls-material-init (subject marked "ENGINEERING ONLY"); without it the listener refuses to start. Development and test only. |
PEM aliases: --cert, --key, --ca; --tls-pkcs12 for --tls-pfx. Passwords belong in --tls-pfx-password-env, never on the command line. The complete certificate requirements are in TLS, PKI and Plug & Charge.
Lifecycle and role locks
Every listener owns a session directory under the runtime root and an active role lock:
<runtime-root>\sessions\<run-id>\state.json protocol, profile, host, ports, status
<runtime-root>\sessions\<run-id>\pid.json process id and executable
<runtime-root>\sessions\<run-id>\lock.json session lock, stale_after_ms 300000
<runtime-root>\sessions\<run-id>\heartbeat.json sequence and last heartbeat time
<runtime-root>\sessions\<run-id>\lifecycle.log starting / running / stopped lines
<runtime-root>\sessions\<run-id>\stop.flag written by evse stop
<runtime-root>\active\evse.lock.json one EVSE at a time per runtime root
Only one EVSE session can be live per runtime root. A second evse start fails with CL-RUNTIME-001 while the lock is held. A session becomes stale when its PID is gone or the heartbeat is older than 300 s; stale sessions are inspectable but do not block a new start after recovery.
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse status # the active session (or --run-id X)
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse list-state
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json runtime list --role evse
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json runtime inspect --run-id <RUN_ID>
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json runtime locks
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse stop --run-id <RUN_ID> # writes stop.flag; the listener exits at its next heartbeat
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json runtime recover --stale-only --dry-run
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json runtime recover --stale-only # release locks of dead sessions
Never delete runtime files by hand while a listener is running. evse live-preflight --recover-stale performs the same recovery as part of the preflight.
Evidence produced by a listener
| File (under the run directory) | Content |
|---|---|
command_result.json | The JSON result of the command, as printed. |
evse_listener_status.json, evse_runtime_status.json, live_runtime_status.json | Bound ports, advertised address, stop reason, runtime state. |
sdp_diagnostics.json | SDP requests received and responses sent. |
tls_handshake_diagnostics.json | Negotiated version, cipher, peer certificate metadata (fingerprints, no bodies). |
session_handshake_artifact_gate.json | Required versus observed states and messages; status passed, attention_required, failed or not_evaluated. |
traces\evse-listener.jsonl, traces\live-v2gtp-frames.jsonl | Chronological listener events and every V2GTP frame with direction, payload type, length and decode verdict. |
protocol\*-live-stack-evidence.json | Lane-specific evidence (for example ISO 15118-2 AC/DC and PnC). |
manifest.json | Inventory with SHA-256 per file and redaction class. |
Evaluate a run with evse live-closure-gate --run-id X --source external-evcc --require-sdp --require-tcp-peer --require-tls --require-v2gtp --require-exi. Each --require-* flag turns a missing observation into a gate failure.
Diagnostic lanes without a peer
These commands write evidence from built-in fixtures and are useful for regression and support cases:
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse listener-policy
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse external-evcc-session-policy # the activation catalog for every protocol
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse iso20-setup-path --write-artifacts
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse iso20-dc-charge-loop-path --write-artifacts
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse iso20-completion-pass --write-artifacts
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse iso2-setup-path --write-artifacts
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse din70121-dc-setup-path --write-artifacts
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse legacy-hlc-completion-pass --protocol all --energy-mode all --write-artifacts
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse tls-pki-doctor --tls --tls-cert C --tls-key K --tls-cafile CA --require-ca
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse live-closure-plan --advertise-ipv6 $Advertise --interface-index $IfIndex
Safety rule for physical benches
The reference-responder lanes never command a power stage. The plant-coupled lane commands a simulated plant through the VeriStand owner host, whose safe start-up profile keeps the contactor open and current at zero until the protocol and the safety inputs (Safety.InterlockClosed, Safety.IsolationValid, Safety.EmergencyStop) permit closure, and which fails safe on watchdog expiry. Any coupling to real power electronics is outside the software and requires its own safety design.

