evcc-io / evcc

Sonne tanken ☀️🚘
https://evcc.io
MIT License
2.86k stars 541 forks source link

e3DC Entladesperrzeiten nutzen #13403

Closed veiter555 closed 3 months ago

veiter555 commented 3 months ago

Describe the solution you'd like Ich möchte im Schnelllademodus nicht, dass meine E3/DC Batterie entladen wird.

Anwendungsfall Bsp.: PHEV kommt um 19 Uhr Heim und muss schnell geladen werden da bis zum nächsten Morgen kein PV Überschuss vorhanden sein wird. Allerdings möchte ich keine Energie aus der Haus-Batterie dafür verwenden (Batterieentladen sperren) oder die Batterienutzung nur bis zu einem bestimmten SOC zulassen (Rest der Batterieladung sollte das Haus später versorgen)

Zusätzlich wird die Batterie geschont durch Reduzierung der Tiefentladezyklen.

Über RSCP können Sperrzeiten übermittelt werden. Es wäre super wenn EVCC das dynamisch anwenden könnte. Bsp. Fahrzeug läd - Min. Entlade SOC der E3/DC Batterie ist erreicht, der nicht durch Fahrzeug unterschritten werden soll. - Entladen der E3/DC Batterie wird gesperrt bis Fahrzeug fertig geladen ist und anschließend automatisch wieder entsperrt um die Batterie für die Hausversorgung wieder freizugeben.

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

Additional context Add any other context or screenshots about the feature request here.

andig commented 3 months ago

@spali I have now found EMS_PARAM_INSTALLED_BAT_CAP. Since that has no REQ in its name I'll need to make it a container request? Or do I need the (not yet defined) TAG_BAT_REQ_SPECIFICATION for that? Unfortunately without a system it is entirely impossible to do anything program-wise without wasting time :(

docolli commented 3 months ago

@andig Keep cool, we are working on it and when we have the command string to get the data, we will send it to you! 😎 I can test all the suggested commands with my E3DC system.

andig commented 3 months ago

Bin nicht 100% sicher, aber es müsste möglich sein den globalen Logger von logrus zu konfigurieren. Ein import vom logger und dann gemäss Doku den Output anpassen.

@spali das wird nicht funktionieren da unterschiedliche Komponenten unterschiedliche Logger brauchen. Das klappt nicht, wenn sich e3dc und andere Bibliotheken einen globalen Logger teilen. Typische Lösung wäre in der Bibliothek zwar eine Log-Library zu nutzen, der Anwendung aber freizustellen ein eigenes Interface einzusetzen.

andig commented 3 months ago

@docolli prima. Dann lege ich mich hin bis es eine vollstände Beschreibung für alle Messwerte gibt.

spali commented 3 months ago

@spali I have now found EMS_PARAM_INSTALLED_BAT_CAP. Since that has no REQ in its name I'll need to make it a container request? Or do I need the (not yet defined) TAG_BAT_REQ_SPECIFICATION for that? Unfortunately without a system it is entirely impossible to do anything program-wise without wasting time :(

Du selber solltest keine Requests zusammen bauen. Wie du siehst ist das Blindflug. Ich kann leider nur begrenzt helfen, da mein Model ziemlich kastriert ist. Jemand der ein aktiv evcc nutzt oder zumindest testen kann und die rscp Befehle ein wenig kennt und ausprobieren kann, sollte dir die fertigen Befehle liefern und eine Beispiel-Antwort dazu @docolli 😜. Du musst das dann nur in go umsetzen.

docolli commented 3 months ago

Heute Abend kann ich weiter testen, muss auch noch was arbeiten.... Befehl samt Antwort werden von mir geliefert, bitte um etwas Gelduld.

spali commented 3 months ago

@spali das wird nicht funktionieren da unterschiedliche Komponenten unterschiedliche Logger brauchen. Das klappt nicht, wenn sich e3dc und andere Bibliotheken einen globalen Logger teilen. Typische Lösung wäre in der Bibliothek zwar eine Log-Library zu nutzen, der Anwendung aber freizustellen ein eigenes Interface einzusetzen.

Du kannst logrus ein Writer geben, siehe z.B. https://stackoverflow.com/questions/76291992/logrus-wrapper-for-standard-go-log-logger der dann du implementierst.

andig commented 3 months ago

Das würde gehen. Dann bräuchte ich aber eine Logrus Instanz mit der ich das machen kann. Die "globale" Logrus Defaultinstanz könnten sich ja mehrere Module teilen. Es wäre also super, wenn sich der verwendete *logrus.Logger konfigurieren ließe. Auf die eigene Instanz kann ich dann einen Adapter bauen.

Minimalinvasiver Vorschlag: du könntest in einer Datei

import (
    "github.com/sirupsen/logrus"
)

var log logrus.StdLogger = logrus.StandardLogger()

// SetLogger allows defining a logrus.StdLogger. The logger must not be nil.
func SetLogger(l logrus.StdLogger) {
    log = l
}

Das sollte nur minimale Codeanpassungen bedeuten und ich könnte einen Logrus Logger oder sogar ein anderes Interface injecten.

docolli commented 3 months ago

Danke @spali für deinen go-rscp Beispielcode! Damit sollte es jetzt klar sein, wie man die Anfrage nach der Batteriekapazität gestalten muss. Wichtig ist, dass man in evcc noch definieren muss, welchen Bat_Index man abfragen will, also welchen Batteriespeicher. In der Regel bei kleinen System mit nur 1 Speicher wird dies 0 sein. Hat jemand aber mehrere Batteriespeicher bei sich stehen, ist es hilfreich, wenn man das bei der Konfiguration in evcc mit angeben kann.

./e3dc -debug 6 '[["BAT_REQ_DATA",[["BAT_INDEX","",0],["BAT_REQ_SPECIFICATION","None",0]]]]' | jq
INFO[0000] Connecting to 192.168.1.121:5033
INFO[0000] successfully connected to 192.168.1.121:5033
INFO[0000] hiding auth request for security, use debug >= 99 to debug authentication
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0x3, 0x67, 0x22, 0x66, 0x0, 0x0, 0x0, 0x0, 0x78, 0xf1, 0xd0, 0x1f, 0x8, 0x0, 0x1, 0x0, 0x80, 0x0, 0x3, 0x1, 0x0, 0xa, 0xc7, 0xd0, 0xe1, 0x1f}
TRAC[0000] read [{ RSCP_AUTHENTICATION UChar8 10 }]
INFO[0000] successfully authenticated (level: AUTH_LEVEL_USER)
DEBU[0000] write [{ BAT_REQ_DATA Container [{ BAT_INDEX UInt16 0 } { BAT_REQ_SPECIFICATION None <nil> }] }]
TRAC[0000] write plain []byte{0xe3, 0xdc, 0x0, 0x11, 0xc4, 0x5d, 0x22, 0x66, 0x0, 0x0, 0x0, 0x0, 0x77, 0xb0, 0x77, 0x16, 0x17, 0x0, 0x0, 0x0, 0x4, 0x3, 0xe, 0x10, 0x0, 0x1, 0x0, 0x4, 0x3, 0x5, 0x2, 0x0, 0x0, 0x0, 0x43, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0xc9, 0xca, 0x9, 0xab}
TRAC[0000] write crypt []byte{0x6, 0xda, 0xc, 0xb, 0x44, 0xf7, 0x3, 0x44, 0x9d, 0x57, 0x1e, 0x7f, 0xdb, 0x54, 0x56, 0x99, 0x53, 0xf5, 0xba, 0x50, 0xb7, 0x24, 0xf6, 0x85, 0x37, 0x25, 0x77, 0xb, 0xfd, 0x4f, 0x3e, 0x99, 0x98, 0x26, 0x9a, 0xf6, 0x66, 0x92, 0xd4, 0x4, 0x9f, 0x81, 0xfb, 0x5f, 0xde, 0x9b, 0xfd, 0x2f, 0x15, 0x9f, 0x39, 0x7d, 0xc1, 0xb0, 0xec, 0x7f, 0x4d, 0xbb, 0xdb, 0x8e, 0x7e, 0x47, 0xb5, 0xcd}
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0x3, 0x67, 0x22, 0x66, 0x0, 0x0, 0x0, 0x0, 0x10, 0xd, 0xe5, 0x20, 0x4e, 0x0, 0x0, 0x0, 0x84, 0x3, 0xe, 0x47, 0x0, 0x1, 0x0, 0x4, 0x3, 0x5, 0x2, 0x0, 0x0, 0x0, 0x43, 0x0, 0x80, 0x3, 0xe, 0x37, 0x0, 0x25, 0x1, 0x80, 0x3, 0x6, 0x4, 0x0, 0x33, 0x33, 0x0, 0x0, 0x26, 0x1, 0x80, 0x3, 0x6, 0x4, 0x0, 0xe0, 0x2e, 0x0, 0x0, 0x27, 0x1, 0x80, 0x3, 0x6, 0x4, 0x0, 0xe0, 0x2e, 0x0, 0x0, 0x28, 0x1, 0x80, 0x3, 0x6, 0x4, 0x0, 0x8, 0x0, 0x0, 0x0, 0x29, 0x1, 0x80, 0x3, 0x7, 0x4, 0x0, 0x1, 0x1, 0x0, 0x0, 0x5a, 0x76, 0x20, 0xe4}
TRAC[0000] read [{ BAT_DATA Container [{ BAT_INDEX UInt16 0 } { BAT_SPECIFICATION Container [{ BAT_SPECIFIED_CAPACITY Int32 13107 } { BAT_SPECIFIED_DSCHARGE_POWER Int32 12000 } { BAT_SPECIFIED_CHARGE_POWER Int32 12000 } { BAT_SPECIFIED_MAX_DCB_COUNT Int32 8 } { BAT_ROLE Uint32 257 }] }] }]
INFO[0000] disconnected
{
  "BAT_DATA": {
    "BAT_INDEX": 0,
    "BAT_SPECIFICATION": {
      "BAT_SPECIFIED_CAPACITY": 13107,
      "BAT_SPECIFIED_DSCHARGE_POWER": 12000,
      "BAT_SPECIFIED_CHARGE_POWER": 12000,
      "BAT_SPECIFIED_MAX_DCB_COUNT": 8,
      "BAT_ROLE": 257
    }
  }
}

@andig Somit wird dein Code aktuell nicht funktionieren. Du musst den Request so zusammen bauen:

request := rscp.Message{
        Tag:      rscp.BAT_REQ_DATA,
        DataType: rscp.Container,
        Value: []rscp.Message{
            {
                Tag:      rscp.BAT_INDEX,
                DataType: rscp.UInt16,
                Value:    uint16(0),
            },
            {
                Tag:      rscp.BAT_REQ_SPECIFICATION,
                DataType: rscp.None,
                Value:    nil,
            },
        },
    }

Und die Kapazität aus dem JSON parsen -> "BAT_SPECIFIED_CAPACITY"

Ich habe versucht das selber anzupassen, aber meine Fähigkeiten sind nur rudimentär:

// decorate api.BatterySoc
    var batterySoc func() (float64, error)
    var batteryCapacity func() float64
    if usage == templates.UsageBattery {
        batterySoc = res.batterySoc
        batteryCapacity = res.batteryCapacity

        request := rscp.Message{
            Tag:      rscp.BAT_REQ_DATA,
            DataType: rscp.Container,
            Value: []rscp.Message{
                {
                    Tag:      rscp.BAT_INDEX,
                    DataType: rscp.UInt16,
                    Value:    uint16(0), // hard coded for battery index 0
                },
                {
                    Tag:      rscp.BAT_REQ_SPECIFICATION,
                    DataType: rscp.None,
                    Value:    nil,
                },
            },
        }
        msg, err := res.conn.Send(request)
        if err != nil {
            return nil, err
        }

        cap, err := cast.ToFloat64E(msg.Value)
        if err != nil {
            return nil, err
        }

        res.capacity = cap / 1e3
    }

Ergebniss (ich kann kein JSON parsen):

[main  ] INFO 2024/04/19 15:08:43 evcc 0.125.0 (a3bce87a)
[main  ] INFO 2024/04/19 15:08:43 using config file: c:\Daten\SW-Entwicklung\evcc\system\evcc\evcc.yaml
[main  ] INFO 2024/04/19 15:08:43 starting ui and api at :7070
[db    ] INFO 2024/04/19 15:08:43 using sqlite database: C:\Daten\SW-Entwicklung\evcc\system\evcc\evcc.db
time="2024-04-19T15:08:43+02:00" level=info msg="Connecting to 192.168.1.121:5033"
time="2024-04-19T15:08:43+02:00" level=info msg="successfully connected to 192.168.1.121:5033"
time="2024-04-19T15:08:43+02:00" level=info msg="hiding auth request for security, use debug >= 99 to debug authentication"
time="2024-04-19T15:08:43+02:00" level=info msg="successfully authenticated (level: AUTH_LEVEL_USER)"
[main  ] FATAL 2024/04/19 15:08:43 cannot create meter 'battery1': cannot create meter type 'e3dc-2': unable to cast []rscp.Message{rscp.Message{Tag:0x3040001, DataType:0x5, Value:0x0}, rscp.Message{Tag:0x3800043, DataType:0xe, Value:[]rscp.Message{rscp.Message{Tag:0x3800125, DataType:0x6, Value:13107}, rscp.Message{Tag:0x3800126, DataType:0x6, Value:12000}, rscp.Message{Tag:0x3800127, DataType:0x6, Value:12000}, rscp.Message{Tag:0x3800128, DataType:0x6, Value:8}, rscp.Message{Tag:0x3800129, DataType:0x7, Value:0x101}}}} of type []rscp.Message to float64
[main  ] FATAL 2024/04/19 15:08:43 will attempt restart in: 5m0s
docolli commented 3 months ago

Und hier noch die Beschäftigung mit der Limitierung der Entladeleistung.

So schaltet man die Limitierung ein:

./e3dc '[["EMS_REQ_SET_POWER_SETTINGS",[["EMS_POWER_LIMITS_USED","Bool",1]]]]'
{"EMS_SET_POWER_SETTINGS":{"EMS_RES_POWER_LIMITS_USED":0}}

So frägt man die aktuell gültigen Werte ab (bei mir Limit 1500W):

./e3dc '[["EMS_REQ_GET_POWER_SETTINGS","None","Nil"]]' | jq
{
  "EMS_GET_POWER_SETTINGS": {
    "EMS_POWER_LIMITS_USED": true,
    "EMS_MAX_CHARGE_POWER": 1500,
    "EMS_MAX_DISCHARGE_POWER": 1500,
    "EMS_DISCHARGE_START_POWER": 65,
    "EMS_POWERSAVE_ENABLED": true,
    "EMS_WEATHER_REGULATED_CHARGE_ENABLED": false,
    "EMS_WEATHER_FORECAST_MODE": 0
  }
}

Und so setzt man das Entladelimit:

./e3dc '[["EMS_REQ_SET_POWER_SETTINGS",[["EMS_MAX_DISCHARGE_POWER","Int8",500]]]]'
{"EMS_SET_POWER_SETTINGS":{"EMS_RES_MAX_DISCHARGE_POWER":1}}

Kontrollabfrage:

./e3dc '[["EMS_REQ_GET_POWER_SETTINGS","None","Nil"]]' | jq
{
  "EMS_GET_POWER_SETTINGS": {
    "EMS_POWER_LIMITS_USED": true,
    "EMS_MAX_CHARGE_POWER": 1000,
    "EMS_MAX_DISCHARGE_POWER": 500,
    "EMS_DISCHARGE_START_POWER": 65,
    "EMS_POWERSAVE_ENABLED": true,
    "EMS_WEATHER_REGULATED_CHARGE_ENABLED": false,
    "EMS_WEATHER_FORECAST_MODE": 0
  }
}

Und noch ein Test (-> Backofen an). Ja, die Batterie liefert jetzt nur noch 500W 😃: grafik

andig commented 3 months ago

Ich habe versucht das selber anzupassen, aber meine Fähigkeiten sind nur rudimentär:

@docolli schau mal ob/was der letzte Commit tut :)

docolli commented 3 months ago
[main  ] INFO 2024/04/19 16:38:12 evcc 0.125.0 (5bf2b9c2)
[main  ] INFO 2024/04/19 16:38:12 using config file: c:\Daten\SW-Entwicklung\evcc\system\evcc\evcc.yaml
[main  ] INFO 2024/04/19 16:38:12 starting ui and api at :7070
[db    ] INFO 2024/04/19 16:38:12 using sqlite database: C:\Daten\SW-Entwicklung\evcc\system\evcc\evcc.db
time="2024-04-19T16:38:12+02:00" level=info msg="Connecting to 192.168.1.121:5033"
time="2024-04-19T16:38:12+02:00" level=info msg="successfully connected to 192.168.1.121:5033"
time="2024-04-19T16:38:12+02:00" level=info msg="hiding auth request for security, use debug >= 99 to debug authentication"
time="2024-04-19T16:38:12+02:00" level=info msg="successfully authenticated (level: AUTH_LEVEL_USER)"
[main  ] FATAL 2024/04/19 16:38:12 cannot create meter 'battery1': cannot create meter type 'e3dc-2': message at index 0: expected *[]rscp.Message got []*rscp.Message : value does not match data type
[main  ] FATAL 2024/04/19 16:38:12 will attempt restart in: 5m0s
andig commented 3 months ago

@docolli nochmal?

docolli commented 3 months ago
[main  ] INFO 2024/04/19 16:52:47 evcc 0.125.0 (029d9bdf)
[main  ] INFO 2024/04/19 16:52:47 using config file: c:\Daten\SW-Entwicklung\evcc\system\evcc\evcc.yaml
[main  ] INFO 2024/04/19 16:52:47 starting ui and api at :7070
[db    ] INFO 2024/04/19 16:52:47 using sqlite database: C:\Daten\SW-Entwicklung\evcc\system\evcc\evcc.db
time="2024-04-19T16:52:47+02:00" level=info msg="Connecting to 192.168.1.121:5033"
time="2024-04-19T16:52:47+02:00" level=info msg="successfully connected to 192.168.1.121:5033"
time="2024-04-19T16:52:47+02:00" level=info msg="hiding auth request for security, use debug >= 99 to debug authentication"
time="2024-04-19T16:52:47+02:00" level=info msg="successfully authenticated (level: AUTH_LEVEL_USER)"
[site  ] INFO 2024/04/19 16:52:47 site config:
[site  ] INFO 2024/04/19 16:52:47   meters:      grid ✓ pv ✓ battery ✓
[site  ] INFO 2024/04/19 16:52:47     grid:      power ✓ energy ✗ currents ✗
[site  ] INFO 2024/04/19 16:52:47     pv 1:      power ✓ energy ✗ currents ✗
[site  ] INFO 2024/04/19 16:52:47     battery 1: power ✓ energy ✗ currents ✗ soc ✓ capacity ✓
[lp-1  ] INFO 2024/04/19 16:52:47 loadpoint 1:
[lp-1  ] INFO 2024/04/19 16:52:47   mode:        off
[lp-1  ] INFO 2024/04/19 16:52:47   charger:     power ✓ energy ✗ currents ✗ phases ✗ wakeup ✗
[lp-1  ] INFO 2024/04/19 16:52:47   meters:      charge ✓
[lp-1  ] INFO 2024/04/19 16:52:47     charge:    power ✓ energy ✗ currents ✗
[site  ] WARN 2024/04/19 16:52:47 interval <30s can lead to unexpected behavior, see https://docs.evcc.io/docs/reference/configuration/interval
time="2024-04-19T16:52:47+02:00" level=info msg="Connecting to 192.168.1.121:5033"
time="2024-04-19T16:52:47+02:00" level=info msg="successfully connected to 192.168.1.121:5033"
time="2024-04-19T16:52:47+02:00" level=info msg="hiding auth request for security, use debug >= 99 to debug authentication"
time="2024-04-19T16:52:47+02:00" level=info msg="successfully authenticated (level: AUTH_LEVEL_USER)"
time="2024-04-19T16:52:47+02:00" level=info msg="Connecting to 192.168.1.121:5033"
time="2024-04-19T16:52:47+02:00" level=info msg="successfully connected to 192.168.1.121:5033"
time="2024-04-19T16:52:47+02:00" level=info msg="hiding auth request for security, use debug >= 99 to debug authentication"
time="2024-04-19T16:52:47+02:00" level=info msg="successfully authenticated (level: AUTH_LEVEL_USER)"
[lp-1  ] INFO 2024/04/19 16:52:47 car disconnected

grafik

grafik

Edit: Läuft stabil! Keine weiteren Log-Nachrichten seit dem Start vor 20min. empfangen.

docolli commented 3 months ago

Nachdem nun klar ist, wie man E3DC per RSCP anspricht und die Implemetierung der Basisabfragen erfolgreich ist, kommen wir mal zur eigentlichen Anfrage zurück, wie man die Entladung im Schnelllademodus unterbinden kann.

Verstehe ich das richtig, dass es mit

site:
  batteryDischargeControl: true

eine Möglichkeit gibt bei Ladung mit max. Leistung (z.B. Mode Now) die Entladung einer Hausbatterie komplett zu unterbinden und dies ist bereits für einige Hausbatterien implementiert? https://github.com/evcc-io/evcc/pull/10553

So etwas könnte man nun für E3DC auch leicht implementieren. Es wäre auch möglich die max. Entladeleistung des Hausakku vorzugeben (z.B. ein typ. Hausverbrauch von 500W), sodaß trotz Schnellladen der Hausakku noch Energie liefert und so den Eigenverbrauch erhöht. Ist so etwas schon vorgesehen, dass man in der config einen Wert definiert, bis zu dem der Hausakku dann Leistung liefert?

veiter555 commented 3 months ago

Hallo,

könnte man die max Entladeleistung nicht dynamisch setzen alle 20 oder 30 sec. Da evcc ja den Hausverbrquch kennt könnte dieser genommen werden natürlich abzüglich der PV Leistung.

VG Veiter

docolli commented 3 months ago

@veiter555 Das ist das, was das E3DC System in Kombination mit einer E3DC Wallbox bei entsprechender Konfiguration bereits von sich aus kann. Siehe https://github.com/evcc-io/evcc/wiki/docolli:-E3DC-S10E-Hauskraftwerk-&-Easy-Connect-Wallbox-11kW,-FHEM,-rscp2mqtt,-MyStrom-Wifi-Switch,-Nissan-Leaf-ZE1#wallbox

Aus meiner Sicht gibt es 4 mögliche Szenarien für eine Batteriesteuerung

1) Bei Schnellladung keine Batterieentladung (mehr) unterhalb eines definierbaren BatterieSoc (=bufferSoc?) 2) Bei Schnellladung wird Batterieentladeleistung unterhalb eines definierbaren BatterieSoc (=bufferSoc?) limitiert auf vom Nutzer konfigurierbaren Wert 3) Bei Schnellladung wird Batterieentladeleistung durch evcc dynamisch limitiert auf Hausverbrauch 4) Bei Schnellladung wird Batterieentladeleistung durch E3DC System unterhalb eines definierbaren BatterieSoc (=bufferSoc?) dynamisch limitiert auf Hausverbrauch

Fall 1) Ist am leichtesten zu implementieren, hier muss bei Schnellladung bei Unterschreiten des definierten BatterieSoc nur das Entladelimit auf 0 gesetzt werden. Dies wäre mit allen Wallboxen kompatibel. Nachteil: In diesem Modus kommt der komplette Strombedarf aus dem Netz, die Hausbatterie ist hier ohne Funktion.

Fall 2) Ist auch einfach zu implementieren, hier muss bei Schnellladung bei Unterschreiten des definierten BatterieSoc nur das Entladelimit auf einen Wert gesetzt werden, den der Nutzer per config.yaml/GUI vorgibt. Dies wäre mit allen Wallboxen kompatibel. Sinnvoll sind Limits, die dem normalen Hausbedarf (z.B. 500W) entsprechen. So kommt zumindest diese Leistung während der Schnellladung aus dem Hausspeicher. Wer mag, kann auch höhere Werte vorgeben, so unterstützt der Hausspeicher die Wallbox noch etwas (oder eben mehr) mit Energie. Nachteil: Wird während der Schnellladung aber z.B. Herd, Waschmaschine etc. gestartet, so kommt die Energie dafür dann auch aus dem Netz.

Fall 3) Ist vermutlich deutlich komplizierter zu implementieren. Hier muss zyklisch das Entladelimit an die Hausleistung (ohne Wallboxleistung) angepasst werden. Dies wäre mit allen Wallboxen kompatibel. Hier muss der Nutzer kein fixes Limit konfigurieren. Mit dieser Lösung würde die Energie für Herd/Waschmaschine bei Schnellladung weiterhin dynamisch aus der Hausbatterie kommen.

Fall 4) Hier muss das E3DC System entsprechend konfiguriert werden (könnte evcc durch RSCP Befehle übernehmen). Ist auch leicht zu implementieren, da nur bei Änderung des bufferSoc dieser Wert per RSCP ans E3DC System gesendet werden muss. Um die dynamische Anpassung der Entladeleistung bei Unterschreiten des bufferSoc an den Hausverbrauch kümmert sich das E3DC System. Mit dieser Lösung würde die Energie für Herd/Waschmaschine bei Schnellladung weiterhin dynamisch aus der Hausbatterie kommen. Und diese Lösung funktionert auch noch weiterhin, wenn evcc mal nicht aktiv sein sollte. Nachteil: Dies ist nur mit E3DC Wallboxen kompatibel, da das E3DC System nur von diesen die aktuelle Wallboxladeleistung lesen kann (wenn man den modbusproxy im readonly modus nutzt, aber das muss man als Besitzer eine E3DC Wallbox und evcc ohnehin).

premultiply commented 3 months ago

Es wird wenn dann Fall 5: Vollständige Entladesperre

veiter555 commented 3 months ago

Hallo,

leider habe ich keine E3DC Wallbox sondern 2 Elli Wallboxen die kann ich dem E3DC leider nicht bekannt machen. Daher kam ja meine Idee das dynamisch über EVCC für jede Wallbox zur Verfügung zu stellen.

VG Veiter

docolli commented 3 months ago

Es wird wenn dann Fall 5: Vollständige Entladesperre

Wenn ich das richtig verstanden haben, gibt es diese 3 BatteryModes: Normal / Hold / Charge.

Folgende Logik kommt zum Einsatz, um die Batterieentladung zu steuern:

{api.StatusB, false, api.BatteryNormal, api.ModeOff},   // mode off -> bat enabled
{api.StatusB, false, api.BatteryNormal, api.ModeNow},   // mode now, not charging -> bat enabled
{api.StatusC, false, api.BatteryLocked, api.ModeNow},   // mode now, charging -> bat disabled
{api.StatusB, false, api.BatteryNormal, api.ModeMinPV}, // mode minPV, not charging -> bat enabled
{api.StatusC, false, api.BatteryNormal, api.ModeMinPV}, // mode minPV, charging -> bat enabled
{api.StatusB, false, api.BatteryNormal, api.ModePV},    // mode PV, not charging -> bat enabled
{api.StatusC, false, api.BatteryNormal, api.ModePV},    // mode PV, charging, no planner -> bat enabled
{api.StatusC, true, api.BatteryLocked, api.ModePV},     // mode PV, charging, planner active -> bat disabled

Für die 3 Zustände muss noch definiert werden, welche RSCP Befehle ans E3DC System geschickt werden müssen. Ich schlage folgendes vor:

1) Normal: '[["EMS_REQ_SET_POWER_SETTINGS",[["EMS_POWER_LIMITS_USED","Bool",0]]]]' Die "0" löscht den Zustand "EMS_POWER_LIMITS_USED" und setzt ihn auf false. Somit sind keine Lade- bzw. Entladelimits mehr aktiv. Dies könnte aber Probleme bei Nutzern ergeben, die ein Ladelimit gesetzt haben wollen. Das wäre dann ebenfalls inaktiv. Vorteil ist aber, dass das E3DC System nach diesem Befehl die Limits (sowohl Lade- als auch Entladeleistung) wieder auf die Maximalwerte setzt.

2) Hold (BatteryLocked): '[["EMS_REQ_SET_POWER_SETTINGS",[["EMS_POWER_LIMITS_USED","Bool",1],["EMS_MAX_DISCHARGE_POWER","Int8",500]]]]' Dies setzt den Zustand "EMS_POWER_LIMITS_USED" auf true und limitiert die Entladeleistung auf 500W. Man könnte hier auch "0" als Wert nehmen, dann ist die Batterie komplett deaktiviert.

3) Charge: Bin mir nicht ganz sicher, aber vermutlich braucht man in evcc diesen dritten Zustand, da einige Batteriesysteme nur komplett deaktiviert werden können. In diesem Zustand werden Befehle ans Batteriesystem gesendet, die wenn die Batterie geladen werden soll, ausgeführt werden und somit den Energiefluss in die Batterie wieder freigeben. Bei E3DC kann Lade- und Entladelimit getrennt gesetzt werden. Dies geht auch übers Display am System bzw. übers Webportal/App. Somit muss Charge nicht unbedingt separat freigegeben werden. Die Ladung sollte gehen, egal ob die Batterie aus dem Zustand Normal oder Hold kommt. Man könnte aber, wie bei "Normal", die Limits komplett zurücksetzen.

Noch ein paar Infos: Beim Setzen des Befehls für Hold gibt es folgende Rückgabewerte: {"EMS_SET_POWER_SETTINGS":{"EMS_RES_POWER_LIMITS_USED":0,"EMS_RES_MAX_DISCHARGE_POWER":1}}

// returns:
    //   1 bei Erfolg, allerdings ist das limit unterhalb des empfohlenden Limits
    //   0 Werte erfolgreich gesetzt
    //  -1 Wert außerhalb des zulässigen Bereichs
    //  -2 setzen momentan nicht möglich, später erneut versuchen

Beispiele für mein System (max. 4500W):

'[["EMS_REQ_SET_POWER_SETTINGS",[["EMS_POWER_LIMITS_USED","Bool",1],["EMS_MAX_DISCHARGE_POWER","Int8",1000]]]]'
{"EMS_SET_POWER_SETTINGS":{"EMS_RES_POWER_LIMITS_USED":0,"EMS_RES_MAX_DISCHARGE_POWER":1}}

'[["EMS_REQ_SET_POWER_SETTINGS",[["EMS_POWER_LIMITS_USED","Bool",1],["EMS_MAX_DISCHARGE_POWER","Int8",2000]]]]'
{"EMS_SET_POWER_SETTINGS":{"EMS_RES_POWER_LIMITS_USED":0,"EMS_RES_MAX_DISCHARGE_POWER":0}}

'[["EMS_REQ_SET_POWER_SETTINGS",[["EMS_POWER_LIMITS_USED","Bool",1],["EMS_MAX_DISCHARGE_POWER","Int8",5000]]]]'
{"EMS_SET_POWER_SETTINGS":{"EMS_RES_POWER_LIMITS_USED":0,"EMS_RES_MAX_DISCHARGE_POWER":-1}}

1000W sieht E3DC unterhalb des empfohlenen Limits (>1000W) für mein System S10E an, 2000W sind okay, 5000W ist außerhalb des zulässigen Bereichs.

andig commented 3 months ago

Dies könnte aber Probleme bei Nutzern ergeben, die ein Ladelimit gesetzt haben wollen. Das wäre dann ebenfalls inaktiv.

Es kann nur einer steuern. Diese Anwender müssen das dann selbst machen.

Charge soll den Akku zwangs-laden. Kriegen wir das auch hin? Die Powerlimits können wir konfigurierbar machen, es braucht aber einen Defaultwert. Welchen?

andig commented 3 months ago

["EMS_MAX_DISCHARGE_POWER","Int8",500]]]]'

int8 steht nicht zur Verfügung? Und wie kann man in ein int8 eine 500 schreiben???

andig commented 3 months ago

Ansonsten wäre ich fertig bis auf https://github.com/evcc-io/evcc/issues/13403#issuecomment-2066152969

spali commented 3 months ago

["EMS_MAX_DISCHARGE_POWER","Int8",500]]]]'

int8 steht nicht zur Verfügung? Und wie kann man in ein int8 eine 500 schreiben???

Müsste nach meiner Info DataType Uint32 haben.

Ansonsten wäre ich fertig bis auf #13403 (comment)

Muss ich schauen wann ich dazu komme... hoffe gibt nicht all zu viel zum umbauen im logging.

docolli commented 3 months ago

Sorry, @spali hat natürlich (fast) Recht. Ist ein Int32

read [{ EMS_GET_POWER_SETTINGS Container 
[
{ EMS_POWER_LIMITS_USED Bool false } 
{ EMS_MAX_CHARGE_POWER Int32 4500 } 
{ EMS_MAX_DISCHARGE_POWER Int32 4500 } 
{ EMS_DISCHARGE_START_POWER Uint32 65 } 
{ EMS_POWERSAVE_ENABLED Bool true } 
{ EMS_WEATHER_REGULATED_CHARGE_ENABLED Bool false } 
{ EMS_WEATHER_FORECAST_MODE Int32 0 }
] 
}]

Charge soll den Akku zwangs-laden. Kriegen wir das auch hin? Die Powerlimits können wir konfigurierbar machen, es braucht aber einen Defaultwert. Welchen?

Ja, man kann den E3DC auch Zwangsbeladen. Über das Portal geht das wohl, habe ich aber noch nie benutzt. grafik Vielleicht hat Thomas ja Erfahrung und kann uns kurz mit Befehlen helfen, sonst mach ich mich auf die Suche. Wie ist die Zwangsbeladung aktuell in evcc gelöst? Gibt es dazu eine Doku oder eine Diskussion?

Konfigurierbare Powerlimits wären toll! Ich denke 500W wären ein guter Defaultwert fürs Entladelimit. Das ist so grob der Bedarf meines Hauses und den Wert habe ich schon bei anderen als Wert in Diskussionen zum Entladelimit bei Wallboxladung gelesen. Hängt aber auch von der Batteriekapazität ab. Bei meinen 13kWh sind das 26h, welche die Batterie damit bis zur vollständigen Entladung brauchen würde. Also so grob 1/24 der Batteriekapazität. Ich bin der Meinung dass dies der User selber setzen soll, ein Limit von 1000W könnte auch Sinn machen, so würde die Hausbatterie im Mittel die Wallbox mit 500W "unterstützen". Das soll jeder selber nach seinem Ziel zur Nutzung der Hausbatterie einstellen.

spali commented 3 months ago

Zwangsladen hatte ich mal benutzt: EMS_REQ_START_MANUAL_CHARGE mit Typ Uint32. Werte > 0 starten die Zwangsladung und Wert 0 Stop die aktive Zwangsladung, wenn ich mich recht erinnere. Ich mag mich so halbwegs erinnern... das ich das sogar mehrere Stunden aufrecht erhalten konnte... sprich wiederholt mit 4500Wh jeweils 1h lang über nach die Batterie gefüllt hatte. Da ich es aktuell nicht mehr verwende, weiss ich leider nicht mehr wie diese 1/24h limite genau umgesetzt ist.... war ehrlich gesagt auch nicht immer nach zu vollziehen....

docolli commented 3 months ago

Danke! Habs mal getestet, auch wenn meine Batterie aktuell 100% voll ist.

Erstmal Werte abfragen... Da ich das noch nie genutzt habe, sind das die Default Werte:

./e3dc -debug 6 '[["EMS_REQ_GET_MANUAL_CHARGE","None","Nil"]]' | jq
INFO[0000] Connecting to 192.168.1.121:5033
INFO[0000] successfully connected to 192.168.1.121:5033
INFO[0000] hiding auth request for security, use debug >= 99 to debug authentication
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0x5c, 0x7e, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0x80, 0xc8, 0x83, 0x10, 0x8, 0x0, 0x1, 0x0, 0x80, 0x0, 0x3, 0x1, 0x0, 0xa, 0x30, 0xb, 0x57, 0x1d}
TRAC[0000] read [{ RSCP_AUTHENTICATION UChar8 10 }]
INFO[0000] successfully authenticated (level: AUTH_LEVEL_USER)
DEBU[0000] write [{ EMS_REQ_GET_MANUAL_CHARGE None <nil> }]
TRAC[0000] write plain []byte{0xe3, 0xdc, 0x0, 0x11, 0x1a, 0x75, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0x7b, 0x3c, 0x8b, 0x28, 0x7, 0x0, 0x8e, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x84, 0xea, 0x4, 0x17}
TRAC[0000] write crypt []byte{0xef, 0x9b, 0x85, 0x92, 0xa8, 0xaf, 0x15, 0xaf, 0x5a, 0x5, 0x32, 0xe4, 0x1f, 0xbb, 0x90, 0xd2, 0x7f, 0x47, 0x2c, 0x73, 0x38, 0x49, 0x50, 0xdf, 0xdb, 0xc9, 0xbf, 0x6a, 0x73, 0xad, 0x38, 0x71}
WARN[0000] unknown tag 0x0100003e received
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0x5c, 0x7e, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0xd8, 0x8b, 0xe5, 0x10, 0x4b, 0x0, 0x8e, 0x0, 0x80, 0x1, 0xe, 0x44, 0x0, 0x51, 0x1, 0x0, 0x1, 0x1, 0x1, 0x0, 0x0, 0x50, 0x1, 0x0, 0x1, 0x8, 0x8, 0x0, 0x9, 0xac, 0x1c, 0x5a, 0x64, 0x3b, 0xdf, 0xff, 0x52, 0x1, 0x0, 0x1, 0xb, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x53, 0x1, 0x0, 0x1, 0xf, 0xc, 0x0, 0xa, 0xa5, 0x2f, 0x84, 0x9c, 0xf7, 0xff, 0xff, 0x0, 0x1c, 0xc2, 0xd1, 0x3e, 0x0, 0x0, 0x1, 0x7, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb9, 0x99, 0xa9, 0xa7}
TRAC[0000] read [{ EMS_GET_MANUAL_CHARGE Container [{ EMS_MANUAL_CHARGE_ACTIVE Bool false } { EMS_MANUAL_CHARGE_START_COUNTER Int64 -9223372036854775 } { EMS_MANUAL_CHARGE_ENERGY_COUNTER Double64 0 } { EMS_MANUAL_CHARGE_LASTSTART Timestamp -290308-12-21 19:59:05.224192 +0000 UTC } { Tag(16777278) Uint32 0 }] }]
INFO[0000] disconnected
{
  "EMS_GET_MANUAL_CHARGE": {
    "16777278": 0,
    "EMS_MANUAL_CHARGE_START_COUNTER": -9223372036854775,
    "EMS_MANUAL_CHARGE_ACTIVE": false,
    "EMS_MANUAL_CHARGE_ENERGY_COUNTER": 0,
    "EMS_MANUAL_CHARGE_LASTSTART": "1970-01-01T00:00:00Z"
  }
}

Dann probier ich trotzdem mal eine Ladung mit 1000 (W / Wh ???):

./e3dc -debug 6 '[["EMS_REQ_START_MANUAL_CHARGE","UInt32",1000]]' | jq
INFO[0000] Connecting to 192.168.1.121:5033
INFO[0000] successfully connected to 192.168.1.121:5033
INFO[0000] hiding auth request for security, use debug >= 99 to debug authentication
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0xe5, 0x80, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0xc0, 0x75, 0xf0, 0x1, 0x8, 0x0, 0x1, 0x0, 0x80, 0x0, 0x3, 0x1, 0x0, 0xa, 0xd3, 0x2c, 0x22, 0x89}
TRAC[0000] read [{ RSCP_AUTHENTICATION UChar8 10 }]
INFO[0000] successfully authenticated (level: AUTH_LEVEL_USER)
DEBU[0000] write [{ EMS_REQ_START_MANUAL_CHARGE Uint32 1000 }]
TRAC[0000] write plain []byte{0xe3, 0xdc, 0x0, 0x11, 0xa3, 0x77, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0xe9, 0x4a, 0xd, 0x19, 0xb, 0x0, 0x8f, 0x0, 0x0, 0x1, 0x7, 0x4, 0x0, 0xe8, 0x3, 0x0, 0x0, 0x7b, 0x28, 0x20, 0xae}
TRAC[0000] write crypt []byte{0x22, 0x38, 0xd, 0xd0, 0x94, 0x59, 0x36, 0x2f, 0xf5, 0x19, 0xf1, 0xf, 0xa9, 0xe1, 0x7, 0xea, 0x5d, 0x47, 0xf5, 0xdf, 0xdd, 0x7f, 0x74, 0xb5, 0xb, 0x23, 0xfd, 0x66, 0xd8, 0x50, 0x21, 0x50, 0x2b, 0x12, 0xc3, 0x39, 0x80, 0x9c, 0x8a, 0xef, 0xf, 0x30, 0xd4, 0x9f, 0xa5, 0x81, 0x5e, 0xd9, 0x1e, 0xc3, 0x7c, 0xd5, 0xb7, 0xbb, 0xda, 0xbd, 0xf2, 0x8, 0x7e, 0x53, 0xd2, 0xd1, 0xf6, 0xa0}
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0xe5, 0x80, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0x78, 0xf3, 0x5a, 0x2, 0x8, 0x0, 0x8f, 0x0, 0x80, 0x1, 0x1, 0x1, 0x0, 0x1, 0x5a, 0xf6, 0x78, 0xdf}
TRAC[0000] read [{ EMS_START_MANUAL_CHARGE Bool true }]
INFO[0000] disconnected
{
  "EMS_START_MANUAL_CHARGE": true
}

Auch wenn meine Batterie zu 100% voll war, habe ich damit meine 1x Laden in 24h Karte verspielt 🙈: grafik Hier die Werte wieder ausgelesen. Es gibt einen UNKNOWN TAG 16777278, der hat aber jetzt den Wert bekommen, den ich gesendet habe. Infos dazu finden sich nicht im Netz, mal sehen, was ich raus bekomme. Wenn es eine Energiemenge ist (wie im Portal anzugeben), dann könnte das die Restmenge sein. Werde ich sehen, wenn ich mal manuell laden kann.

./e3dc -debug 6 '[["EMS_REQ_GET_MANUAL_CHARGE","None","Nil"]]' | jq
INFO[0000] Connecting to 192.168.1.121:5033
INFO[0000] successfully connected to 192.168.1.121:5033
INFO[0000] hiding auth request for security, use debug >= 99 to debug authentication
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0x38, 0x81, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0x48, 0xb, 0xa, 0x16, 0x8, 0x0, 0x1, 0x0, 0x80, 0x0, 0x3, 0x1, 0x0, 0xa, 0x19, 0x0, 0x29, 0x11}
TRAC[0000] read [{ RSCP_AUTHENTICATION UChar8 10 }]
INFO[0000] successfully authenticated (level: AUTH_LEVEL_USER)
DEBU[0000] write [{ EMS_REQ_GET_MANUAL_CHARGE None <nil> }]
TRAC[0000] write plain []byte{0xe3, 0xdc, 0x0, 0x11, 0xf6, 0x77, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0x50, 0x1e, 0x3, 0x2d, 0x7, 0x0, 0x8e, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xe0, 0xca, 0xed, 0x30}
TRAC[0000] write crypt []byte{0x85, 0x22, 0x49, 0x8b, 0xb2, 0xce, 0x8a, 0x4f, 0x35, 0x34, 0xd3, 0x69, 0x38, 0x89, 0x45, 0x2e, 0xf1, 0xf6, 0xb1, 0xec, 0x13, 0x23, 0x5d, 0x55, 0x3, 0x55, 0xf7, 0x3c, 0x84, 0x91, 0x4, 0xc}
WARN[0000] unknown tag 0x0100003e received
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0x38, 0x81, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0x60, 0xc7, 0x67, 0x16, 0x4b, 0x0, 0x8e, 0x0, 0x80, 0x1, 0xe, 0x44, 0x0, 0x51, 0x1, 0x0, 0x1, 0x1, 0x1, 0x0, 0x0, 0x50, 0x1, 0x0, 0x1, 0x8, 0x8, 0x0, 0xaf, 0x7e, 0x67, 0x6, 0x8f, 0x1, 0x0, 0x0, 0x52, 0x1, 0x0, 0x1, 0xb, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x53, 0x1, 0x0, 0x1, 0xf, 0xc, 0x0, 0xe5, 0x80, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0xa8, 0xfd, 0x57, 0x2, 0x3e, 0x0, 0x0, 0x1, 0x7, 0x4, 0x0, 0xe8, 0x3, 0x0, 0x0, 0x7f, 0xb6, 0xc4, 0x66}
TRAC[0000] read [{ EMS_GET_MANUAL_CHARGE Container [{ EMS_MANUAL_CHARGE_ACTIVE Bool false } { EMS_MANUAL_CHARGE_START_COUNTER Int64 1713799397039 } { EMS_MANUAL_CHARGE_ENERGY_COUNTER Double64 0 } { EMS_MANUAL_CHARGE_LASTSTART Timestamp 2024-04-22 15:23:17.039321 +0000 UTC } { Tag(16777278) Uint32 1000 }] }]
INFO[0000] disconnected
{
  "EMS_GET_MANUAL_CHARGE": {
    "16777278": 1000,
    "EMS_MANUAL_CHARGE_START_COUNTER": 1713799397039,
    "EMS_MANUAL_CHARGE_ACTIVE": false,
    "EMS_MANUAL_CHARGE_ENERGY_COUNTER": 0,
    "EMS_MANUAL_CHARGE_LASTSTART": "2024-04-22T15:23:17.039321Z"
  }
}

Dann versuche ich nochmals zu laden, obwohl das Laden jetzt für 24h gesperrt ist:

./e3dc -debug 6 '[["EMS_REQ_START_MANUAL_CHARGE","UInt32",1000]]' | jq
INFO[0000] Connecting to 192.168.1.121:5033
INFO[0000] successfully connected to 192.168.1.121:5033
INFO[0000] hiding auth request for security, use debug >= 99 to debug authentication
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0x93, 0x81, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0x80, 0xea, 0x24, 0x11, 0x8, 0x0, 0x1, 0x0, 0x80, 0x0, 0x3, 0x1, 0x0, 0xa, 0xd9, 0x65, 0xc7, 0xc}
TRAC[0000] read [{ RSCP_AUTHENTICATION UChar8 10 }]
INFO[0000] successfully authenticated (level: AUTH_LEVEL_USER)
DEBU[0000] write [{ EMS_REQ_START_MANUAL_CHARGE Uint32 1000 }]
TRAC[0000] write plain []byte{0xe3, 0xdc, 0x0, 0x11, 0x51, 0x78, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0xff, 0x8a, 0xfd, 0x27, 0xb, 0x0, 0x8f, 0x0, 0x0, 0x1, 0x7, 0x4, 0x0, 0xe8, 0x3, 0x0, 0x0, 0x4f, 0xc8, 0x1d, 0xc9}
TRAC[0000] write crypt []byte{0xdc, 0xa2, 0x21, 0x43, 0x2f, 0x72, 0xe7, 0x1, 0xc3, 0x90, 0x76, 0xf9, 0xa0, 0xd2, 0xe0, 0xb0, 0x19, 0x65, 0x78, 0xf, 0x5, 0x8, 0x7, 0x8c, 0xa4, 0xb, 0xe4, 0xba, 0x8c, 0x5e, 0x71, 0x73, 0x8a, 0x32, 0x8a, 0x12, 0x1d, 0xb8, 0x81, 0x53, 0xeb, 0x14, 0xc6, 0x61, 0x34, 0xa8, 0x4c, 0x7, 0x59, 0xef, 0x5, 0x65, 0xe9, 0xd4, 0xc9, 0xe7, 0x78, 0x7b, 0x53, 0x3d, 0x2c, 0x22, 0x22, 0x4a}
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0x93, 0x81, 0x26, 0x66, 0x0, 0x0, 0x0, 0x0, 0x60, 0xb5, 0x88, 0x11, 0x8, 0x0, 0x8f, 0x0, 0x80, 0x1, 0x1, 0x1, 0x0, 0x0, 0x2, 0x81, 0x62, 0x61}
TRAC[0000] read [{ EMS_START_MANUAL_CHARGE Bool false }]
INFO[0000] disconnected
{
  "EMS_START_MANUAL_CHARGE": false
}

Nun bekommen ich ein false zurück.

docolli commented 3 months ago

@andig Neue Erkenntnisse zum manuellen Laden.

Ich habe den Akku auf 80% entladen und dann die Ladung gestartet;

./e3dc -debug 6 '[["EMS_REQ_START_MANUAL_CHARGE","UInt32",1000]]' | jq
INFO[0000] Connecting to 192.168.1.121:5033
INFO[0000] successfully connected to 192.168.1.121:5033
INFO[0000] hiding auth request for security, use debug >= 99 to debug authentication
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0xca, 0xd9, 0x27, 0x66, 0x0, 0x0, 0x0, 0x0, 0x40, 0x94, 0x82, 0x30, 0x8, 0x0, 0x1, 0x0, 0x80, 0x0, 0x3, 0x1, 0x0, 0xa, 0x7a, 0xa, 0x84, 0x6c}
TRAC[0000] read [{ RSCP_AUTHENTICATION UChar8 10 }]
INFO[0000] successfully authenticated (level: AUTH_LEVEL_USER)
DEBU[0000] write [{ EMS_REQ_START_MANUAL_CHARGE Uint32 1000 }]
TRAC[0000] write plain []byte{0xe3, 0xdc, 0x0, 0x11, 0x89, 0xd0, 0x27, 0x66, 0x0, 0x0, 0x0, 0x0, 0x9d, 0x78, 0x6a, 0x23, 0xb, 0x0, 0x8f, 0x0, 0x0, 0x1, 0x7, 0x4, 0x0, 0xe8, 0x3, 0x0, 0x0, 0x14, 0x58, 0xbd, 0x7a}
TRAC[0000] write crypt []byte{0x99, 0x98, 0x8a, 0x7f, 0x61, 0x31, 0xc5, 0x96, 0x52, 0x44, 0xea, 0xd0, 0x79, 0x42, 0x7e, 0x9b, 0xd, 0x2d, 0xa5, 0x9a, 0xa4, 0xd8, 0x93, 0x5f, 0x35, 0xfe, 0xc5, 0x90, 0x7d, 0x1, 0xd7, 0x74, 0x83, 0x4b, 0x55, 0xc6, 0xaa, 0xb0, 0x9a, 0x6b, 0x1c, 0xc7, 0x4b, 0x40, 0xa6, 0x34, 0x79, 0xfa, 0xc5, 0xe5, 0x5d, 0xd6, 0xa4, 0xf8, 0x43, 0x6c, 0x3c, 0x74, 0xe6, 0xd0, 0x94, 0xa2, 0xf7, 0xf1}
TRAC[0000] read plain []byte{0xe3, 0xdc, 0x0, 0x11, 0xca, 0xd9, 0x27, 0x66, 0x0, 0x0, 0x0, 0x0, 0x78, 0x78, 0x10, 0x31, 0x8, 0x0, 0x8f, 0x0, 0x80, 0x1, 0x1, 0x1, 0x0, 0x1, 0x52, 0x7a, 0x48, 0xc7}
TRAC[0000] read [{ EMS_START_MANUAL_CHARGE Bool true }]
INFO[0000] disconnected
{
  "EMS_START_MANUAL_CHARGE": true
}

Ich übergebe einen Wert als UInt32 und man bekommt als Antwort EMS_START_MANUAL_CHARGE mit einem Bool als Wert. Zum Testen habe ich "1000" übergeben, dann wurde die Ladung gestartet. Die Batterie wurde mit 4,5kW (kein Ladelimit gesetzt) geladen.

Um zu sehen, was passiert, habe ich den Container "EMS_REQ_GET_MANUAL_CHARGE" abgefragt. Antwort:

[{ EMS_GET_MANUAL_CHARGE Container 
[
{ EMS_MANUAL_CHARGE_ACTIVE Bool true } 
{ EMS_MANUAL_CHARGE_START_COUNTER Int64 1713887690823 } 
{ EMS_MANUAL_CHARGE_ENERGY_COUNTER Double64 146.51342583333357 } 
{ EMS_MANUAL_CHARGE_LASTSTART Timestamp 2024-04-23 15:54:50.823046 +0000 UTC } 
{ Tag(16777278) Uint32 1000 }
] 
}]`

CHARGE_ACTIVE wurde true und EMS_MANUAL_CHARGE_ENERGY_COUNTER stieg inkrementell an. Das wird die geladene Leistung in Wh sein. Geladen wurde bis dieser Wert 1000 erreicht hat, dann hat die Ladung automatisch geendet.

[{  "EMS_GET_MANUAL_CHARGE": {
    "16777278": 1000,
    "EMS_MANUAL_CHARGE_START_COUNTER": 1713887690823,
    "EMS_MANUAL_CHARGE_ACTIVE": false,
    "EMS_MANUAL_CHARGE_ENERGY_COUNTER": 1000.1322958333304,
    "EMS_MANUAL_CHARGE_LASTSTART": "2024-04-23T15:54:50.823044Z"
  }
}

Somit wird der Befehl EMS_REQ_START_MANUAL_CHARGE sehr wahrscheinlich die zu ladende Energiemenge in Wh als Wert nehmen und das E3DC System lädt dann selbstständig die gewünschte Energiemenge.

Genügt das, oder brauchst du auch noch Befehle, um eine laufende Ladung unterbrechen zu können? Aber Achtung, eine Ladung ist erst wieder nach EMS_MANUAL_CHARGE_LASTSTART plus 24h möglich.

andig commented 3 months ago

Muss das bei normal/hold resettet werden? Wie- einfach auf 0 stellen?

docolli commented 3 months ago

Wann läuft denn evcc in Charge rein? Wann löst evcc eine Ladung der Hausbatterie aus? Ich verstehe den Sinn des Zustands noch nicht so ganz.

andig commented 3 months ago

Spielt doch für die Frage keine Rolle? Aktuell nur über die Kommandozeile oder wenn Du mit https://github.com/evcc-io/evcc/pull/10814 spielen willst.

docolli commented 3 months ago

Ich möchte schon einigermaßen verstehen was das Ziel ist, dann kann ich versuchen spezifischere Infos zu geben. 😉

Zurück zu deiner Frage mit Reset des Zustands: Wenn eine Sperre gesetzt ist, so sind sowohl die Lade- als auch die Entladeleistung limitiert. Da wir bei "Hold" nur die Entladeleistung auf einen fixen Wert setzen und bei "Normal" mit dem Entsperrbefehl deaktivieren, sollte das Ladelimit immer auf dem maximal möglichen Wert stehen. Also kann das E3DC System auch bei aktivierter Entladeleistungslimitierung mit maximaler Leistung laden. Also wenn die Batterie gerade geladen wird und wir setzen durch Hold ein Entladelimit, sollte das keine Auswirkungen haben. Auch wenn die Batterie während der Ladung in den Modus Normal reinläuft, hat der Reset der Limits sehr wahrscheinliche keine Auswirkung aufs Laden.

andig commented 3 months ago

Ich verstehe nur Bahnhof. Sichergestellt sein muss, dass bei Charge -> Normal das Zwangsladen beendet wird. Wäre vllt. gut das zu testen ;)

docolli commented 3 months ago

Ja sorry, habs ja selber kaum verstanden mit Ladelimit / Entladelimit usw. und wann welches Limit aktiv ist und wieder auf den Default Wert vom System gesetzt wird... 😂

Ich schau mal, wie ich das Zwangsladen bei E3DC unterbrechen kann. Geht aber erst morgen Abend wieder, für heute darf ich keine Ladung mehr starten.

docolli commented 3 months ago

Testung Unterbrechung der manuellen Ladung.

  1. Setzen von Limits, Entladen -> 500W, Laden -> 750W

    ./e3dc '[["EMS_REQ_SET_POWER_SETTINGS",[["EMS_POWER_LIMITS_USED","Bool",1],["EMS_MAX_DISCHARGE_POWER","Int8",500],["EMS_MAX_CHARGE_POWER","Int8",750]]]]'
    {"EMS_SET_POWER_SETTINGS":{"EMS_RES_POWER_LIMITS_USED":0,"EMS_RES_MAX_CHARGE_POWER":1,"EMS_RES_MAX_DISCHARGE_POWER":1}}
  2. Abfrage der gesetzen Werte (zur Kontrolle)

    ./e3dc '[["EMS_REQ_GET_POWER_SETTINGS","None","Nil"]]' | jq
    {
    "EMS_GET_POWER_SETTINGS": {
    "EMS_POWER_LIMITS_USED": true,
    "EMS_MAX_CHARGE_POWER": 750,
    "EMS_MAX_DISCHARGE_POWER": 500,
    "EMS_DISCHARGE_START_POWER": 65,
    "EMS_POWERSAVE_ENABLED": true,
    "EMS_WEATHER_REGULATED_CHARGE_ENABLED": false,
    "EMS_WEATHER_FORECAST_MODE": 0
    }
    }
  3. Start manuelle Ladung von 1000Wh (Mein System erlaubt laut Web Portal 0 bis 4500Wh)

    ./e3dc '[["EMS_REQ_START_MANUAL_CHARGE","UInt32",1000]]' | jq
    {
    "EMS_START_MANUAL_CHARGE": true
    }

    -> Es wird geladen mit ~750W.

  4. Abfrage der Werte (zur Kontrolle)

    ./e3dc '[["EMS_REQ_GET_MANUAL_CHARGE","None","Nil"]]' | jq
    {
    "EMS_GET_MANUAL_CHARGE": {
    "16777278": 1000,
    "EMS_MANUAL_CHARGE_START_COUNTER": 1713979605597,
    "EMS_MANUAL_CHARGE_ACTIVE": true,
    "EMS_MANUAL_CHARGE_ENERGY_COUNTER": 0.1222253535,
    "EMS_MANUAL_CHARGE_LASTSTART": "2024-04-24T17:26:45.597996Z"
    }
    }

    -> Der Tag 16777278 gibt die manuell zu ladende Energiemenge in Wh an, der Tag EMS_MANUAL_CHARGE_ENERGY_COUNTER hat wieder bei 0 angefangen und gibt somit die aktuell manuell geladene Energiemenge an.

  5. Versuch des Abbruchs der manuellen Ladung durch Senden von "0"

    ./e3dc '[["EMS_REQ_START_MANUAL_CHARGE","UInt32",0]]' | jq
    {
    "EMS_START_MANUAL_CHARGE": true
    }
  6. Ladung wurden unterbrochen!

    ./e3dc '[["EMS_REQ_GET_MANUAL_CHARGE","None","Nil"]]' | jq
    {
    "EMS_GET_MANUAL_CHARGE": {
    "16777278": 0,
    "EMS_MANUAL_CHARGE_START_COUNTER": 1713979605597,
    "EMS_MANUAL_CHARGE_ACTIVE": false,
    "EMS_MANUAL_CHARGE_ENERGY_COUNTER": 8.225446666666663,
    "EMS_MANUAL_CHARGE_LASTSTART": "2024-04-24T17:26:45.597996Z"
    }
    }
  7. Weitere Ladung ist nun nicht mehr möglich, das "1x in 24h" Laden ist wieder aufgebraucht. Morgen wieder...

 ./e3dc '[["EMS_REQ_START_MANUAL_CHARGE","UInt32",500]]' | jq
{
  "EMS_START_MANUAL_CHARGE": false
}

PS: Das Entladelimit von 500W greift auch: grafik

PPS: den Tag 16777278 würde ich "EMS_MANUAL_CHARGE_ENERGY" benennen, aber ich bin nicht E3DC😉

andig commented 3 months ago

Supi. Also müssen wir bei Normal/Hold zusätzlich [["EMS_REQ_START_MANUAL_CHARGE","UInt32",0]] senden, ggf. nachdem wir den Bedarf vorher über [["EMS_REQ_GET_MANUAL_CHARGE","None","Nil"]] abgefragt haben. Ich würde erstmal versuchen, das pauschal zu schicken.

spali commented 3 months ago

Supi. Also müssen wir bei Normal/Hold zusätzlich [["EMS_REQ_START_MANUAL_CHARGE","UInt32",0]] senden, ggf. nachdem wir den Bedarf vorher über [["EMS_REQ_GET_MANUAL_CHARGE","None","Nil"]] abgefragt haben. Ich würde erstmal versuchen, das pauschal zu schicken.

Achtung "Nil" heisst für dich in dem Fall nil. Da hat @docolli json, json string und go nil ein wenig durcheinander gebracht. PS: DateType: rscp.None ignoriert die Value... von dem her funktionierts trotzdem, sollte aber bei dem Datentyp immer nil sein. Bzw. für @docolli null in json.

Und wenn wir schon dabei sind... zumindestens nach meinen Tests (siehe Kommentar):

    EMS_MAX_CHARGE_POWER:                     Uint32, // documented as Int32, but requires Uint32
    EMS_MAX_DISCHARGE_POWER:                  Uint32, // documented as Int32, but requires Uint32

E3DC frisst es zu mindestens in meinem Fall nur mit Uint32 auch wenn die Antwort wieder rum ein Int32 ist.... Würde auch erklären wieso @docolli bei seinen Tests kein Erfolg hatte.

andig commented 3 months ago

BatteryCharge ist jetzt auch drin und könnte mittels

evcc meter --help

getestet werden. Die Werte werden jetzt einfach immer gesetzt und nicht abgefragt.

spali commented 3 months ago

@andig @docolli

PPS: den Tag 16777278 würde ich "EMS_MANUAL_CHARGE_ENERGY" benennen, aber ich bin nicht E3DC😉

v0.2.0-beta5 kenn nun auch diesen Tag mit deinem Namen. Datentyp spuckt meiner Uint32 zurück, habe ich ensprechend eingetragen: https://github.com/spali/go-rscp/blob/9ee4bc6c03c13167b1f0eb30e9ffc5c009346285/rscp/tag_datatype.go#L104

docolli commented 3 months ago

Die Powerlimits können wir konfigurierbar machen, es braucht aber einen Defaultwert. Welchen?

Nachdem die E3DC RSCP Implementation endlich läuft und wir die Batterieentladung kontrollieren können (aktuell setzt du die auf 0), möchte ich hierauf wieder zurück kommen. Können wir die Powerlimits konfigurierbar machen? 😉😎

andig commented 3 months ago

Welche Limits willst du denn konfigurieren? Es wird doch gar keins verwendet?!

docolli commented 3 months ago

Das Entladelimit wird auf 0W gesetzt, das könnte man z. B. auch auf 500W setzen, so würde die Batterie weiterhin entladen werden und so den mittleren Hausverbrauch unterstützen. So könnte man erreichen, dass die Batterie am nächsten Morgen ziemlich leer ist und wieder genügend PV Überschuss aufnehmen kann.

veiter555 commented 3 months ago

Geht das auch, dass das Entladelimit dynamisch angepasst wird? Auf (Haushaltsverbrauch - PV Leistung) natürlich nur während ein Fahrzeug geladen wird und das alle 20 - 60 sec. anzupassen? (Dann wird quasi die Wallboxladung mit einer gewissen Unschärfe ausgeblendet bei der Batterieentladung. Das wäre aber absolut akzeptabel. PS: geht ja nicht um jedes Elektron sondern am Ende um kWh 😉

andig commented 3 months ago

Was ist der Unterschied zwischen gutem und schlechtem Strom? Warum braucht die Batteriesteuerung wenn man so ein Enladelimit such einfach fix extern setzen könnte? Ich denke nicht, dass wir das tun wollen.

veiter555 commented 3 months ago

Es gibt 2 Gründe dafür:

  1. die Hausbatterie soll durch das Fahrzeug nicht zusätzlich belastet werden und dadurch schneller altern da das Fahrzeug in jedem Fall beim Schnell Laden die maximale Entladeleistung anfordert bis auf 0% SOC
  2. Fleet Customer mit Ladeabrechnung über Fleetmanager. Da soll die PV Energy für den Haushalt zur Verfügung stehen und nicht für den Fleetmanager

Ich hoffe die Use Case Erläuterung verdeutlicht den Anwendungsfall etwas besser bzgl. Trennung zwischen Lade Energiemenge und Haushaltsverbrauch. Es geht hier also nicht um grüne und schwarze Elektronen sondern um Energiemengen und wie die abgerechnet werden.

andig commented 3 months ago

Ich habs nicht verstanden. Da da saber auch nix mit e3dc zu tun hat gerne neues Issue dazu.

veiter555 commented 3 months ago

@andig genau das war die initiale Idee E3DC beim Laden des Fahrzeugs zu sperren, dass die Batterie nicht durch das Fahrzeug entladen wird.

Eine Einstellung der maximalen Entladeleistung E3DC (Hausverbrauch minus PV Erzeugung) und dynamische Nachführung alle 30sec. Würde genau das sicher stellen.

Also keine neue Idee sonder nur Konkretisierung des Kundennutzens.

Ihr habt da die letzten beiden Wochen einen echt super job gemacht und mit dem was ich gelesen habe ist es denk ich möglich das so umsetzen zu können.

Vielen Dank Euch allen!

docolli commented 3 months ago

Ich denke hier ist in evcc einfach für versch. Batteriesysteme der "kleinste gemeinsame Nenner" implementiert worden und das ist die Entladesperre. Vermutlich bieten einige Systeme nur an per true/false diese zu setzen, ein Entladelimit ist nicht vorgesehen. Um konsistent zu bleiben, muss unser E3DC sich dieser Implementierung beugen, auch wenn es an dieser Stelle mehr Funktionalität bieten würde. Wenn, dann müsste man ein Entladelimit für alle Batteriesysteme implementieren, so wäre auch die Doku zu neuen Parametern konsistent und müsste nicht unterscheiden für welches Batteriesystem welche Parameter möglich sind und was sie bedeuten. Das erhöht die Einsteigshürde für evcc enorm und bedeutet dann auch mehr Supportaufwand. Ein dynamisches Entladelimit, das sich am aktuellen Hausverbrauch orientiert ist natürlich cool und ich verstehe den Anwendungsfall. Aber das muss fürs E3DC System nicht in evcc implementiert werden, das kann das HKW bereits von sich aus! Siehe ganz oben einen meiner ersten Posts. Einzig eine Synchronisation von bufferSoc und EMS_REQ_SET_WB_DISCHARGE_BAT_UNTIL wäre hier noch das i-Tüpfelchen:

./e3dc '[["EMS_REQ_SET_WB_DISCHARGE_BAT_UNTIL","Int32",80]]' | jq
{
  "EMS_SET_WB_DISCHARGE_BAT_UNTIL": true
}

./e3dc '[["EMS_REQ_GET_WB_DISCHARGE_BAT_UNTIL","None","Nil"]]' | jq
{
  "EMS_GET_WB_DISCHARGE_BAT_UNTIL": 80
}

Aber dass kann man, wenn man mag, auch über eine externe Lösung implementieren.

Als Kompromiss, würde ich vorschlagen, dass man bei BatteryHold das Entladelimit nicht fix im Code auf "0" setzt, sondern einen Parameter einführt, über den der Nutzer vorgeben kann, wieviel Leistung die Batterie bei einem WB Ladevorgang (wenn die Batterie von evcc gesperrt wird) noch abgeben darf. Gerne darf der Default-Wert hier "0" sein, dann haben wir die Entladesperre wie bei anderen Systemen, wenn der Nutzer den Parameter nicht konfiguriert hat.

docolli commented 3 months ago

Ziehe ich meine reine "evcc User mit E3DC System und E3DC Wallbox" Brille auf und denke nicht an andere Batteriesysteme, würde ich in e3dc.go bei BatteryHold folgende Befehle ans E3DC System schicken, damit es in den dynamischen Entladelimitmodus wechselt und bis bufferSoc der E3DC Wallbox maximale Leistung aus der Batterie liefert, danach nur noch den aktuellen Hausverbrauch.

 ./e3dc '[["EMS_REQ_SET_BATTERY_BEFORE_CAR_MODE","UInt8",0]]' | jq
{
  "EMS_SET_BATTERY_BEFORE_CAR_MODE": 0
}

 ./e3dc '[["EMS_REQ_SET_BATTERY_TO_CAR_MODE","UInt8",1]]' | jq
{
  "EMS_SET_BATTERY_TO_CAR_MODE": 1
}

 ./e3dc '[["EMS_REQ_SET_WALLBOX_ENFORCE_POWER_ASSIGNMENT","Bool",true]]' | jq
{
  "EMS_SET_WALLBOX_ENFORCE_POWER_ASSIGNMENT": true
}

./e3dc '[["EMS_REQ_SET_WB_DISCHARGE_BAT_UNTIL","UChar8",80]]' | jq
{
  "EMS_SET_WB_DISCHARGE_BAT_UNTIL": true
}

Aber das kann sich jeder E3DC User selbst im HKW so einrichten und die Entladesperre in evcc einfach nicht aktivieren. So werde ich es bei mir halten, auch wenn ich gerne hier bei der Implementierung der Entladesperre mithelfe. 😉

@veiter555 Edit: Aber dann MUSS die Wallbox über den evcc Modbusproxy eingebunden werden. Man könnte das wiederum von evcc aus prüfen, aber um die IP-Adresse der Wallbox im HKW abzufragen benötigt man wieder den Index der Wallbox im RSCP Universum, welches der User konfigurieren muss.... Ach es wird dann einfach zu kompliziert. 🙈 Sorry... Das kann und sollte der User selber nach Anleitung konfigurieren, wenn bei ihm die Voraussetzungen passen bzw. eingerichtet sind. Das ist dann was für die Doku, aber nicht für den Code.

Ein konfigurierbares Entladelimit ist hier das Beste, was mit vertretbarem Aufwand erreichbar ist.

veiter555 commented 2 months ago

Vielen Danke Euch, dass ist nachvollziehbar. Vielen Dank für die Implementierung der Entladesperre, dass hilft sehr viel.

VG Veiter