Skip to content

Commit

Permalink
Merge branch 'evcc-io:master' into feature/add-hoymiles-wifi-inverter…
Browse files Browse the repository at this point in the history
…-meter
  • Loading branch information
BLun78 committed Sep 27, 2024
2 parents dd5e107 + 53928bd commit 802e561
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 25 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,6 @@ jobs:
go-version: ${{ env.GO_VERSION }}
id: go

- name: Install Cloudsmith CLI
run: pip install --upgrade cloudsmith-cli

- name: Patch ASN1
run: make patch-asn1-sudo

Expand All @@ -111,6 +108,10 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TESLA_CLIENT_ID: ${{ secrets.TESLA_CLIENT_ID }}

- uses: actions/setup-python@v5
- name: Install Cloudsmith CLI
run: pip install --upgrade cloudsmith-cli

- name: Publish .deb to Cloudsmith
env:
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ jobs:
go-version: ${{ env.GO_VERSION }}
id: go

- name: Install Cloudsmith CLI
run: pip install --upgrade cloudsmith-cli

- name: Patch ASN1
run: make patch-asn1-sudo

Expand Down Expand Up @@ -105,6 +102,10 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
TESLA_CLIENT_ID: ${{ secrets.TESLA_CLIENT_ID }}

- uses: actions/setup-python@v5
- name: Install Cloudsmith CLI
run: pip install --upgrade cloudsmith-cli

- name: Publish .deb to Cloudsmith
env:
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
Expand Down
7 changes: 6 additions & 1 deletion .goreleaser-nightly.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
version: 2

dist: release
release:
disable: true
Expand Down Expand Up @@ -48,7 +50,7 @@ checksum:
name_template: "checksums.txt"

snapshot:
name_template: '{{ .Version }}{{ if eq (len (split .Version ".")) 2 }}.0{{ end }}+{{ .Timestamp }}'
version_template: '{{ .Version }}{{ if eq (len (split .Version ".")) 2 }}.0{{ end }}+{{ .Timestamp }}'

changelog:
sort: asc
Expand All @@ -73,6 +75,9 @@ nfpms:
formats:
- deb

dependencies:
- adduser

contents:
- src: ./packaging/init/evcc.service
dst: /lib/systemd/system/evcc.service
Expand Down
3 changes: 3 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ nfpms:
formats:
- deb

dependencies:
- adduser

contents:
- src: ./packaging/init/evcc.service
dst: /lib/systemd/system/evcc.service
Expand Down
8 changes: 4 additions & 4 deletions charger/mypv-elwa2.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (wb *MyPvElwa2) heartbeat(timeout time.Duration) {
// Status implements the api.Charger interface
func (wb *MyPvElwa2) Status() (api.ChargeStatus, error) {
res := api.StatusA
b, err := wb.conn.ReadInputRegisters(elwaRegStatus, 1)
b, err := wb.conn.ReadHoldingRegisters(elwaRegStatus, 1)
if err != nil {
return res, err
}
Expand Down Expand Up @@ -181,7 +181,7 @@ var _ api.Meter = (*MyPvElwa2)(nil)

// CurrentPower implements the api.Meter interface
func (wb *MyPvElwa2) CurrentPower() (float64, error) {
b, err := wb.conn.ReadInputRegisters(elwaRegPower, 1)
b, err := wb.conn.ReadHoldingRegisters(elwaRegPower, 1)
if err != nil {
return 0, err
}
Expand All @@ -193,7 +193,7 @@ var _ api.Battery = (*MyPvElwa2)(nil)

// CurrentPower implements the api.Meter interface
func (wb *MyPvElwa2) Soc() (float64, error) {
b, err := wb.conn.ReadInputRegisters(elwaRegTemp, 1)
b, err := wb.conn.ReadHoldingRegisters(elwaRegTemp, 1)
if err != nil {
return 0, err
}
Expand All @@ -205,7 +205,7 @@ var _ api.SocLimiter = (*MyPvElwa2)(nil)

// GetLimitSoc implements the api.SocLimiter interface
func (wb *MyPvElwa2) GetLimitSoc() (int64, error) {
b, err := wb.conn.ReadInputRegisters(elwaRegTempLimit, 1)
b, err := wb.conn.ReadHoldingRegisters(elwaRegTempLimit, 1)
if err != nil {
return 0, err
}
Expand Down
8 changes: 1 addition & 7 deletions charger/ocpp.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,7 @@ func NewOCPP(id string, connector int, idTag string,
stackLevelZero: stackLevelZero,
}

if cp.HasRemoteTriggerFeature {
if err := conn.TriggerMessageRequest(core.StatusNotificationFeatureName); err != nil {
c.log.DEBUG.Printf("failed triggering StatusNotification: %v", err)
}

go conn.WatchDog(10 * time.Second)
}
go conn.WatchDog(10 * time.Second)

return c, conn.Initialized()
}
Expand Down
7 changes: 7 additions & 0 deletions charger/ocpp/cp_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ func (cp *CP) Setup(meterValues string, meterInterval time.Duration) error {
cp.log.DEBUG.Printf("failed configuring %s: %v", KeyWebSocketPingInterval, err)
}

// trigger status for all connectors
if cp.HasRemoteTriggerFeature {
if err := cp.TriggerMessageRequest(0, core.StatusNotificationFeatureName); err != nil {
cp.log.WARN.Printf("failed triggering StatusNotification: %v", err)
}
}

return nil
}

Expand Down
34 changes: 28 additions & 6 deletions cmd/dumper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"os"
"slices"
"strings"
"text/tabwriter"
"time"
Expand Down Expand Up @@ -36,6 +37,11 @@ func (d *dumper) DumpWithHeader(name string, device interface{}) {
func (d *dumper) Dump(name string, v interface{}) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)

var isHeating bool
if fd, ok := v.(api.FeatureDescriber); ok {
isHeating = slices.Contains(fd.Features(), api.Heating)
}

// meter

if v, ok := v.(api.Meter); ok {
Expand Down Expand Up @@ -95,10 +101,18 @@ func (d *dumper) Dump(name string, v interface{}) {
}
}

if err != nil {
fmt.Fprintf(w, "Soc:\t%v\n", err)
if isHeating {
if err != nil {
fmt.Fprintf(w, "Temp:\t%v\n", err)
} else {
fmt.Fprintf(w, "Temp:\t%.0f°C\n", soc)
}
} else {
fmt.Fprintf(w, "Soc:\t%.0f%%\n", soc)
if err != nil {
fmt.Fprintf(w, "Soc:\t%v\n", err)
} else {
fmt.Fprintf(w, "Soc:\t%.0f%%\n", soc)
}
}
}

Expand Down Expand Up @@ -204,10 +218,18 @@ func (d *dumper) Dump(name string, v interface{}) {
}

if v, ok := v.(api.SocLimiter); ok {
if limitSoc, err := v.GetLimitSoc(); err != nil {
fmt.Fprintf(w, "Limit Soc:\t%v\n", err)
if isHeating {
if limitSoc, err := v.GetLimitSoc(); err != nil {
fmt.Fprintf(w, "Max Temp:\t%v\n", err)
} else {
fmt.Fprintf(w, "Max Temp:\t%d°C\n", limitSoc)
}
} else {
fmt.Fprintf(w, "Limit Soc:\t%d%%\n", limitSoc)
if limitSoc, err := v.GetLimitSoc(); err != nil {
fmt.Fprintf(w, "Limit Soc:\t%v\n", err)
} else {
fmt.Fprintf(w, "Limit Soc:\t%d%%\n", limitSoc)
}
}
}

Expand Down
8 changes: 7 additions & 1 deletion tariff/awattar.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,14 @@ func (t *Awattar) run(done chan error) {
for ; true; <-tick.C {
var res awattar.Prices

// Awattar publishes prices for next day around 13:00 CET/CEST, so up to 35h of price data are available
// To be on the safe side request a window of -2h and +48h, the API doesn't mind requesting more than available
start := time.Now().Add(-2 * time.Hour).UnixMilli()
end := time.Now().Add(48 * time.Hour).UnixMilli()
uri := fmt.Sprintf("%s?start=%d&end=%d", t.uri, start, end)

if err := backoff.Retry(func() error {
return backoffPermanentError(client.GetJSON(t.uri, &res))
return backoffPermanentError(client.GetJSON(uri, &res))
}, bo()); err != nil {
once.Do(func() { done <- err })

Expand Down
60 changes: 60 additions & 0 deletions templates/definition/charger/elli-wallbox-2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
template: eebus
products:
- brand: Elli
description:
generic: Charger Connect 2
- brand: Elli
description:
generic: Charger Pro 2
- brand: Elli
description:
generic: Charger Pro Eichrecht 2
- brand: Volkswagen
description:
generic: Charger Connect 2
- brand: Volkswagen
description:
generic: Charger Pro 2
- brand: Volkswagen
description:
generic: Charger Pro Eichrecht 2
- brand: Skoda
description:
generic: Charger Connect
- brand: Skoda
description:
generic: Charger Pro
- brand: Skoda
description:
generic: Charger Pro Eichrecht
- brand: Cupra
description:
generic: Charger Pro 2
- brand: Cupra
description:
generic: Charger Pro 2
- brand: Cupra
description:
generic: Charger Pro Eichrecht 2
capabilities: ["iso151182", "mA"]
requirements:
evcc: ["eebus"]
description:
de: |
Die Wallbox muss im normalen Lademodus betrieben werden.
Die Nutzung der Phasenumschaltung ist in evcc momentan noch nicht möglich.
Eine Identifikation des Fahrzeugs über die RFID Karte ist nicht möglich.
en: |
The device has to be used in the normal charging mode.
The usage of phase switching is currently not possible in evcc.
The identification of a vehicle using the RFID card is not possible.
params:
- preset: eebus
render: |
{{ include "eebus" . }}
meter: true
vasvw: true
73 changes: 73 additions & 0 deletions templates/definition/meter/alpha-ess-smile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ products:
- brand: Alpha ESS
description:
generic: Storion SMILE
capabilities: ["battery-control"]
requirements:
description:
de: |
Um die aktive Ladesteuerung zu nutzen muss einmalig über das Webinterface oder App Zeiten für das Netzladen definiert werden. (Einstellungen->Funktionseinstellungen->Netzladen/Entladen) Hier sollte ein durchgehender Zeitraum (z.B: Ladezeit 1 00:00-23:00, Ladezeit 2 23:00-00:00) eingetragen werden. Den Schalter "Netzladen" aber deaktivieren. Die eigentliche Steuerung erfolgt über evcc. Der Entladestopp wird über eine geplante Netzladung mit einem Ziel-SoC von 10% realisiert. Alternativ können die Zeiten auch über Modbus konfiguriert werden. Dafür die Register `2134,2142,2135,2136,2144,2137,2175` auf die Werte `0,0,23,0,23,0,0,0` setzen.
en: |
To use active battery control, times for grid charging must be defined once via the web interface or app. (Settings->Function settings->Grid charging/discharging) A continuous time period should be entered here (e.g.: Charging time 1 00:00-23:00, Charging time 2 23:00-00:00). However, deactivate the "Grid charging" switch. The actual control takes place via evcc. Discharge stop is realized via a scheduled grid charge with a target SoC of 10%. Alternatively, it can also be configured via Modbus. To do this, set the registers `2134,2142,2135,2136,2144,2137,2175` to the values `0,0,23,0,23,0,0,0,0`.
params:
- name: usage
choice: ["grid", "pv", "battery"]
Expand All @@ -13,6 +20,14 @@ params:
id: 85
- name: capacity
advanced: true
- name: minsoc
default: 10
type: number
advanced: true
- name: maxsoc
default: 100
type: number
advanced: true
render: |
type: custom
{{- if eq .usage "grid" }}
Expand Down Expand Up @@ -134,4 +149,62 @@ render: |
decode: uint16
scale: 0.1
capacity: {{ .capacity }} # kWh
batterymode:
source: switch
switch:
- case: 1 # normal
set:
source: const
value: 0
set:
source: modbus
{{- include "modbus" . | indent 8 }}
register:
address: 2127 # 0x84F Time period control flag
type: writemultiple
decode: uint16
- case: 2 # hold -> Enable grid charging with 10% (default) target soc -> will not start charging but will prevent uncharging of battery
set:
source: sequence
set:
- source: const
value: 1
set:
source: modbus
{{- include "modbus" . | indent 10 }}
register:
address: 2127 # 0x84F Time period control flag
type: writemultiple
decode: uint16
- source: const
value: {{ .minsoc }}
set:
source: modbus
{{- include "modbus" . | indent 10 }}
register:
address: 2133 # 0x855 Charge Cut Soc
type: writemultiple
decode: uint16
- case: 3 # charge -> Enable grid charging with 100% target soc (will be stopped by evcc)
set:
source: sequence
set:
- source: const
value: 1
set:
source: modbus
{{- include "modbus" . | indent 10 }}
register:
address: 2127 # 0x84F Time period control flag
type: writemultiple
decode: uint16
- source: const
value: {{ .maxsoc }}
set:
source: modbus
{{- include "modbus" . | indent 10 }}
register:
address: 2133 # 0x855 Charge Cut Soc
type: writemultiple
decode: uint16
{{- end }}
4 changes: 4 additions & 0 deletions templates/definition/meter/fronius-solarapi-v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ capabilities: ["battery-control"]
requirements:
description:
de: |
Solar API sollte nur als Fallback genutzt werden. Die Integration über Modbus ist bevorzugt.
Benutzername und Passwort werden nur für die aktive Batteriesteuerung benötigt.
**Achtung**: Die aktive Batteriesteuerung sollte nur verwendet werden, wenn keine weiteren Einstellungen für die zeitabhängige Batteriesteuerung in der Wechselrichter-Konfiguration unter "Energiemanagement" - "Batteriemanagement" getätigt wurden, denn bestehende Einstellungen werden überschrieben.
en: |
Solar API should only be used as fallback. Integration via Modbus is preferred.
Username and password are only required for active battery control.
**Attention**: Active battery control should only be used if no other settings for time-dependent battery control were made in the inverter configuration under "Energy Management" - "Battery Management", as existing settings will be overwritten.
Expand Down

0 comments on commit 802e561

Please sign in to comment.