Evse15118D20¶
Handwritten Documentation¶
This module implements the SECC side of ISO 15118-20 charging, including both AC
DER services of ISO 15118-20 Amendment 1, AC_DER_IEC (Annex L) and
AC_DER_SAE (Annex M), and a grid_support provider that accepts active DER
directives and raises grid alarms from EV-reported grid-event conditions.
It also offers ISO 15118-2 and DIN SPEC 70121 (see supported_ISO15118_2
and supported_DIN70121). DIN SPEC 70121 sends the EVSEID from EvseManager’s
evse_id_din (DIN SPEC 91286 as hexBinary, e.g. 49A80737A45678); when that
is empty the eMI3 evse_id is packed instead, which only works for ids made of
digits and *, so an eMI3 id like DE*PNX*E12345*1 is sent as 0x00.
TLS and SECC leaf certificates¶
ISO 15118-2 and ISO 15118-20 prescribe different TLS profiles that cannot be served by one certificate:
ISO 15118-2: TLS 1.2,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, SECC leaf onsecp256r1(prime256v1), no client certificate.ISO 15118-20: TLS 1.3,
TLS_AES_256_GCM_SHA384/TLS_CHACHA20_POLY1305_SHA256, SECC leaf onsecp521r1orEd448, mutual TLS with the vehicle certificate.
The TLS version and cipher follow whatever the EV offers in its ClientHello
(unless enforce_tls_1_3 pins TLS 1.3). To also present the right leaf,
install both SECC leaf certificates (with their keys) in the EvseSecurity
SECC leaf directory – or let OCPP provision them (V2GCertificate and, on
OCPP 2.1, V2G20Certificate; see the OCPP module documentation). The two
are the EvseSecurity leaf types V2G (ISO 15118-2 profile) and V2G20
(ISO 15118-20 profile, secp521r1 / Ed448 key). The module fetches every
valid leaf of both types – newest per issuing root – and tags each chain by
its key: prime256v1 leaves are presented on TLS 1.2 connections,
secp521r1 / Ed448 leaves on TLS 1.3 connections, anything else on both.
Within a version the EV’s advertised CA list (certificate_authorities on
TLS 1.3, trusted_ca_keys on TLS 1.2) picks among the chains, so the two
leaves may chain to different sub-CAs or roots. When only one leaf is installed
it is presented on every connection as before; a warning is logged at startup
if a protocol is offered without a leaf on its mandated curve. The chain list
is rebuilt on every certificate_store_update event, so a renewed leaf of
either type is served from the next connection on without a restart.
The two DER flavors are mutually exclusive per EVSE, so at most one is ever advertised. EvseManager enforces that when it builds the energy transfer mode set; see “DER flavor selection” below.
Plug and Charge¶
Contract-certificate authorization is offered whenever EvseManager passes
Contract in session_setup (payment_enable_contract). For ISO
15118-2 this is the Contract payment option; for ISO 15118-20 the SECC lists
PnC next to EIM in AuthorizationSetupRes and issues the 128 bit
GenChallenge ([V2G20-697]). The CertificateInstallationService flag
follows supported_certificate_service.
An ISO 15118-20 AuthorizationReq with PnC is checked in this order:
session id, offered service ([V2G20-2209]), GenChallenge match
([V2G20-2565], WARNING_ChallengeInvalid), header signature over
PnC_AReqAuthorizationMode with the contract leaf key ([V2G20-1063];
ecdsa-sha512 with SHA-512 digests or Ed448 with SHAKE256 digests, r||s per
[V2G20-1000]; a failure is FAILED_SignatureError and ends the session), then
the contract chain. The chain is validated locally against the MO and V2G root
bundles of EvseSecurity (get_verify_file): validity window of every
element (WARNING_CertificateExpired / WARNING_CertificateNotYetValid),
the Annex B profile (secp521r1 or Ed448 keys, ecdsa-with-SHA512 or Ed448
signatures, critical KeyUsage and BasicConstraints, no
ExtendedKeyUsage, no extension outside Table B.9/B.10, CN = EMAID and
O in the subject, CRL or OCSP pointer; WARNING_CertificateValidationError)
and the trust chain. Annex B marks the key identifiers and the revocation
pointers critical where IETF RFC 5280 does not, so those extensions are decoded
and accepted; any other unknown critical extension still fails the chain. A
chain whose eMSP root is not installed is WARNING_eMSPUnknown unless
central_contract_validation_allowed is set, in which case it is still handed
to the backend.
An accepted chain is published as require_auth_pnc (eMAID plus the PEM
chain) and answered OK / Ongoing until authorization_response
arrives. While that poll is open the EV repeats the request unaltered apart from
the header timestamp ([V2G20-1582]) and a freshly computed header signature,
which is verified on every repetition; a changed request is a sequence error,
so a pending result can never be consumed by a different contract. The wait is
bounded by auth_timeout_pnc ([V2G20-2102]); an EIM authorization left
Ongoing stops the session after the 55 s V2G_SECC_Ongoing_Performance_Time
(the next repetition is answered FAILED, [V2G20-2102]). Accepted gives
OK, or OK_CertificateExpiresSoon when the leaf expires within 14 days
([V2G20-2218]), which keeps CertificateInstallationReq available so the EV
can install a fresh contract ([V2G20-2232]); a rejection maps the CertificateStatus onto
WARNING_CertificateExpired, WARNING_CertificateRevoked,
WARNING_CertificateValidationError (chain, signature, no certificate) or
WARNING_GeneralPnCAuthorizationError (everything else, including
ContractCancelled, which has no code of its own in the -20 schema), and an
AuthorizationStatus of Unknown onto WARNING_eMSPUnknown. After a
WARNING the EV may retry with another chain, switch to EIM or send a
CertificateInstallationReq ([V2G20-1583]). Once authorized the eMAID and
contract certificate are fixed for the session ([V2G20-2702]) and survive a
pause ([V2G20-1844]).
CertificateInstallationReq is accepted when the service was offered. The
SECC checks the validity period of every OEM provisioning chain element
(WARNING_CertificateExpired / WARNING_CertificateNotYetValid,
[V2G20-2203], [V2G20-2204]), verifies the header signature over
OEMProvisioningCertificateChain against the OEM provisioning leaf
([V2G20-1548], FAILED_SignatureError) and relays the raw request over
iso15118_extensions with
iso15118_schema_version urn:iso:std:iso:15118:-20:CommonMessages. Until
set_get_certificate_response arrives every repetition is answered OK /
Ongoing ([V2G20-1972]); the backend’s complete, CPS-signed
CertificateInstallationRes then goes out verbatim, and its
RemainingContractCertificateChains decides whether another
CertificateInstallationReq is allowed ([V2G20-1973], [V2G20-1975]), while a
relayed WARNING_eMSPUnknown allows a further attempt ([V2G20-2224]). A
backend failure, timeout, or a response that is not a CertificateInstallationRes
for this session is WARNING_NoCertificateAvailable ([V2G20-2207],
[V2G20-2225]). Algorithm profile and trust of the OEM provisioning chain are
the certificate provisioning service’s job ([V2G20-1548] NOTE 2).
Not implemented: SupportedProviders in AuthorizationSetupRes (optional,
omitted), MeteringConfirmationReq on the multiplexed side stream, and the
OCPP 2.1 maximumContractCertificateChains / prioritizedEMAIDs /
remainingContracts pass-through (the RemainingContractCertificateChains
the EV sees is whatever the backend encoded).
DER grid support¶
This section describes both directive relays. The SAE negotiation, the default grid code and the mid-session path are covered in “AC_DER_SAE grid code” below.
Active DER directives received via grid_support::set_active_directives are
stored and relayed to the EV per annex.
The IEC relay maps three curve families, VoltVar to VoltVarMode,
WattVar to WattVarMode and WattPF to WattCosPhiMode, each as an
absolute-unit control curve; a type that appears twice is last-wins. Non-curve
directives (frequency, volt-watt, setpoint, ride-through) have no counterpart here
and are logged and skipped. Application is next-session-dynamic: a directive
arriving mid-session takes effect at the next V2G session. The DER transfer limits
advertised at each session’s charge parameter discovery derive from ac_limits.
The SAE relay maps the directive table onto the inert default grid code, so a
directive that leaves the set falls back to the shipped default rather than
lingering: HVMustTrip, HVMayTrip, HVMomCess, LVMustTrip,
LVMayTrip, LVMomCess, HFMustTrip, HFMayTrip, LFMustTrip,
VoltVar, WattVar, FixedVar, VoltWatt, FreqDroop,
LimitMaxDischarge, FixedPFAbsorb, FixedPFInject and EnterService.
FixedPFAbsorb and FixedPFInject share the single ConstantPowerFactor
element, so one wins and the other is shadowed. Each Annex M element takes one
writer: the lowest priority wins, array order breaks ties, and shadowed
directives are logged by id (unlike the IEC relay, which ignores priority). A
winner that fails validation frees its element for the next candidate. Only the
single-phase fields are written. LimitMaxDischarge is an approximation: the
percentage is clamped to 0..100 and rounded, not rescaled against the EV’s
maximum discharge power. The mapped grid code reaches the next session and, after
validation, the running one; see “Mid-session updates” below.
The relay owns every unit and orientation conversion, so the library below it knows nothing about OCPP:
grid_supporttrip curves arrive in OCPP orientation, threshold onxand seconds ony. The relay swaps them into the Annex M duration-first form (xthe duration in seconds,ythe threshold) and sorts by duration per M.2.2.1.10 and M.2.2.1.11; two points sharing a duration reject the directive. HV/LV thresholds stay percentages of nominal (PercentageV) and HF/LF stay Hz, so no volt conversion happens.EnterServicevoltage bands and the VoltVarReferenceVoltagepass through in volts, because AMD1 Table 1 gives them in volts and so doesgrid_support.The
FixedVarsetpoint sign is inverted intoVarSetpoint. The two sign conventions are opposed and [V2G20-3183] mandates the conversion.The directive
priorityis forwarded into every written element that carries one;EnterServicehas none. A value outside the Annex Muint16range is omitted with a warning rather than wrapped.A curve with more than ten data points is rejected, never truncated: dropping points would silently reshape the grid code the operator asked for.
This module does not publish DER capability; an empty one is expected for
AC_DER_IEC.
The DER control functions the EV supports are surfaced in
ChargingNeeds.der_charging_parameters.ev_supported_dercontrol, so the backend
learns what the EV supports without the EVSE guessing. For AC_DER_IEC they come
from what the EV negotiates during service selection; for AC_DER_SAE from the
SupportedModes bitmap in the charge parameter discovery request
([V2G20-3409]). See “Known gaps” for what a SAE session leaves out.
Discharge power limits follow ISO 15118-20 8.3.5.2.1: negative when the
negative_bidirectional_limits config key is set, with nominal discharge power
set equal to maximum discharge power so nominal never exceeds maximum in
magnitude. That constraint is normative only for AC_DER_SAE ([V2G20-3228],
[V2G20-3229], Annex M); Annex L has no equivalent numbered requirement, so the IEC
path applies it defensively.
AC_DER_SAE grid code¶
Negotiation¶
SAE negotiation is declare, enable, acknowledge. The EV declares its
SupportedModes bitmap in the charge parameter discovery request. The SECC
masks it with SAE_MODE_BITMAP_MASK (0x05FFFDFB; bits 2, 9, 25 and 27 to 31
are unused by the specification and must be ignored), then sets the per-function
Enable booleans inside DERControlCPDRes, clearing every Enable whose
function the EV did not declare. There is no SECC-side mode bitmap; the Enable
flags are the SECC’s only expression channel.
The EV acknowledges in EnabledModes. The charge loop compares that against the
modes the SECC enabled, not against the EV’s declaration, masked with
SAE_ENABLED_MODE_MASK to ignore unused bits and bits with no Enable in
DERControlCPDRes. A mismatch is not an error: no requirement makes the SECC
enforce the acknowledge, so it emits one latched warning naming the missing and
extra functions and continues.
The diagram shows which side owns each step, and where the mask and the per-function gating sit relative to the response carrying them.
sequenceDiagram
participant EV
participant SECC as SECC AC_DER_SAE states
participant Config as DerSaeSetupConfig
Note over Config: default der_control is inert:<br/>every enable false, permit_service false
rect rgb(238, 244, 250)
Note over EV, Config: charge parameter discovery
EV->>SECC: DER_SAE_AC_ChargeParameterDiscoveryReq<br/>SupportedModes, EnabledModes, EV limits
Note over SECC: declare: SupportedModes AND 0x05FFFDFB<br/>bits 2, 9, 25 and 27 to 31 are unused and ignored<br/>EnabledModes in the request is not consumed
SECC->>SECC: session.set_ev_supported_sae_functions(masked)
Config-->>SECC: der_control, required_der_operating_mode,<br/>grid_connection_mode, revision,<br/>der_control_update_time (UpdateTime on the wire only)
Note over SECC: enable: gate_enables_by_supported_modes clears<br/>every Enable whose function the EV did not declare.<br/>There is no SECC-side mode bitmap.
SECC-->>EV: DER_SAE_AC_ChargeParameterDiscoveryRes<br/>DERControlCPDRes with per-function Enable,<br/>SAE transfer limits, UpdateTime
SECC->>SECC: session.record_der_control_sent(revision)
end
rect rgb(240, 248, 240)
Note over EV, Config: charge loop
loop every DER_SAE_AC_ChargeLoopReq
EV->>SECC: DER_SAE_AC_ChargeLoopReq<br/>EnabledModes, DERAlarmStatus
Note over SECC: acknowledge: EnabledModes, masked with<br/>SAE_ENABLED_MODE_MASK, is compared against the modes<br/>the SECC enabled. A mismatch is one latched warning, not an error.
alt revision changed since discovery
SECC-->>EV: DERControlCLRes: EnterServiceCLRes plus voltage_trip,<br/>frequency_trip, reactive_power_support_cl_res,<br/>active_power_support_cl_res
SECC->>SECC: session.record_der_control_sent(revision)
else unchanged
SECC-->>EV: DERControlCLRes: EnterServiceCLRes.permit_service only
end
Note over SECC: each mode field is checked on its own,<br/>[V2G20-3358] to [V2G20-3361], an unchanged field is left unset
opt RequiredDEROperatingMode differs from the last sent
SECC-->>EV: RequiredDEROperatingMode re-sent in the response
end
opt GridConnectionMode differs from the last sent
SECC-->>EV: GridConnectionMode re-sent in the response
end
SECC->>SECC: session.record_der_modes_sent(operating mode, connection mode)
end
end
Default grid code¶
get_default_sae_der_control(nominal_voltage_v) returns a complete but
functionally inactive configuration: every enable and permit_service is
false. DERControlCPDRes and all its sub-elements are mandatory, so a SAE SECC
must emit a full grid code at charge parameter discovery or not offer the service
at all. An inert one keeps a station that was never given a grid code from
claiming one.
The volt-valued fields are derived from the nominal voltage passed in: the
enter-service window is 1.05 and 0.917 of nominal (AMD1 Table 1 gives both bands
in volts) and the volt-var ReferenceVoltage is the nominal itself. A
FrequencyDroop carrying a zeroed over-frequency branch is present but
disabled, because Table M.33 obliges UnderFrequencyDroop whenever
OverFrequencyDroop is absent, and that holds regardless of enable. The
frequency bands remain the shipped 50 Hz-family values and do not follow the
nominal frequency.
The values are structurally valid, and the two mandatory curves per trip family carry the schema minimum of two data points, so a SAE station is conformant without any DSO directive.
Mid-session updates¶
DERControlCLRes updates parameters already sent in DERControlCPDRes
([V2G20-3236]). Only EnterServiceCLRes is mandatory inside it, and only
permit_service inside that. The other four blocks (voltage_trip,
frequency_trip, reactive_power_support_cl_res,
active_power_support_cl_res) are emitted only when the grid code changed
since charge parameter discovery. Sending a conditional element unconditionally
is itself non-conformant, so the unchanged path clears them.
Change detection is keyed on DerSaeSetupConfig::revision, a producer-owned
counter this module bumps only when the relay input changes: the
sorted directive ids with their received_at stamps, plus the nominal voltage
and frequency the mapping converts against. The session records the revision it
sent at charge parameter discovery and after each re-send, and compares that
against the installed config. der_control_update_time is the wall clock
UpdateTime on the wire and nothing else; it is never compared, because a
timestamp changes on every construction while the counter changes only with the
content. A re-apply of an unchanged directive set, or an AC-limit re-derivation,
therefore does not re-dictate the grid code.
RequiredDEROperatingMode and GridConnectionMode are handled per field and
independently of the revision: each is re-sent in the charge loop response only
when it differs from the value last sent to this EV and is left unset otherwise
([V2G20-3358] to [V2G20-3361]).
The path from a directive to the wire runs once AC_DER_SAE is advertised and
its limits are derived; otherwise apply_active_der_directives logs at info and
leaves the revision untouched. relay_sae_grid_code compares the relay input,
maps the set with map_active_directives_to_sae_der_control, validates the
result with validate_sae_der_setup against the SAE DER limits and AC limits
held at that moment, stores it as the next-session setup and hands it to
TbdController::update_der_sae_limits. The controller pushes it into the
running session as a control event, where install_der_sae_setup_config
validates it once more against the session’s own limits before installing it. The
next DERControlCLRes then carries the four blocks, gated by the EV’s declared
SupportedModes like the discovery response, and the EnabledModes mismatch
warning re-arms. An invalid grid code is rejected with a warning at either stage.
A module-stage rejection leaves the previous revision dictated. A session-stage
rejection keeps the running session on its old grid code; the new revision is
still the next-session setup. The controller also guards a caller passing no
setup config: that withdrawal is logged once per withdrawal and does not reach
the running session, which keeps its grid code until it ends. This module never
withdraws; an empty directive set produces a new inert revision instead. The
relayed setup config outlives AC-limit re-derivations: the derivation seeds it
only while none is held or the held one is still the seed (revision 0).
sequenceDiagram
participant CSMS
participant OCPP as OCPP module
participant Module as Evse15118D20
participant Ctrl as TbdController
participant Session as running Session
participant EV
CSMS->>OCPP: SetDERControl
OCPP->>Module: grid_support set_active_directives
Module->>Module: apply_active_der_directives
opt AC_DER_SAE not advertised or its limits not derived yet
Note over Module: info log, revision untouched, stop here
end
Module->>Module: relay_sae_grid_code
Module->>Module: sae_relay_input<br/>sorted (id, received_at) plus nominal voltage and frequency
alt relay input unchanged
Note over Module: revision stays in effect, nothing pushed
else relay input changed
Module->>Module: map_active_directives_to_sae_der_control<br/>default grid code plus winners per Annex M element,<br/>trip curves transposed to duration-first
Module->>Module: validate_sae_der_setup against SAE DER limits and AC limits
alt violation
Note over Module: warning, previous revision remains dictated
else valid
Module->>Module: revision + 1, store as next-session setup
Module->>Ctrl: update_der_sae_limits(limits, setup config)
Ctrl->>Session: push_control_event(DerSaeSetupConfig)
Session->>Session: install_der_sae_setup_config<br/>validate_sae_der_setup against the session's own limits
alt violation
Note over Session: warning, the running session keeps its old grid code,<br/>the new revision is still the next-session setup
else installed
EV->>Session: DER_SAE_AC_ChargeLoopReq
Session-->>EV: DERControlCLRes: EnterServiceCLRes plus voltage_trip,<br/>frequency_trip, reactive_power_support_cl_res,<br/>active_power_support_cl_res
Session->>Session: record_der_control_sent(revision),<br/>EnabledModes warning re-armed
end
end
end
Transfer limits and the voltage window¶
Unlike the IEC limits, the SAE limits do not derive from ac_limits alone. They
also use evse_max_reactive_power (from update_ac_parameters) and the
nominal voltage from ac_setup_config. The nominal voltage has no fallback:
until the AC parameters arrive it is unset and the service is withheld.
The advertised voltage window is the nominal voltage times 1.10
(GridMaximumVoltage) and 0.88 (GridMinimumVoltage). Both fractions must
stay in step with the first breakpoints of the library’s default over- and
under-voltage must-trip curves (110 % and 88 %): those curves carry duration on x
and PercentageV on y, and the EV denormalizes the percentage against the base
voltage for the function, usually the nominal voltage advertised here. Changing
one side alone silently moves the EV’s trip thresholds.
PercentageV does not carry its base voltage on the wire. For trip thresholds,
the relay assumes the EV uses the advertised nominal as its base voltage; an EV
using a different function-specific base would interpret the same percentage
differently.
Service withdrawal¶
If ac_limits.nominal_frequency or the nominal voltage is not yet positive when
the DER limits are derived, the module logs an error naming the missing parameter
and leaves der_sae_limits unset, which makes the library strip AC_DER_SAE
from the advertised services. Advertising a placeholder grid is worse than
withholding the service: the nominal voltage is the usual base for the percentage
voltage curves, so a guess moves those thresholds on a 277 V or 120 V site, and
the nominal frequency is advertised as the GridNominalFrequency the EV adopts
as the frequency of the grid it is connecting to.
The frequency-trip curves are separate. Their y unit is Hz, so their
breakpoints are absolute and not scaled by GridNominalFrequency. The shipped
default carries 50 Hz-family constants (51.5 and 52 Hz over-frequency must-trip,
47.5 and 47 Hz under-frequency, a 49.5 to 50.1 Hz enter-service band). Setting the
nominal frequency to 60 does not move them; a 60 Hz operator supplying a real setup
config must supply 60 Hz curve values with it.
The withdrawal is not permanent. The derivation re-runs whenever the supported
energy services, the AC limits or the AC parameters change, not only at
ready(), so a service withheld at boot is picked up once they arrive.
Reactive power sign convention¶
Absorption fields are advertised non-negative and injection fields non-positive, per ISO 15118-20 AMD1 clause 8.3.5.2, which replaces Table 94 and binds both annexes. All four reactive power limits are mandatory on the wire, so an absent or zero EVSE capability yields explicit zeros rather than omitted elements.
Known gaps¶
A SAE session’s
ChargingNeedsomits the reactive-power limits. SAE var absorption and injection do not map onto the IEC charge and discharge reactive fields oftypes::iso15118::DERChargingParameters, so those are left unset. The supported-modes bitmap, the four excitation fields and the optional session total discharge energy available do pass through.required_der_operating_modeandgrid_connection_modeare re-sent per field in the charge loop response when they differ from the value last sent ([V2G20-3358] to [V2G20-3361]). Nothing in this module changes them after boot; the relay carries the current values through, so in practice both are dictated at charge parameter discovery only.Directive types with no Annex M target are logged once per applied set and skipped:
FreqWatt,WattPF,ZeroCurrent,OvervoltageFaultRideThrough,UndervoltageFaultRideThrough,MaximumLevelDCInjection,DSOQSetpoint,DSOCosPhiSetpoint,PowerMonitoringMustTripandGradientsexist in Annex L or in OCPP only.The SAE relay writes the single-phase fields only; every
_L2and_L3counterpart stays unset.LimitMaxDischargeis approximated:pct_max_discharge_powerlands inPercentageValueclamped to 0..100 and rounded, not rescaled against the EV’s maximum discharge power.grid_supportramp_rate(%/s) is copied intoEnterServiceRampTime(s) unconverted, by decision, and needs a follow-up. It reachesEnterServiceRampTimeonly when paired withdelay; alone it is dropped at debug, anddelaywithoutramp_raterejects the directive.
DER flavor selection¶
The diagram answers “why is my station not advertising the DER service I
configured?”. An AC DER service needs set_der_available asserted and an
export-capable EVSE before the iso15118_der_flavor config key picks the annex,
and SAE needs the AC parameters on top of that. The key defaults to NONE, so
AC DER is opt-in even when availability is asserted.
Asserting availability does not require a wired grid_support provider. It
normally arrives from OCPP via a grid_support capability publish, but the SIL
configs assert it directly over MQTT with no provider wired, which advertises the
service while leaving the directive path inert.
flowchart TD
subgraph EvseManager
A["set_der_available(available)"] --> B{"DER available for this EVSE?"}
B -- no --> Z["No AC DER service advertised"]
B -- yes --> C{"EVSE export capable?<br/>max_current_A_export positive and<br/>max_phase_count_export at least 1"}
C -- no --> Z
C -- yes --> D{"config iso15118_der_flavor"}
D -- "NONE (default)" --> Z
D -- IEC --> E["EnergyTransferMode AC_DER_IEC"]
D -- SAE --> F["EnergyTransferMode AC_DER_SAE"]
D -- unrecognized --> W["warning logged,<br/>no AC DER advertised"]
W --> Z
end
subgraph Evse15118D20
E --> G["IEC DER transfer limits from ac_limits"]
G --> H["AC_DER_IEC advertised"]
F --> I{"ac_limits.nominal_frequency and<br/>nominal voltage both positive?"}
I -- yes --> J["SAE DER transfer limits and the inert default<br/>grid code configuration built,<br/>AC_DER_SAE advertised"]
I -- no --> K["error logged, der_sae_limits left unset,<br/>AC_DER_SAE stripped from the offered services"]
K --> L["derivation re-runs on the next change of the<br/>supported energy services, AC limits or AC parameters"]
L --> I
end
SECC state machine¶
The ISO 15118-20 state machine of the underlying library, with the four AC DER
states in place. Two things to take from it: the four AC DER states sit alongside
the plain AC and DC ones rather than inside them, and AC_DER_SAE charge
parameter discovery is the only charge parameter discovery state that can hand
control back to ServiceDetail, which is how an EV that rejects the dictated
grid code restarts service selection.
Terminations that any state performs on a SessionStopReq or a sequence error
are omitted, since they end the session rather than move it to another state.
On a DC PowerDeliveryReq with Stop, or any PowerDeliveryReq while a
shutdown is requested, current_demand_finished and dc_open_contactor are
published before the response, and the response is held
until ac_contactor_closed(false) reports the power path off, for at most 500 ms.
The EV leaves state C as soon as it has the response, so this withdraws the power
permissive first (IEC 61851-23-3 Table CC.111, t103 before t105). An MCS board
support treats a C exit under a standing permissive as an emergency shutdown
(CC.4.3).
A pause requested with pause_charging is sent as EVSENotification Pause
with NotificationMaxDelay 60 s ([V2G20-1850]). In scheduled control mode it may
only be sent while the applied entry of the EV’s power profile, from its latest
PowerDeliveryReq, is 0 kW ([V2G20-1198]): until then every charge loop response
goes out without it and the check is repeated. pause_notified is published once
the notification has gone out. In dynamic control mode the SECC has to bring the power
to 0 kW before asking ([V2G20-2115]); EvseManager does that before it requests the
pause.
stateDiagram-v2
[*] --> SupportedAppProtocol
SupportedAppProtocol --> SessionSetup : protocol namespace agreed
SessionSetup --> AuthorizationSetup : new session
SessionSetup --> AC_ChargeParameterDiscovery : resumed session, AC or AC_BPT
SessionSetup --> AC_DER_IEC_ChargeParameterDiscovery : resumed session, AC_DER_IEC
SessionSetup --> AC_DER_SAE_ChargeParameterDiscovery : resumed session, AC_DER_SAE
SessionSetup --> DC_ChargeParameterDiscovery : resumed session, DC, DC_BPT, MCS or MCS_BPT
AuthorizationSetup --> Authorization
Authorization --> ServiceDiscovery : authorization accepted
ServiceDiscovery --> ServiceDetail
ServiceDetail --> ServiceSelection
ServiceSelection --> ServiceSelection : further ServiceDetailReq
ServiceSelection --> AC_ChargeParameterDiscovery : AC or AC_BPT selected
ServiceSelection --> AC_DER_IEC_ChargeParameterDiscovery : AC_DER_IEC selected
ServiceSelection --> AC_DER_SAE_ChargeParameterDiscovery : AC_DER_SAE selected
ServiceSelection --> DC_ChargeParameterDiscovery : DC, DC_BPT, MCS or MCS_BPT selected
AC_ChargeParameterDiscovery --> ScheduleExchange
DC_ChargeParameterDiscovery --> ScheduleExchange
AC_DER_IEC_ChargeParameterDiscovery --> AC_DER_IEC_ChargeParameterDiscovery : EV Processing Ongoing
AC_DER_IEC_ChargeParameterDiscovery --> ScheduleExchange : EV Processing Finished
AC_DER_SAE_ChargeParameterDiscovery --> AC_DER_SAE_ChargeParameterDiscovery : EV Processing Ongoing
AC_DER_SAE_ChargeParameterDiscovery --> ScheduleExchange : EV Processing Finished
AC_DER_SAE_ChargeParameterDiscovery --> ServiceDetail : ServiceDiscoveryReq, EV restarts service selection
ScheduleExchange --> PowerDelivery : AC, AC_DER_IEC or AC_DER_SAE
ScheduleExchange --> DC_CableCheck : DC, DC_BPT, MCS or MCS_BPT
DC_CableCheck --> DC_PreCharge : cable check done
DC_PreCharge --> PowerDelivery : EV Processing Finished
PowerDelivery --> AC_ChargeLoop : contactor closed
PowerDelivery --> AC_DER_IEC_ChargeLoop : contactor closed
PowerDelivery --> AC_DER_SAE_ChargeLoop : contactor closed
PowerDelivery --> DC_ChargeLoop
PowerDelivery --> SessionStop : shutdown requested, AC family
PowerDelivery --> DC_WeldingDetection : shutdown requested, DC family
AC_ChargeLoop --> SessionStop : PowerDeliveryReq Stop or shutdown
AC_DER_IEC_ChargeLoop --> SessionStop : PowerDeliveryReq Stop or shutdown
AC_DER_SAE_ChargeLoop --> SessionStop : PowerDeliveryReq Stop or shutdown
DC_ChargeLoop --> DC_WeldingDetection : PowerDeliveryReq Stop or shutdown, after power path off
DC_WeldingDetection --> SessionStop : EV Processing Finished
SessionStop --> [*]