Reach the charger where it is, instead of waiting for it to call
OCPP asks the charger to dial us: a public endpoint, a TLS certificate, and a route in through the customer's router. Our own handler then demanded two more things the V1 does not offer — TLS on a charger that connects over ws://, and Basic auth credentials the Anker app has no field for — so every connection was turned away before the upgrade. Anker publishes a Modbus TCP register map for this charger, and it inverts the problem: we dial the charger, on its own network, with no inbound reachability to arrange. That works for a charger behind a router that OCPP cannot reach at all. internal/modbus is the protocol, hand-rolled against the spec like the MQTT and WebSocket clients beside it. The plugin's modbus.go is the V1's map: the same 0-8 status enum the cloud already reports, per-phase measurements, and the writable registers behind start, stop, current limit, boost and phase mode. A new "modbus" control mode routes the existing control endpoints down it, so the REST surface, the rate limit, the confirmation step and the audit trail are the ones already there. The commands the register map has no equivalent for say so by name rather than failing as unknown, and a current below the charger's 6 A floor is refused because it pauses the charge rather than slowing it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e9a82a1cca
commit
f7472bada3
13 files changed
+1658
-47
No files matched your search
@@ -28,10 +28,14 @@ const (
|
||||
ankerPlugin = "anker-solix"
|
||||
ankerSecretMask = "••••••••"
|
||||
|
||||
// OCPP control modes for the Anker Solix charger (see internal/ocpp).
|
||||
ankerControlOff = "off" // monitoring only (default)
|
||||
ankerControlOwn = "own" // DriverVault is the charger's Central System
|
||||
ankerControlProxy = "proxy" // DriverVault relays to Anker's cloud and injects
|
||||
// Control modes for the Anker Solix charger. The first three are OCPP paths
|
||||
// (see internal/ocpp) and need the charger to dial in to us; modbus is the
|
||||
// local path (see the ankersolix plugin's modbus.go), where we dial the
|
||||
// charger instead — the only one that works when the charger cannot reach us.
|
||||
ankerControlOff = "off" // monitoring only (default)
|
||||
ankerControlOwn = "own" // DriverVault is the charger's Central System
|
||||
ankerControlProxy = "proxy" // DriverVault relays to Anker's cloud and injects
|
||||
ankerControlModbus = "modbus" // DriverVault talks Modbus TCP to the charger on the LAN
|
||||
)
|
||||
|
||||
// normalizeControlMode maps a raw control-mode value to a recognized mode, or ""
|
||||
@@ -43,6 +47,8 @@ func normalizeControlMode(v string) string {
|
||||
return ankerControlOwn
|
||||
case ankerControlProxy:
|
||||
return ankerControlProxy
|
||||
case ankerControlModbus:
|
||||
return ankerControlModbus
|
||||
case ankerControlOff:
|
||||
return ankerControlOff
|
||||
default:
|
||||
@@ -60,7 +66,8 @@ type ankerConfig struct {
|
||||
ControlMode string `json:"controlMode"`
|
||||
}
|
||||
|
||||
// ankerChargerBinding records a per-charger OCPP control token. The operator
|
||||
// ankerChargerBinding is what we know about one charger the caller controls:
|
||||
// its OCPP control token, its local Modbus address, or both. The operator
|
||||
// installs the token into the charger (as its OCPP Basic-auth password); we keep
|
||||
// only its SHA-256 hash and a short hint, never the plaintext — the token is
|
||||
// shown to the owner exactly once, at generation. User-layer only, not a cascade
|
||||
@@ -69,6 +76,14 @@ type ankerChargerBinding struct {
|
||||
TokenHash string `json:"tokenHash,omitempty"` // sha256(token), lowercase hex
|
||||
TokenHint string `json:"tokenHint,omitempty"` // last 4 chars, for the UI
|
||||
AddedAt string `json:"addedAt,omitempty"`
|
||||
|
||||
// ModbusHost and ModbusPort address the charger's local Modbus TCP server,
|
||||
// which the owner enables in the Anker app (Settings > Integrations > Modbus
|
||||
// TCP; the app then shows this address). They are per charger rather than per
|
||||
// account because they are a LAN address, not a credential — and unlike the
|
||||
// OCPP token they are not a secret, so they are stored and shown verbatim.
|
||||
ModbusHost string `json:"modbusHost,omitempty"`
|
||||
ModbusPort int `json:"modbusPort,omitempty"` // 0 means the standard 502
|
||||
}
|
||||
|
||||
// ankerStored is what we persist per user/org under pluginSettings.ankerSolix.
|
||||
|
||||
Reference in new issue
Block a user