Skip to content

feat(ocpp): restore the OCPP 1.6J Central System - #732

Draft
HuggeK wants to merge 2 commits into
srcfl:masterfrom
HuggeK:worktree-ocpp-restore
Draft

feat(ocpp): restore the OCPP 1.6J Central System#732
HuggeK wants to merge 2 commits into
srcfl:masterfrom
HuggeK:worktree-ocpp-restore

Conversation

@HuggeK

@HuggeK HuggeK commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Brings back go/internal/ocpp, retired as unused in #578, so EV chargers can
connect to FTW directly instead of through a vendor cloud.

Groundwork only — nothing is wired into main.go, so runtime behaviour is
unchanged.
Opening early because the design questions below are worth settling
before the wiring lands.

Why this comes back

Bench testing six chargers turned up a gap: Charge Amps has no FTW driver at
all
, and three of the six units are Charge Amps. Every current model speaks
OCPP 1.6J since Charge Amps migrated off its proprietary CAPI protocol.

The wider picture, from srcfl/device-drivers#52:

Charger Local path Cloud needed?
Charge Amps Dawn / Luna / Halo / Aura OCPP 1.6J no — hotspot or Bluetooth installer app
Easee Charge Up native OCPP 1.6J one-time commissioning via Easee's API
Zaptec Go / Go 2 / Pro box-level OCPP 1.6J one-time unlock in the Zaptec Portal

Easee and Zaptec need a one-time cloud commissioning step, Charge Amps needs
none — but after commissioning all three dial out to a local central system
and the cloud leaves the runtime path entirely.
One server covers all of them.

State of the restore

Restored unchanged from 61c5250^. It still builds, vets, and passes its own
tests against the current tree — the original deletion was clean.

ok  github.com/srcfl/ftw/go/internal/ocpp   2.32s
  TestStopIsConcurrentAndIdempotent      PASS
  TestBootAndMeterValuesPushDerEV        PASS
  TestStartStopTransactionTracksSession  PASS
  TestBasicAuthRejectsWrongCredentials   PASS

go get github.com/lorenzodonini/ocpp-go@latest resolves to v0.19.0 — the
same version that was removed. Upstream has not cut a release since August 2025
(367★, 117 open issues, MIT, not archived).

Why a Go module and not a git submodule

A submodule was considered and rejected. go build resolves the dependency
through go.mod and the module cache, so a submodule checkout would be inert
unless paired with a replace directive — and that would make the repo
unbuildable for anyone cloning without --recurse-submodules, break
go install, and force submodule-aware checkout into CI, make build-arm64,
Docker and the release flow. FTW uses no submodules today.

If we end up carrying patches upstream will not take, the right move is a
srcfl/ocpp-go fork plus a replace directive — still an ordinary Go module.
Given upstream's release cadence, that is the likely destination.

Gaps that must close before this is enabled

Both are carried over from the original, not introduced here.

  • Config.Bind is advisory only. ocpp-go exposes no bind address, so the
    listener takes 0.0.0.0 regardless of config, and Phase 1 has no TLS. On a Pi
    this is an unauthenticated-by-default WebSocket on every interface. Basic auth
    is optional and off unless configured. This needs fixing before the server can
    ship enabled.
  • Handlers are read-only. They ack everything and push no commands.

Design questions

1. How should an OCPP charger surface as a device? The restored code writes
straight into telemetry.Store from Go, keyed by chargePointId, with no Lua
driver involved. That sits awkwardly against AGENTS.md, which says drivers own
vendor protocols and are the only place power signs are converted. It is also
inverted from the driver model: Lua drivers poll, OCPP chargers dial in and push.

Either OCPP stays a core service that synthesises device entries and handles
vendor quirks in Go, or the server exposes a host API so Lua drivers consume
OCPP messages. Worth deciding before the wiring.

2. Control should be current-based, not RemoteStopTransaction. Charge Amps
remote stop is unreliable in other OCPP integrations — units bounce straight back
to on. The path that works is SetChargingProfile at 0 A to stop and target
amps to start. Phase 2 should model stop that way.

🤖 Generated with Claude Code

claude and others added 2 commits July 31, 2026 09:52
Brings back go/internal/ocpp, retired as unused in srcfl#578, so EV chargers can
connect to FTW directly instead of through a vendor cloud.

The package is restored unchanged and still builds, vets and passes its own
tests against the current tree. github.com/lorenzodonini/ocpp-go resolves to
v0.19.0 at @latest — the same version that was removed, since upstream has not
cut a release since August 2025.

Nothing is wired into main.go yet, so this changes no runtime behaviour. Two
known gaps are carried over from the original and must be closed before the
server is enabled:

- Config.Bind is advisory only. ocpp-go does not expose a bind address, so the
  listener takes 0.0.0.0 regardless, and Phase 1 has no TLS.
- Handlers are read-only. Charge Amps needs SetChargingProfile-based control,
  because its RemoteStopTransaction is unreliable in the field.

Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
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