Skip to content

Use a short OCPP UniqueId to support firmware that truncates the echo… - #106

Open
loosrob wants to merge 1 commit into
dallmann-consulting:mainfrom
loosrob:fix/short-ocpp-uniqueid
Open

Use a short OCPP UniqueId to support firmware that truncates the echo…#106
loosrob wants to merge 1 commit into
dallmann-consulting:mainfrom
loosrob:fix/short-ocpp-uniqueid

Conversation

@loosrob

@loosrob loosrob commented Sep 1, 2026

Copy link
Copy Markdown

Use a short OCPP UniqueId to support firmware that truncates the echoed id

Summary

Server-initiated OCPP 1.6 messages currently use a full 32-character GUID as the
message UniqueId:

msgOut.UniqueId = Guid.NewGuid().ToString("N");   // 32 hex chars

This PR replaces that with an 11-character id via a small helper
(NewShortUniqueId()), applied to all six existing server-initiated senders in
OCPPMiddleware.OCPP16.cs.

Motivation

Per OCPP-J, a charge point must echo the request's UniqueId back in its
CALLRESULT, and Receive16 correlates the response by looking that id up in
_requestQueue. Most chargers (including KEBA) echo the full id and work fine.

However, at least one firmware family — eNovates, seen on a Bluecorner "Curved"
charge point (firmware 70.13.0) — truncates the echoed UniqueId to 11
characters
. When a 32-char GUID is sent, the truncated echo never matches the
queued id, so every server-initiated request logs:

OCPPMiddleware.Receive16 => HttpContext from caller not found / Msg: [3,"<11-char id>",{...}]

and the API caller receives {"status":"Timeout"} after 60 s even though the
charger answered correctly.

Example (sent vs. echoed, consistent across requests):

sent : df40da35a51xxxxxxxxxxxxxxxxxxxxx   (32 chars)
echo : df40da35a51                          (11 chars)

Fix

private static string NewShortUniqueId()
{
    return Guid.NewGuid().ToString("N").Substring(0, 11);
}

11 hex chars is ~44 bits of entropy — far more than enough uniqueness for these
one-at-a-time backend requests.

Compatibility

This is backward compatible. Spec-compliant chargers echo the shorter id
unchanged, so correlation continues to work exactly as before. Verified against a
live eNovates-based charge point: with the fix, server-initiated requests
(Reset, GetConfiguration, etc.) correlate correctly and the API returns the
charger's real answer instead of a false timeout.

Scope

Only OCPP.Core.Server/OCPPMiddleware.OCPP16.cs is changed: the new helper plus
six one-line replacements in the existing senders (Reset16, UnlockConnector16,
SetChargingProfile16, ClearChargingProfile16, RemoteStartTransaction16,
RemoteStopTransaction16).

Note on overlap with the GetConfiguration/ChangeConfiguration PR

If my other PR (adding GetConfiguration/ChangeConfiguration) is merged first,
this file will have moved and this PR will need a trivial rebase (the same helper
and the same one-line swaps, additionally applied to the two new senders). Happy
to rebase whenever suits — just let me know the preferred order. The two changes
are logically independent; I kept them apart so this firmware-workaround can be
accepted, gated behind a flag, or declined on its own merits.

Licensed under GPLv3, consistent with the rest of the project.

@dallmann-consulting

Copy link
Copy Markdown
Owner

Cutting a 32-character GUID down to 11 characters seems like a much higher risk of collisions. I would prefer a solution using case-sensitive characters (like Base64 does) to extend the possible range and reduce the probability of collisions. The necessary function would only require a few lines of code.
Would that be OK for you? Then I will implement that change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants