ISO 15118-2
ChargeLink plays both roles of ISO 15118-2 (2014) for AC and DC EIM sessions, over IPv6 SDP, TCP or TLS 1.2 with server authentication, V2GTP and EXI. As vehicle, ChargeLink runs one session against your charger: iso2-evcc for DC, iso2-ac-evcc for AC. As charger, ChargeLink runs plant-coupled on the NI VeriStand bench for AC and DC; for DC there is also a generic listener that answers the message sequence without a plant.
Before you start
| Requirement | What you need |
|---|---|
| Hardware | A Windows PC for ChargeLink with an Ethernet adapter on the link to the other side. For the plant-coupled charger: the NI VeriStand bench of the package. A powerline (PLC) link needs the hardware described in Connecting to Real PLC Hardware. |
| Network | IPv6 enabled on that adapter; link-local addresses (fe80::/10), no router. UDP 15118 (SDP) and the TCP port of the session (default 50118) open in Windows Firewall for fe80::/10 (Install and Activate). Run the preflight. |
| Licence | An active ChargeLink licence on the ChargeLink PC (chargelink --json license status). A command that needs it stops with exit code 20 (CL-LICENSE-001). |
| TLS material | Optional. EIM runs on TLS 1.2 with server authentication (the charger presents a private-environment identity that the vehicle trusts) or on plain TCP in a trusted environment. As charger: a SECC chain and key (iso2-pki generates an engineering set), or for the generic listener with Windows SChannel a PKCS#12 (PFX) identity. As vehicle: the private operator root the charger's chain validates to. See TLS and PKI. |
$CL = 'C:\Program Files\DEVlink\ChargeLink\<VERSION>\charger\bin\chargelink.exe'
$Data = "$env:ProgramData\DEVlink\ChargeLink\data"
$IfIndex = <INTERFACE_INDEX>
$Advertise = 'fe80::<ADDRESS>%' + $IfIndex
$Pki = "$Data\pki"
The kit has a charger\ and a vehicle\ folder; chargelink.exe is the same binary in both.
# engineering TLS identity for the private environment (SECC chain and key, private root); the folder must not exist
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json iso2-pki --output-dir "$Data\pki\iso2"
ChargeLink as charger
| Charger | Profile ID | What it does |
|---|---|---|
| DC, plant-coupled | iso15118_2_dc_eim | Full DC EIM session on the NI VeriStand bench; the plant values come from the bench. Needs --plant-grpc-endpoint, --requested-power-kw and --target-voltage-v. |
| AC, plant-coupled | iso15118_2_ac_eim | Full AC EIM session on the NI VeriStand bench. Needs --plant-grpc-endpoint. |
| DC, generic listener | iso15118_2_dc_evse_reference (aliases iso2-dc-eim-nominal, dc_fast); with SChannel TLS iso2-dc-eim-tls-schannel | Answers the message sequence with scripted replies and no plant (no contactor, no energy). Protocol exchange only. |
The plant-coupled AC and DC chargers are verified with the ChargeLink vehicle on the VeriStand bench.
Plant-coupled charger (AC and DC)
The charger runs on the NI VeriStand bench, coupled to the bench's plant endpoint. The session has this shape (DC shown; for AC use --profile-id iso15118_2_ac_eim with the same power and voltage targets):
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse start --run-id $Run `
--protocol iso15118-2 --profile-id iso15118_2_dc_eim `
--plant-grpc-endpoint <BENCH_PLANT_ENDPOINT> --requested-power-kw <kW> --target-voltage-v <V> `
--host '::' --interface-index $IfIndex --advertise-ipv6 $Advertise `
--tls --tls-cert "$Data\pki\iso2\secc-chain.pem" --tls-key "$Data\pki\iso2\secc-key.pem" --allow-engineering-tls-identity
Leave out the --tls options for plain TCP. --allow-engineering-tls-identity is needed with the engineering identity from iso2-pki.
Generic listener (DC)
The generic listener answers your vehicle's DC EIM requests with scripted replies. It checks discovery, transport, optional TLS, V2GTP framing and message sequencing; it has no plant and delivers no energy, and it is not for full sessions.
$Run = "iso2-dc-$(Get-Date -Format yyyyMMdd-HHmmss)"
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse live-preflight --source external-evcc `
--protocol iso15118-2 --profile-id iso15118_2_dc_evse_reference `
--host '::' --tcp-port 50118 --udp-port 15118 `
--advertise-ipv6 $Advertise --interface-index $IfIndex --recover-stale
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse start --external-evcc-session --run-id $Run `
--protocol iso15118-2 --profile-id iso15118_2_dc_evse_reference `
--host '::' --tcp-port 50118 --udp-port 15118 `
--advertise-ipv6 $Advertise --interface-index $IfIndex `
--max-runtime-ms 1800000 --heartbeat-interval-ms 1000
TLS 1.2 with Windows SChannel and a PKCS#12 identity: keep the PFX password out of shell history with an environment variable.
$env:CHARGELINK_PFX_PASSWORD = Read-Host 'PFX password'
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse start --external-evcc-session --run-id $Run `
--protocol iso15118-2 --profile-id iso2-dc-eim-tls-schannel `
--host '::' --tcp-port 50118 --udp-port 15118 `
--advertise-ipv6 $Advertise --interface-index $IfIndex `
--tls --external-evcc-windows-tls `
--tls-pfx "$Pki\secc-identity.pfx" --tls-pfx-password-env CHARGELINK_PFX_PASSWORD `
--max-runtime-ms 1800000
--external-evcc-windows-tls is an alias for --tls-adapter windows-schannel-external-evcc --tls-sni-policy external-evcc-windows-schannel. Without SChannel, --tls --tls-cert --tls-key --tls-cafile uses the built-in TLS adapter.
What a good session looks like
Watch from a second window with evse status --run-id $Run. In the run folder <artifact-root>\<run-id>\, after the session:
evse_listener_status.jsonreads"status": "stopped";stop_reasonsays how it stopped.- The last row of
traces\live-v2gtp-frames.jsonlis the outbound SessionStopRes. command_result.jsonreads"session_status": "stopped".- An AC session also writes
protocol\iso2_ac_frames.jsonl.
Do not judge an ISO 15118-2 run by summary.json. For ISO 15118-2, the "status" in summary.json can read "attention_required" after a good session. Read the result in evse_listener_status.json and command_result.json instead.
ChargeLink as vehicle
Your DUT is a charger or SECC. Connect it to the ChargeLink PC's adapter. The vehicle discovers your charger by SDP, connects over TLS 1.2 (server authentication) or TCP, and runs one session: iso2-evcc for DC EIM, iso2-ac-evcc for AC EIM.
DC EIM: iso2-evcc
# discover the charger by SDP, TLS 1.2, 20 CurrentDemandReqs
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json iso2-evcc --sdp-server "[fe80::<CHARGER_ADDRESS>%$IfIndex]:15118" `
--tls --tls-root "<PRIVATE_ROOT_OF_THE_CHARGER>.pem" `
--current-demands 20 --target-voltage-v 400 --target-current-a 100 --run-id iso2-ev-<DATE> --artifact-root "$Data\artifacts"
# without SDP, plain TCP, straight to the charger port
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json iso2-evcc --peer "[fe80::<CHARGER_ADDRESS>%$IfIndex]:<SECC_TCP_PORT>" --current-demands 0 --run-id iso2-ev-<DATE>
| Option | Meaning |
|---|---|
--sdp-server / --peer | Discover the charger through SDP (its UDP socket, [<charger link-local>%<interface>]:15118), or connect to its TCP or TLS port directly. |
--tls, --tls-root FILE | TLS 1.2 with the cipher suites of ISO 15118-2; without --tls EIM runs on TCP. --tls-root names the private operator root(s) the charger chain must validate to (repeatable). |
--current-demands N, --period-ms | CurrentDemandReqs before the vehicle stops (0: until the charger stops) and their period (default 50 ms). |
--renegotiate-after N | After N CurrentDemands the vehicle renegotiates once. |
--pause, --resume-session-id HEX | End with SessionStop Pause instead of Terminate; resume a paused session by its SessionID. |
--target-voltage-v, --target-current-a, --max-voltage-v, --max-current-a | The vehicle's targets and limits (defaults 400 V, 100 A, 920 V, 200 A). |
--connect-timeout-ms | Connection timeout (default 2000 ms). |
--run-id, --artifact-root | Run ID and the folder the run folder is written to. |
AC EIM: iso2-ac-evcc
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json iso2-ac-evcc --sdp-server "[fe80::<CHARGER_ADDRESS>%$IfIndex]:15118" `
--tls --tls-root "<PRIVATE_ROOT_OF_THE_CHARGER>.pem" `
--energy-transfer-mode ac-three-phase --ev-max-current-a 16 --charging-statuses 20 --run-id iso2-ac-ev-<DATE> --artifact-root "$Data\artifacts"
| Option | Meaning |
|---|---|
--sdp-server | The charger's SDP socket, [<charger link-local>%<interface>]:15118. The vehicle discovers the charger by SDP, then runs one session. |
--tls, --tls-root FILE | TLS 1.2 with server authentication against the private root; without --tls EIM runs on TCP. |
--energy-transfer-mode ac-three-phase|ac-single-phase | The AC energy transfer mode the vehicle requests. |
--ev-max-current-a A | The vehicle's maximum current per phase (default 16). |
--charging-statuses N | ChargingStatus exchanges before the vehicle stops. |
--run-id, --artifact-root | Run ID and the folder the run folder is written to. |
What a good session looks like
- The command exits with code 0.
<artifact-root>\<run-id>\iso2_evcc_report.jsonreads"passed": true, withrun.session.outcome={"outcome": "ended", "end": "stopped", "charging_session": "Terminate"}.- The frames are in
traces\live-v2gtp-frames.jsonl.
The reference vehicle profiles (iso15118_2_dc_evcc_reference, iso15118_2_ac_evcc_reference, iso15118_2_dc_evcc_aged_demo) send a ChargeLink-specific encoding that a real charger does not decode. Use them only for evcc start --dry-run and the deterministic simulation. Deterministic simulation for ISO 15118-2 and DIN 70121 is available on request through DEVlink support.
Results and evidence
Each run writes one folder under the artifact root, $Data\artifacts\<run-id>. Stop the charger, then check the evidence:
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json evse stop --run-id $Run
chargelink --runtime-root "$Data\runtime" --artifact-root "$Data\artifacts" --json artifacts integrity --run-id $Run
Judge the charger run by evse_listener_status.json and command_result.json, and the vehicle run by iso2_evcc_report.json (see the good-session lists above). artifacts integrity confirms that no file changed after the run. See Trace, Evidence and Reports. The ISO 15118-4 test-case identifiers are available for campaign work in the Test Workflow.
In DEVlink's own interoperability tests, ChargeLink's ISO 15118-2 charger and vehicle (AC and DC, TLS 1.2 and TCP) completed sessions with an independent open-source ISO 15118 implementation. This is not certification.
Limits
- External Payment (EIM) only. ChargeLink does not provide Plug & Charge (Contract payment, PaymentDetails, CertificateInstallation/Update):
evse startrefuses an ISO 15118-2 profile whose ID names it (pnc,contractorplug) with exit code 70 (CL-UNSUPPORTED-001) before any socket opens. - The charging session of the charger role runs plant-coupled on the NI VeriStand bench, for AC and DC. It is verified with the ChargeLink vehicle.
- The DC generic listener answers with scripted replies and has no plant: no contactor, no energy, protocol exchange only. Its reply order has a known limitation, so it is not for full sessions and must not be used to control a power stage. There is no AC generic listener.
- As vehicle, if your charger sends no MeterInfo, that check is not judged.
- For ISO 15118-2,
summary.jsoncan read"attention_required"after a good session; readevse_listener_status.jsonandcommand_result.json. - No physical charging interface (PLC, control pilot, power stage) is included.
See Capability Boundaries. To check the installation without a DUT, see Self-test without a device under test.
Troubleshooting
| Symptom | Usually means | Action |
|---|---|---|
summary.json reads attention_required after a session that looked good | Expected for ISO 15118-2 | Read evse_listener_status.json and command_result.json, or iso2_evcc_report.json on the vehicle side. |
| TLS fails with a TLS 1.2 ECDSA vehicle on the generic listener | The built-in TLS adapter or the wrong identity is in use | Use --external-evcc-windows-tls with a PFX identity; check tls_handshake_diagnostics.json. |
Exit 10, CL-CONFIG-001, at evse start with SChannel | The PFX password variable is empty | Set CHARGELINK_PFX_PASSWORD in the same shell before the command. |
Exit 70, CL-UNSUPPORTED-001 | The profile ID names Plug & Charge | Use an EIM profile from the table above. |
evse start refuses iso15118_2_dc_eim or iso15118_2_ac_eim | The plant-coupled profile needs --plant-grpc-endpoint | Run it on the NI VeriStand bench with the bench's plant endpoint. |
| Your vehicle rejects a reply from the generic listener | The known reply-order limitation of the generic listener | Use the plant-coupled charger for full sessions; keep the trace for DEVlink support. |
iso2-evcc or iso2-ac-evcc exits non-zero | The session did not end as asked | Read run in iso2_evcc_report.json and the last frames in traces\live-v2gtp-frames.jsonl. |
| Your charger does not decode ChargeLink's vehicle messages | An evcc start reference profile was used | Use iso2-evcc or iso2-ac-evcc. |
iso2-pki fails | The output folder exists | Name a new folder; the files must not exist. |
General failures (licence, ports, firewall, role locks) are in Troubleshooting.

