All device types use a registry-based factory pattern:
// Self-registration in init()
func init() {
registry.AddCtx("typename", NewFromConfig)
}
func NewFromConfig(ctx context.Context, other map[string]interface{}) (api.Charger, error) {
// Parse config, create client, return implementation
}Optional interfaces are added via the decorator pattern:
//go:generate decorate -f decorateXxx -b *Xxx -t "api.PhaseSwitcher,Phases1p3p,func(int) error"| Protocol | Examples |
|---|---|
| HTTP/REST | Easee (REST+SignalR), Wallbox, go-e, OpenWB, Shelly |
| Modbus RTU/TCP | KEBA, Wallbe, CFOS, Bender, Delta, Mennekes |
| OCPP 1.6 | Generic charge point server |
| EEBus/ISO 15118 | EEBus SPINE protocol |
| UDP/Custom | KEBA UDP, OpenEVSE, Wattpilot, NRGKick |
| MQTT | OpenWB, Tasmota, Shelly |
| Smart Socket | Shelly, Tapo, TP-Link, FritzDECT |
type Charger interface {
ChargeState
Enabled() (bool, error)
Enable(enable bool) error
CurrentController
}Where ChargeState provides Status() (ChargeStatus, error) (A/B/C) and
CurrentController provides MaxCurrent(current int64) error.
ChargerExβMaxCurrentMillis(float64)for milliamp precisionPhaseSwitcherβPhases1p3p(int)to switch 1p/3pMeter/MeterEnergyβ built-in power/energy measurementPhaseCurrents/PhaseVoltagesβ per-phase readingsChargeRaterβChargedEnergy()for session energyChargeTimerβChargeDuration()for session timeIdentifierβIdentify()for RFID/vehicle identification
- Easee β REST + async SignalR; see
docs/agents/easee-architecture.mdfor full detail - OCPP (
charger/ocpp.go) β Full 1.6 with charge point management - go-e β Dual API (v1 local HTTP, v2 cloud); phase switching on v2
- EEBus β Complex SPINE protocol with USE cases (CEM, EV, EVCC)
- Generic configurable (
charger/charger.go) β plugin-driven via YAML template
- Create
charger/xxx.go(or YAML template intemplates/definition/charger/) - Implement
NewXxxFromConfig()returningapi.Charger - Required:
Status(),Enabled(),Enable(),MaxCurrent() - Register:
registry.AddCtx("xxx", factory)ininit() - Optional: add decorator for PhaseSwitcher, Meter, etc.
- Add template:
templates/definition/charger/xxx.yamlfor UI metadata
| Category | Examples |
|---|---|
| Modbus/SunSpec | SDM630, SMA, Fronius, Victron |
| HTTP/REST | Homewizard, Shelly Gen3, E3DC |
| Smart Home | HomeAssistant entities, Homematic |
| Battery/Storage | Tesla Powerwall, LG ESS, Zendure |
type Meter interface {
CurrentPower() (float64, error) // watts
}- mbmd (
meter/mbmd.go) β RS485 device library with auto-detection - SunSpec (
plugin/sunspec.go) β Modbus model-based point queries - Generic β plugin-driven (HTTP, Modbus, MQTT sources)
| Manufacturer | API Type |
|---|---|
| Tesla | Fleet API + vehicle-command proxy |
| VW Group | WeConnect (VW, Audi, Skoda, Seat, Cupra) |
| Hyundai/Kia | BlueLink (regional variants) |
| BMW/Mini | ConnectedDrive v2 |
| Mercedes | Official API |
| Renault/Nissan | Renault API + Carwings |
| Ford | FordConnect (US/EU) |
| Porsche | Porsche Connect |
| PSA Group | Peugeot, Citroen, DS, Opel |
| Generic | OVMS, Tronity |
type Vehicle interface {
Battery // Soc() (float64, error)
BatteryCapacity // Capacity() float64
IconDescriber // Icon() string
FeatureDescriber // Features() []Feature
PhaseDescriber // Phases() int
TitleDescriber // GetTitle() string
SetTitle(string)
Identifiers() []string
OnIdentified() ActionConfig
}Optional: SocLimiter, ChargeState, VehicleRange, VehicleOdometer, VehicleClimater, VehicleFinishTimer, VehiclePosition, CurrentLimiter, CurrentController, ChargeController, Resurrector
Configurable: always / while charging / while connected. Interval-based caching to avoid excessive cloud API calls. OAuth2 token handling built into each provider.
Task-based parallel IP scanning:
ping -> tcp_http -> tcp_modbus -> sunspec -> device-specific probes
Detects: OpenWB, SMA, KEBA, E3DC, Sonnen, Tesla Powerwall, Wallbe, Fronius, Tasmota, Shelly, Phoenix, and many more.