evcc icon indicating copy to clipboard operation
evcc copied to clipboard

Attempt to fix EN+ connection issues using OCPP

Open hf81-ble opened this issue 1 month ago • 12 comments

  • added the Atronix wallbox on basis of the ocpp 1.6j implementation.
  • added Workarounds to handle with setting the output power
  • workaround to chargecurrent 0 => use remote stop
  • ocpp request are answered after getting BootNotification

hf81-ble avatar Nov 05 '25 14:11 hf81-ble

I think a new template should suffice here.

The various adjustments to the OCPP code cannot be traced without a log and explanation. We deliberately do not stop any transactions as this is not compatible with how evcc works.

In this case, it would be advisable to first check with the manufacturer of the box to ensure compatibility with the OCPP standard.

premultiply avatar Nov 05 '25 16:11 premultiply

I think a new template should suffice here.

The various adjustments to the OCPP code cannot be traced without a log and explanation. We deliberately do not stop any transactions as this is not compatible with how evcc works.

For that reason i changed this only in this wallbox implementation. As i have seen, evcc also uses the tag="evcc" on remote Start to the wallbox this should be no issue and i had also not yet any issues while running. But of cause, i surely not have tested all features. But "Überschussladen" with controlling the currents works well.

In this case, it would be advisable to first check with the manufacturer of the box to ensure compatibility with the OCPP standard.

I my case the atronix wallbox will not response to any request from the central system, unless the BootNotification is accepted. This behavior should fully compliant with the OCPP 1.6 standard in 4.2 for BootNotification. If not accepted, it shall also not response. Only if in pending state. But till the CS will not answer the CP, the cp cannot know the state.

So my changes for the OCPP are:

  1. wait for receiving the BootNotification
  2. after that start the Setup Procedure. => Setup ist NOT started when only the CONNECTED state is triggered, which means, that only the WebSocket was established but not yet the BootNotification received

I hope i could explain why a added these changes.

hf81-ble avatar Nov 06 '25 16:11 hf81-ble

Mmmmh. I couldn't really find anything in the OCPP spec that says a charging station MUST report a BootNotification after establishing a connection.

The way I read the spec, a BootNotification only has to be sent if the station has been restarted – as the name suggests.

Personally, I would find it straightforward if there were such a clear handshake after each connection, but unfortunately, this is not the case in the reality of many implementations. And, as I said, I cannot find this strict requirement in the specification. Do you have any other/further information and documents?

Apart from that, we already accept every boot notification immediately. The received content is not relevant to the function and is essentially only logged for diagnostic purposes. The sent response synchronises the CP's clock with the CS.

premultiply avatar Nov 08 '25 12:11 premultiply

Hi,

i was on a business travel. So lets go into more details for this discussion:

There seems to be confusion about what BootNotification actually represents in OCPP 1.6. To clarify: BootNotification is not just a simple notification. It is the mandatory authorization + registration handshake of OCPP.

Below are the relevant OCPP 1.6 Edition 2 specification passages with exact page + line references.

1. WebSocket is only the transport – not the OCPP protocol

OCPP 1.6 defines two independent protocol bindings:

OCPP 1.6J (JSON) → runs on WebSocket

OCPP 1.6S (SOAP) → runs on HTTP/SOAP

This means:

OCPP ≠ WebSocket. WebSocket is only the transport layer for the JSON variant.

A WebSocket connection does not mean an OCPP session has started.

OCPP only begins when the CP sends its first OCPP CALL message: BootNotification.

2. BootNotification is mandatory after startup

Spec reference: Page 38, Lines 16–20

After start-up, a Charge Point SHALL send a request…” “The Charge Point SHALL send a BootNotification.req each time it boots or reboots.

This is mandatory (SHALL = RFC2119 requirement).

3. BootNotification gates all further communication

Spec reference: Page 38, Lines 20–22

Between power-on/reboot and the successful completion of a BootNotification… the Charge Point SHALL NOT send any other request to the Central System.

➡️ This makes BootNotification the protocol gate that controls whether OCPP communication is allowed.

4. Rejected = the CP must stop all communication

Spec reference: Page 38, Lines 30–35

If the status is Rejected, the Charge Point SHALL NOT send any OCPP message… While Rejected, the Charge Point SHALL NOT respond to any Central System message. The Central System SHOULD NOT initiate any.

If BootNotification is rejected, nothing may proceed.

5. Pending allows only limited CS→CP messages

Spec reference: Page 38, Lines 36–42

If Pending… The Central System MAY send request messages to retrieve or set information… The Charge Point SHALL NOT send request messages unless triggered.

➡️ Pending ≠ full operation. The CP is not fully authorized yet.

6. Why this is mandatory: RFC2119 normative language

Spec reference: Page 10, Lines 47–54

The key words MUST, SHALL, SHALL NOT… are to be interpreted as described in RFC2119.

Meaning:

SHALL / SHALL NOT → mandatory

SHOULD / SHOULD NOT → recommended

MAY → optional

BootNotification rules use SHALL/SHALL NOT, therefore they are not optional.

Conclusion

A WebSocket connection does not imply an OCPP session.

OCPP itself begins only when the CP sends BootNotification.req.

Until BootNotification is Accepted/Pending, the CP SHALL NOT send any other request.

If Rejected, the CP SHALL NOT send or respond to any OCPP message.

Therefore, BootNotification is the mandatory authorization handshake of OCPP 1.6 — not an optional diagnostic message.

The issue on your implementation is, if a wallbox is waiting for the bootNotification Accepted, and is may overinterpreting the spec, then your implementations fails, even the wall box is referencing correct to the spec from that viewpoint. I see there is a GAP in spec, but as a system architect for me, the notification step is a clear guarding gate, which does the handling on the Application layer and not on the transport layer. And it is fully OK, if evcc does accept every wallbox. And does no futher actions with these informations. But i can be in larger scale, that you want to forbit certain firmare versions because of several issues internal security or rounding issues on metering or something like this. There is also a Chapter "4.2.1 Transactions before being accepted by a central system" You can MAY do this but the behavoir may be uncertain.

That are my points ;)

hf81-ble avatar Nov 17 '25 09:11 hf81-ble

I agree with your interpretation on all points except point 2. 😉

Only booting up or restarting is mentioned. Nowhere does it say ‘(also) after establishing a connection’.

Most boxes only send a BootNotification automatically after the next connection is established if they have been (re)started in the meantime. That is the only way I can interpret the specification literally. It is intended as an indicator that the station has been restarted for some reason (e.g. power failure, software update, malfunction, etc.). Only a few send a boot notification after each connection is established.

premultiply avatar Nov 17 '25 21:11 premultiply

Thanks for your feedback — and yes, I also agree with you that the OCPP 1.6 spec is not fully precise on whether a BootNotification must be sent after every new WebSocket connection. It only explicitly requires it after reboot/startup, and I agree that this is the only literal requirement.

So from a purely textual reading of the spec, your interpretation (let’s call it Viewpoint A) is valid.

My interpretation (call it Viewpoint B) — that BootNotification also acts as the mandatory session handshake after each connection — is also valid, but it comes more from the behavior described around BootNotification rather than the literal wording.

Because the spec fails to explicitly mandate one of these interpretations, both A and B are compliant behaviors.

And that is the core of the compatibility problem.

Why evcc must support both interpretations (A and B)

Let’s say a wallbox vendor follows A. Another vendor follows B.

Both follow the spec correctly, because the spec leaves a gap.

If evcc only supports one of these interpretations, then:

It will fail for wallboxes that follow the other (still correct) interpretation.

The user cannot understand why “their compliant box” doesn’t work.

The responsibility for interoperability shifts unfairly from CSMS → device.

This is why I wrote: When it is not explicitly mentioned in the spec, it cannot be “wrong.”

And since both interpretations exist in real devices, a CSMS like evcc should ideally handle both.

many implementations treat BootNotification as a handshake

Even though the spec only explicitly says “after startup”, the behavioral rules around BootNotification make it clear that it is more than a simple reboot indicator:

CP SHALL NOT send anything before BootNotification is accepted (Page 38, Lines 20–22).

If Rejected, the CP SHALL NOT communicate at all (Page 38, Lines 30–35).

Pending limits what CS → CP messages are allowed (Page 38, Lines 36–42).

These rules effectively make BootNotification the authorization gate for the session.

And here are the practical reasons why many manufacturers send BootNotification after each connection:

After a reboot, the CP always needs to reconnect

Every reboot inherently triggers:

Device restarts

WebSocket connection must be re-established

BootNotification must be sent (mandatory per spec)

So reconnect + BootNotification are naturally coupled.

A device without persistent storage may not even remember whether it had been accepted before — sending BootNotification each time is the safest behavior.

Many CPs have no persistent storage

A lot of inexpensive wallboxes:

do not store internal protocol state across reboots

do not remember the last BootNotification status

do not keep time without BootNotification.conf

Therefore, on reconnect they cannot know:

Am I accepted?

Am I rejected?

Did CSMS change the heartbeat interval?

Did CSMS require a configuration change?

Sending BootNotification again is the only reliable method.

CPs may be intentionally Rejected until a mandatory firmware update

This is a real operational scenario:

A CP has a security issue

CSMS rejects it to enforce updating

CP must not continue communicating until updated

Only BootNotification gives CSMS the ability to enforce this.

Chapter “4.2.1 Transactions before being accepted” implies BootNotification is the gate

The spec explicitly discusses behavior when communication happens before being accepted — clearly assuming BootNotification is the relevant gate.

This reinforces the idea that BootNotification is the start of the OCPP application session, independent of WebSocket/SOAP transport.

OCPP has NO Disconnect command — which strengthens the handshake role of BootNotification

This is an important point that is often overlooked:

There is no “disconnect” or “close session” operation anywhere in OCPP 1.6.

No Disconnect.req

No CloseConnection.req

No OCPP command that tells a CP or CSMS to terminate communication

OCPP never defines a way to close a session on the application layer.

The only references to disconnecting are descriptive, not protocol-defined:

“The Charge Point … MAY close its communication channel… The Central System MAY close the communication channel.” (Page 38, Lines 30–34)

This describes transport-layer behavior (WebSocket or HTTP), not OCPP logic.

And this becomes especially clear with OCPP-S (SOAP):

In SOAP:

There is no persistent connection

Every request is a separate HTTP POST

There is nothing to “close” at the protocol level

Therefore, OCPP has no mechanism to end or reject an application session other than:

BootNotification Accepted/Pending/Rejected

This means:

BootNotification is the only application-layer session gate

There is no other mechanism to authorize, de-authorize a CP

BootNotification effectively acts as the “session start” and “session permission” primitive

Which is exactly why treating it as “just a notification” underestimates its role.

Final Summary

Your interpretation (A) is valid — the spec literally says “after startup”.

My interpretation (B) is also valid — the behavioral rules effectively make BootNotification the session handshake.

The spec does not define behavior after a new transport connection → therefore both A and B are legal.

evcc should support both, because both exist in real devices.

OCPP has no disconnect command, so BootNotification is the only application-layer authorizing mechanism.

Because of this, BootNotification becomes the de-facto session gate, especially for:

CPs without persistent storage

CPs requiring firmware-based rejection

SOAP-based implementations with no transport-session concept

Interoperability across vendors

That’s the core of my argument.

But how to proceed? I may can put the changes also to an WORKAOUND folder for the OCPP B Implementation. I could add a parameter => wait for Bootnotification and then we could split the Process not to get a regression with the existing implementation, if that is your issue.

hf81-ble avatar Nov 18 '25 07:11 hf81-ble

The best thing would be if we could somehow implement both approaches without configuration options.

Perhaps it would also help to take a look at other open source implementations.

I am inclined to follow your interpretation and thus also your implementation approach, but I am a little concerned that we will create more problems than we solve and end up (initially) breaking something that currently works without any issues.

That is why I am so hesitant.

It would be essential to proceed in very small steps.

premultiply avatar Nov 18 '25 09:11 premultiply

We can get CP to send a BootNotification with a TriggerMessage, right? So if we get a websocket connection and there's no communication over it for, lets say, 10 seconds or whatever other timeout, try sending a TriggerMessage of our own. If we don't get any response in some additional timeout after sending the message, something is wrong and we should report an issue.

nagisa avatar Nov 20 '25 14:11 nagisa

@nagisa yes this should be valid. On small Controllers (like MCUs) the goal with initial BootNotification was, that the CP is really Ready.( Slow Boot, internal init, etc). But if the netinterface is ready for opening the websocket, that after some seconds it should also be ready to receive a trigger for the BootNotification. Many implemenation have an internal timer which count for the BootNotification or Hearbeat. But this is often not synchronized to the websocket creation event. So the trigger could help to get an faster BootNotification also on the evcc side.

hf81-ble avatar Nov 20 '25 14:11 hf81-ble

Triggers are not part of the core profile...

premultiply avatar Nov 20 '25 15:11 premultiply

While we can't rely on it being supported, sending a messsage not supported by CP shouldn't make things go more wrong than they already are when CP isn't sending its BootNotification, right? CP will either respond with a BootNotification, an error message and do nothing, or not respond at all. Regardless of the outcome, things wouldn't get worse.

FWIW The occp-j 1.6 spec has the following snippet so it sounds like BootNotification is indeed not required:

5.4. Reconnecting When reconnecting a charge point should not send a BootNotification unless one or more of the elements in the BootNotification have changed since the last connection. For the previous SOAP based solutions this was considered good practice but when using WebsSocket the server can already make the match between the identity and a communciation channel at the moment the connection is established. There is no need for an additional message.

and so in principle it seems like evcc should have some recollection mechanism and the correct root fix is really to remember rather than figure how to get the message be sent again.

nagisa avatar Nov 20 '25 17:11 nagisa

I want to emphasize once more that evcc should not cling too rigidly to a single “optimally interpreted” reading of the specification when the same specification clearly allows multiple interpretations. If we lock ourselves into only one interpretation, we unnecessarily exclude wallboxes that are in fact fully compliant with the spec, just implemented according to a different, equally valid reading.

From a System Engineering perspective, this situation is very familiar. Whether in automotive, industrial automation, or renewable energy systems, specifications are often released too quickly, are incomplete, or simply not precise enough. As system architects, our job is to understand the underlying mechanism and intent, not just the exact wording.

This is exactly why I see BootNotification as an architectural synchronization point. It may not be described with perfect clarity in every corner of the spec, but it clearly acts as the moment where both sides (CP & CS) reestablish known, well-defined states.

Yes — the spec does not explicitly mandate that BootNotification must be sent on every connection attempt. But at the same time, it does not say that sending BootNotification on each connection is forbidden. Both behaviors are therefore valid and compliant.

And this leads to an important point:

This issue will not remain limited to this particular wallbox. Other manufacturers will make the same design choice because the specification permits it.

That’s why I believe it’s problematic for us to say:

“Anything that doesn’t align with our interpretation is out.”

Formally speaking, that is not correct, because the alternative behavior is still OCPP-compliant.

From my perspective, the idea behind the merge request was absolutely right: evcc should aim to support both interpretations without forcing users into overwhelming configuration choices. A flexible, adaptive approach is possible — and we have already discussed several low-risk implementation steps.

For this reason, I think it would be unfortunate to close the merge request completely without deriving at least some follow-up action. We should work together to define a path that:

  • does not break existing working installations,

  • but still achieves broader interoperability,

  • and acknowledges the ambiguity in the specification instead of locking out devices that follow the “other” valid interpretation.

I am quite confident this problem will surface again sooner or later — just with different devices.

hf81-ble avatar Dec 03 '25 08:12 hf81-ble