From 7b8ccdfdba1dca63a307d8b3147142040fc1814c Mon Sep 17 00:00:00 2001 From: Martin Buchleitner Date: Tue, 17 Jan 2023 11:22:29 +0100 Subject: [PATCH] Add Fronius Wattpilot (#5772) --- charger/wattpilot.go | 134 ++++++++++++++++++ go.mod | 1 + go.sum | 2 + templates/definition/charger/wattpilot.yaml | 24 ++++ .../docs/charger/fronius-wattpilot_0.yaml | 13 ++ templates/evcc.io/brands.json | 1 + 6 files changed, 175 insertions(+) create mode 100644 charger/wattpilot.go create mode 100644 templates/definition/charger/wattpilot.yaml create mode 100644 templates/docs/charger/fronius-wattpilot_0.yaml diff --git a/charger/wattpilot.go b/charger/wattpilot.go new file mode 100644 index 000000000..717ad7c9b --- /dev/null +++ b/charger/wattpilot.go @@ -0,0 +1,134 @@ +package charger + +import ( + "errors" + "fmt" + "time" + + "github.com/evcc-io/evcc/api" + "github.com/evcc-io/evcc/util" + wattpilot "github.com/mabunixda/wattpilot" +) + +// Wattpilot charger implementation +type Wattpilot struct { + api *wattpilot.Wattpilot +} + +func init() { + registry.Add("wattpilot", NewWattpilotFromConfig) +} + +// NewWattpilotFromConfig creates a wattpilot charger from generic config +func NewWattpilotFromConfig(other map[string]interface{}) (api.Charger, error) { + var cc struct { + URI string + Password string + Cache time.Duration + } + + if err := util.DecodeOther(other, &cc); err != nil { + return nil, err + } + + if cc.URI == "" || cc.Password == "" { + return nil, errors.New("must have uri and password") + } + + return NewWattpilot(cc.URI, cc.Password, cc.Cache) +} + +// NewWattpilot creates Wattpilot charger +func NewWattpilot(uri, password string, cache time.Duration) (api.Charger, error) { + c := &Wattpilot{ + api: wattpilot.New(uri, password), + } + + if _, err := c.api.Connect(); err != nil { + return nil, err + } + + return c, nil +} + +// Status implements the api.Charger interface +func (c *Wattpilot) Status() (api.ChargeStatus, error) { + car, err := c.api.GetProperty("car") + if err != nil { + return api.StatusNone, err + } + + switch car.(float64) { + case 1.0: + return api.StatusA, nil + case 2.0, 5.0: + return api.StatusC, nil + case 3.0, 4.0: + return api.StatusB, nil + default: + return api.StatusNone, fmt.Errorf("car unknown result: %d", car) + } +} + +// Enabled implements the api.Charger interface +func (c *Wattpilot) Enabled() (bool, error) { + resp, err := c.api.GetProperty("alw") + if err != nil { + return false, err + } + return resp.(bool), nil +} + +// Enable implements the api.Charger interface +func (c *Wattpilot) Enable(enable bool) error { + var forceState int + if !enable { + forceState = 1 // off + } + + return c.api.SetProperty("frc", forceState) +} + +// MaxCurrent implements the api.Charger interface +func (c *Wattpilot) MaxCurrent(current int64) error { + return c.api.SetCurrent(float64(current)) +} + +var _ api.Meter = (*Wattpilot)(nil) + +// CurrentPower implements the api.Meter interface +func (c *Wattpilot) CurrentPower() (float64, error) { + return c.api.GetPower() +} + +var _ api.ChargeRater = (*Wattpilot)(nil) + +// ChargedEnergy implements the api.ChargeRater interface +func (c *Wattpilot) ChargedEnergy() (float64, error) { + resp, err := c.api.GetProperty("wh") + if err != nil { + return 0, err + } + return resp.(float64) / 1e3, err +} + +var _ api.PhaseCurrents = (*Wattpilot)(nil) + +// Currents implements the api.PhaseCurrents interface +func (c *Wattpilot) Currents() (float64, float64, float64, error) { + return c.api.GetCurrents() +} + +var _ api.PhaseVoltages = (*Wattpilot)(nil) + +// Currents implements the api.PhaseCurrents interface +func (c *Wattpilot) Voltages() (float64, float64, float64, error) { + return c.api.GetVoltages() +} + +var _ api.Identifier = (*Wattpilot)(nil) + +// Identify implements the api.Identifier interface +func (c *Wattpilot) Identify() (string, error) { + return c.api.GetRFID() +} diff --git a/go.mod b/go.mod index b40aa02b1..3ae0f341e 100644 --- a/go.mod +++ b/go.mod @@ -62,6 +62,7 @@ require ( github.com/libp2p/zeroconf/v2 v2.2.0 github.com/lorenzodonini/ocpp-go v0.16.1-0.20220927200117-d4afed542168 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 + github.com/mabunixda/wattpilot v1.1.1 github.com/manifoldco/promptui v0.9.0 github.com/mergermarket/go-pkcs7 v0.0.0-20170926155232-153b18ea13c9 github.com/mitchellh/go-homedir v1.1.0 diff --git a/go.sum b/go.sum index 7b7038df4..470c524d1 100644 --- a/go.sum +++ b/go.sum @@ -603,6 +603,8 @@ github.com/lorenzodonini/ocpp-go v0.16.1-0.20220927200117-d4afed542168/go.mod h1 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/mabunixda/wattpilot v1.1.1 h1:ZEzaYp1hHea8MQtQxoZlMzxwZppOUEDiBg45sKBs514= +github.com/mabunixda/wattpilot v1.1.1/go.mod h1:LiFXIWIV81uAxsazaDFArWOgM4srGxsyBPSmvQVUvjo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= diff --git a/templates/definition/charger/wattpilot.yaml b/templates/definition/charger/wattpilot.yaml new file mode 100644 index 000000000..3215b9e3a --- /dev/null +++ b/templates/definition/charger/wattpilot.yaml @@ -0,0 +1,24 @@ +template: fronius-wattpilot +products: + - brand: Fronius + description: + generic: Wattpilot +capabilities: ["1p3p", "rfid"] +requirements: + description: + de: | + Benötigt mindestens Firmware 36.3 oder neuer. + en: | + Requires firmware 36.3 or later. + uri: https://docs.evcc.io/docs/devices/chargers# +params: + - name: host + - name: password +render: | + type: wattpilot + {{ if .host }} + uri: {{ .host }} + {{ end }} + {{ if ne .password "" }} + password: {{ .password }} + {{ end }} diff --git a/templates/docs/charger/fronius-wattpilot_0.yaml b/templates/docs/charger/fronius-wattpilot_0.yaml new file mode 100644 index 000000000..afba5cbf5 --- /dev/null +++ b/templates/docs/charger/fronius-wattpilot_0.yaml @@ -0,0 +1,13 @@ +product: + brand: Fronius + description: Wattpilot +capabilities: ["1p3p", "rfid"] +description: | + Benötigt mindestens Firmware 36.3 oder neuer. + +render: + - default: | + type: template + template: fronius-wattpilot + host: 192.0.2.2 # IP-Adresse oder Hostname + password: # Passwort des Benutzerkontos (bei führenden Nullen bitte in einfache Hochkommata setzen) # Optional diff --git a/templates/evcc.io/brands.json b/templates/evcc.io/brands.json index f98cbd580..04f5fa47f 100644 --- a/templates/evcc.io/brands.json +++ b/templates/evcc.io/brands.json @@ -16,6 +16,7 @@ "Elli", "Ensto", "Etrel", + "Fronius", "Garo", "go-eCharger", "HardyBarth",