From dbfce599a7c359e8bad87c237143db5ab2e8b855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20He=C3=9F?= Date: Wed, 11 Sep 2024 10:52:52 +0200 Subject: [PATCH 001/116] chore: fix linter (#16026) --- vehicle/saic/api.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/vehicle/saic/api.go b/vehicle/saic/api.go index 1a8aff2506..4a04f561da 100644 --- a/vehicle/saic/api.go +++ b/vehicle/saic/api.go @@ -135,14 +135,12 @@ func (v *API) DoRequest(req *http.Request, result *requests.Answer) (string, err if result.Code == 4 { err = api.ErrMustRetry } else { - err = fmt.Errorf("%d: %s\n", result.Code, result.Message) + err = fmt.Errorf("%d: %s", result.Code, result.Message) } - v.Logger.DEBUG.Printf("%d: %s\n", result.Code, result.Message) + v.Logger.DEBUG.Printf("%d: %s", result.Code, result.Message) } } else { - if err != nil { - v.Logger.DEBUG.Printf("Decrypt: %s", err.Error()) - } + v.Logger.DEBUG.Printf("decrypt: %s", err.Error()) } } From fd586a3082062ef0009f7425a2753b648fd44635 Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 11 Sep 2024 16:05:27 +0200 Subject: [PATCH 002/116] Renault: fix climater --- vehicle/renault/provider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vehicle/renault/provider.go b/vehicle/renault/provider.go index e8dff19e81..d92de41f30 100644 --- a/vehicle/renault/provider.go +++ b/vehicle/renault/provider.go @@ -150,7 +150,7 @@ func (v *Provider) Climater() (bool, error) { return false, api.ErrNotAvailable } - active := !slices.Contains([]string{"off", "false", "invalid", "error"}, state) + active := !slices.Contains([]string{"off", "false", "invalid", "error", "unavailable"}, state) return active, nil } From 68653c41455538db52c592724d3d5fc3b78289e9 Mon Sep 17 00:00:00 2001 From: Andreas Linde <42185+DerAndereAndi@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:14:11 +0200 Subject: [PATCH 003/116] Update EEBUS libraries (#16039) - Update SPINE and EEBUS libraries - Fixes issues in internal data handling, which lead to usecases only working on the first connection to a remote device --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 48a2e40576..8aff5152cc 100644 --- a/go.mod +++ b/go.mod @@ -121,7 +121,7 @@ require ( github.com/cstockton/go-conv v1.0.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/enbility/go-avahi v0.0.0-20240829083637-9ae2ef5f5ed2 // indirect + github.com/enbility/go-avahi v0.0.0-20240909195612-d5de6b280d7a // indirect github.com/enbility/zeroconf/v2 v2.0.0-20240827101515-f3956627c450 // indirect github.com/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -204,8 +204,8 @@ replace github.com/grid-x/modbus => github.com/evcc-io/modbus v0.0.0-20240503125 replace github.com/lorenzodonini/ocpp-go => github.com/evcc-io/ocpp-go v0.0.0-20240730071053-d69e53b0fce9 -replace github.com/enbility/ship-go => github.com/enbility/ship-go v0.0.0-20240904104254-04d944c4f825 +replace github.com/enbility/ship-go => github.com/enbility/ship-go v0.0.0-20240909200111-0d37cebbfc21 -replace github.com/enbility/spine-go => github.com/enbility/spine-go v0.0.0-20240907194637-0024041a4f36 +replace github.com/enbility/spine-go => github.com/enbility/spine-go v0.0.0-20240911140055-b637b5392906 -replace github.com/enbility/eebus-go => github.com/enbility/eebus-go v0.0.0-20240907200357-cd3e59d01934 +replace github.com/enbility/eebus-go => github.com/enbility/eebus-go v0.0.0-20240911140240-9cc1fcff7307 diff --git a/go.sum b/go.sum index b64f2dc60b..80d4101afb 100644 --- a/go.sum +++ b/go.sum @@ -127,14 +127,14 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o= github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/enbility/eebus-go v0.0.0-20240907200357-cd3e59d01934 h1:dqPRBE0JpbLmPfIhvqDMKKFJmCChHbN/zfu9YWwXtJc= -github.com/enbility/eebus-go v0.0.0-20240907200357-cd3e59d01934/go.mod h1:WhvimKG+DVyHRr4H++A+9c3F9AuuA7VJtLFo6m/BwxY= -github.com/enbility/go-avahi v0.0.0-20240829083637-9ae2ef5f5ed2 h1:voP4zFVNvVWxlV22T1EUAdZ0VlqVV1pkFLhoTTPgwbA= -github.com/enbility/go-avahi v0.0.0-20240829083637-9ae2ef5f5ed2/go.mod h1:KJXUEgg/b4XZzS+OFfqnykHREsinuNSL/IzJ+nU43P8= -github.com/enbility/ship-go v0.0.0-20240904104254-04d944c4f825 h1:i/n9UFYf660TyC8Y48P3MDxLaWWKRNW3pFjEOVzPzto= -github.com/enbility/ship-go v0.0.0-20240904104254-04d944c4f825/go.mod h1:dzymc1D7BDZUTLVHVt9JRRkFLlBrlUmRKyLJvAe07Mc= -github.com/enbility/spine-go v0.0.0-20240907194637-0024041a4f36 h1:Y44hzp5uIYSEyBMe/zwFzlXKokgZHQ9cv2NiIF1NkZs= -github.com/enbility/spine-go v0.0.0-20240907194637-0024041a4f36/go.mod h1:BDvhbs+XsWDGYwd8eQOzPXc8w/avVFmWKLlSKV/gx9k= +github.com/enbility/eebus-go v0.0.0-20240911140240-9cc1fcff7307 h1:kbLNFmMwNF8qNSPcTIJoOgmzZMh5hwJUZEeu2Sl/tXk= +github.com/enbility/eebus-go v0.0.0-20240911140240-9cc1fcff7307/go.mod h1:D5d+EQVuqhjGBaJwsxljEOwbzTNw4q6HOO3jiVN77L4= +github.com/enbility/go-avahi v0.0.0-20240909195612-d5de6b280d7a h1:foChWb8lhzqa6lWDRs6COYMdp649YlUirFP8GqoT0JQ= +github.com/enbility/go-avahi v0.0.0-20240909195612-d5de6b280d7a/go.mod h1:H64mhYcAQUGUUnVqMdZQf93kPecH4M79xwH95Lddt3U= +github.com/enbility/ship-go v0.0.0-20240909200111-0d37cebbfc21 h1:ZuOja5wms/Yujch+f1wQAw5ASY8mEFUpqf/j2LFrjzA= +github.com/enbility/ship-go v0.0.0-20240909200111-0d37cebbfc21/go.mod h1:8EaCKa2WOVZ/4SpquvZStPakEarjRXQLNHhC4azvaA0= +github.com/enbility/spine-go v0.0.0-20240911140055-b637b5392906 h1:/jhq32DUM6vj/mUwy0134PP6wtP7Rm8SI5tmixZhE4I= +github.com/enbility/spine-go v0.0.0-20240911140055-b637b5392906/go.mod h1:BDvhbs+XsWDGYwd8eQOzPXc8w/avVFmWKLlSKV/gx9k= github.com/enbility/zeroconf/v2 v2.0.0-20240827101515-f3956627c450 h1:39tnpfiV5OVfYb9sOqYmoivBzTHyNLWSYIxd9Qng1eg= github.com/enbility/zeroconf/v2 v2.0.0-20240827101515-f3956627c450/go.mod h1:1sUbJ+VE7yLNyRzGoCMjoDWtdZ+bW4aYBKx2+Rw+9hs= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= From 2d60e6797a501c100d5c9ea24d72f9721913a6f2 Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 11 Sep 2024 18:14:49 +0200 Subject: [PATCH 004/116] chore: cleanup capacity (#15989) --- templates/definition/meter/alpha-ess-smile.yaml | 2 -- templates/definition/meter/deye-hybrid-hp3.yaml | 2 -- templates/definition/meter/deye-storage.yaml | 2 -- templates/definition/meter/e3dc-modbus.yaml | 2 -- templates/definition/meter/enphase.yaml | 2 -- templates/definition/meter/fronius-gen24.yaml | 2 -- templates/definition/meter/fronius-solarapi-v1.yaml | 2 -- templates/definition/meter/growatt-hybrid-tlxh.yaml | 2 -- templates/definition/meter/growatt-hybrid.yaml | 2 -- templates/definition/meter/huawei-sun2000-rs485.yaml | 2 -- templates/definition/meter/kostal-piko-hybrid.yaml | 2 -- templates/definition/meter/lg-ess-home-8-10.yaml | 2 -- templates/definition/meter/openems.yaml | 2 -- templates/definition/meter/rct-power.yaml | 2 -- templates/definition/meter/saj-h2.yaml | 2 -- templates/definition/meter/senec-home.yaml | 2 -- templates/definition/meter/sma-datamanager.yaml | 2 -- templates/definition/meter/sma-hybrid.yaml | 2 -- templates/definition/meter/sma-inverter-speedwire.yaml | 2 -- templates/definition/meter/sma-sbs-modbus.yaml | 2 -- templates/definition/meter/sma-si-modbus.yaml | 2 -- templates/definition/meter/sofarsolar.yaml | 2 -- templates/definition/meter/solaredge-hybrid.yaml | 2 -- templates/definition/meter/solarmax-maxstorage.yaml | 2 -- templates/definition/meter/solarwatt-myreserve-matrix.yaml | 2 -- templates/definition/meter/solarwatt.yaml | 2 -- templates/definition/meter/solax-hybrid-cloud.yaml | 2 -- templates/definition/meter/solax.yaml | 2 -- templates/definition/meter/solis-hybrid-s.yaml | 2 -- templates/definition/meter/solis-hybrid.yaml | 2 -- templates/definition/meter/sonnenbatterie.yaml | 2 -- templates/definition/meter/sonnenbatterie_eco56.yaml | 2 -- templates/definition/meter/sungrow-hybrid.yaml | 2 -- templates/definition/meter/sunspec-inverter-control.yaml | 2 -- templates/definition/meter/varta.yaml | 2 -- 35 files changed, 70 deletions(-) diff --git a/templates/definition/meter/alpha-ess-smile.yaml b/templates/definition/meter/alpha-ess-smile.yaml index 4a81d6ded7..72caa8ffc1 100644 --- a/templates/definition/meter/alpha-ess-smile.yaml +++ b/templates/definition/meter/alpha-ess-smile.yaml @@ -133,7 +133,5 @@ render: | type: holding decode: uint16 scale: 0.1 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/deye-hybrid-hp3.yaml b/templates/definition/meter/deye-hybrid-hp3.yaml index 168b797f97..93c1e2c8c6 100644 --- a/templates/definition/meter/deye-hybrid-hp3.yaml +++ b/templates/definition/meter/deye-hybrid-hp3.yaml @@ -254,7 +254,5 @@ render: | decode: int32s minsoc: {{.minsoc}} maxsoc: {{.maxsoc}} - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/deye-storage.yaml b/templates/definition/meter/deye-storage.yaml index 6a90dee722..85a9aa3f1b 100644 --- a/templates/definition/meter/deye-storage.yaml +++ b/templates/definition/meter/deye-storage.yaml @@ -77,10 +77,8 @@ render: | address: 184 # "battery capacity" type: holding decode: uint16 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} {{- if eq .usage "grid" }} power: source: modbus diff --git a/templates/definition/meter/e3dc-modbus.yaml b/templates/definition/meter/e3dc-modbus.yaml index 8cccec9baf..731b54b2f5 100644 --- a/templates/definition/meter/e3dc-modbus.yaml +++ b/templates/definition/meter/e3dc-modbus.yaml @@ -56,7 +56,5 @@ render: | address: 40082 # Batterie-SOC in % type: holding decode: uint16 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/enphase.yaml b/templates/definition/meter/enphase.yaml index 3e8bdf9bf6..1b646cb249 100644 --- a/templates/definition/meter/enphase.yaml +++ b/templates/definition/meter/enphase.yaml @@ -75,7 +75,5 @@ render: | insecure: true {{- end }} jq: .[].devices | map(.percentFull) | add / length - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/fronius-gen24.yaml b/templates/definition/meter/fronius-gen24.yaml index 10f8f60f0d..51fd35e0da 100644 --- a/templates/definition/meter/fronius-gen24.yaml +++ b/templates/definition/meter/fronius-gen24.yaml @@ -149,7 +149,5 @@ render: | uri: {{ .host }}:{{ .port }} id: 1 value: 124:0:OutWRte - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/fronius-solarapi-v1.yaml b/templates/definition/meter/fronius-solarapi-v1.yaml index 7da4f1d8b7..1aef223a54 100644 --- a/templates/definition/meter/fronius-solarapi-v1.yaml +++ b/templates/definition/meter/fronius-solarapi-v1.yaml @@ -89,7 +89,5 @@ render: | password: {{ .password }} body: '{"timeofuse":[]}' {{- end }} - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/growatt-hybrid-tlxh.yaml b/templates/definition/meter/growatt-hybrid-tlxh.yaml index b04db49e08..f35adc6687 100644 --- a/templates/definition/meter/growatt-hybrid-tlxh.yaml +++ b/templates/definition/meter/growatt-hybrid-tlxh.yaml @@ -107,9 +107,7 @@ render: | address: 3171 # SOC type: input decode: uint16 - {{- if .capacity }} capacity: {{ .capacity }} # kWh - {{- end }} energy: source: modbus {{- include "modbus" . | indent 2 }} diff --git a/templates/definition/meter/growatt-hybrid.yaml b/templates/definition/meter/growatt-hybrid.yaml index a28b726302..2aa8f56f8c 100644 --- a/templates/definition/meter/growatt-hybrid.yaml +++ b/templates/definition/meter/growatt-hybrid.yaml @@ -95,9 +95,7 @@ render: | address: 1014 # SOC type: input decode: uint16 - {{- if .capacity }} capacity: {{ .capacity }} # kWh - {{- end }} energy: source: modbus {{- include "modbus" . | indent 2 }} diff --git a/templates/definition/meter/huawei-sun2000-rs485.yaml b/templates/definition/meter/huawei-sun2000-rs485.yaml index e3b31fbf43..cbe9a66c12 100644 --- a/templates/definition/meter/huawei-sun2000-rs485.yaml +++ b/templates/definition/meter/huawei-sun2000-rs485.yaml @@ -116,7 +116,5 @@ render: | type: holding decode: uint32 scale: 0.01 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/kostal-piko-hybrid.yaml b/templates/definition/meter/kostal-piko-hybrid.yaml index 342b20961d..c9a6808961 100644 --- a/templates/definition/meter/kostal-piko-hybrid.yaml +++ b/templates/definition/meter/kostal-piko-hybrid.yaml @@ -48,7 +48,5 @@ render: | uri: http://{{ .host }}/api/dxs.json?dxsEntries=33556229 # Battery SOC # | ----------------------------- Bat SOC% --------- | jq: (.dxsEntries[] | select(.dxsId==33556229) | .value ) - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/lg-ess-home-8-10.yaml b/templates/definition/meter/lg-ess-home-8-10.yaml index 4e229dcb75..10f05dfb09 100644 --- a/templates/definition/meter/lg-ess-home-8-10.yaml +++ b/templates/definition/meter/lg-ess-home-8-10.yaml @@ -35,6 +35,4 @@ render: | {{- if .registration }} registration: {{ .registration }} {{- end }} - {{- if .capacity }} capacity: {{ .capacity }} # kWh - {{- end }} diff --git a/templates/definition/meter/openems.yaml b/templates/definition/meter/openems.yaml index 521ab57461..fac38d4347 100644 --- a/templates/definition/meter/openems.yaml +++ b/templates/definition/meter/openems.yaml @@ -40,7 +40,5 @@ render: | user: x password: {{ .password }} jq: (.value // 0) - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/rct-power.yaml b/templates/definition/meter/rct-power.yaml index e777e9c3a4..a9c6a4d9c7 100644 --- a/templates/definition/meter/rct-power.yaml +++ b/templates/definition/meter/rct-power.yaml @@ -15,6 +15,4 @@ render: | uri: {{ .host }} usage: {{ .usage }} cache: 2s - {{- if .capacity }} capacity: {{ .capacity }} # kWh - {{- end }} diff --git a/templates/definition/meter/saj-h2.yaml b/templates/definition/meter/saj-h2.yaml index 3f683dc4ef..6eec38791d 100644 --- a/templates/definition/meter/saj-h2.yaml +++ b/templates/definition/meter/saj-h2.yaml @@ -97,7 +97,5 @@ render: | type: holding decode: uint16 scale: 0.01 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/senec-home.yaml b/templates/definition/meter/senec-home.yaml index 27d609fb22..a4976b4b9a 100644 --- a/templates/definition/meter/senec-home.yaml +++ b/templates/definition/meter/senec-home.yaml @@ -52,7 +52,5 @@ render: | jq: .ENERGY.GUI_BAT_DATA_FUEL_CHARGE | sub("fl_"; "") unpack: hex decode: float32 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/sma-datamanager.yaml b/templates/definition/meter/sma-datamanager.yaml index 205a0fdcaf..ddbfd6be5b 100644 --- a/templates/definition/meter/sma-datamanager.yaml +++ b/templates/definition/meter/sma-datamanager.yaml @@ -100,7 +100,5 @@ render: | address: 30845 # Battery Soc, % type: holding decode: uint32nan - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/sma-hybrid.yaml b/templates/definition/meter/sma-hybrid.yaml index 8d36d9f125..f6bddf9b1e 100644 --- a/templates/definition/meter/sma-hybrid.yaml +++ b/templates/definition/meter/sma-hybrid.yaml @@ -143,10 +143,8 @@ render: | address: 40151 # SMA Modbus Profile: Inverter.WModCfg.WCtlComCfg.WCtlComAct type: writemultiple decode: uint32 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} {{- if eq .usage "grid" }} power: source: modbus diff --git a/templates/definition/meter/sma-inverter-speedwire.yaml b/templates/definition/meter/sma-inverter-speedwire.yaml index 5c153a3eed..830291b692 100644 --- a/templates/definition/meter/sma-inverter-speedwire.yaml +++ b/templates/definition/meter/sma-inverter-speedwire.yaml @@ -22,6 +22,4 @@ render: | {{- if .password }} password: {{ .password }} # optional {{- end }} - {{- if .capacity }} capacity: {{ .capacity }} # kWh - {{- end }} diff --git a/templates/definition/meter/sma-sbs-modbus.yaml b/templates/definition/meter/sma-sbs-modbus.yaml index 3ef1575d65..2ab7120325 100644 --- a/templates/definition/meter/sma-sbs-modbus.yaml +++ b/templates/definition/meter/sma-sbs-modbus.yaml @@ -84,6 +84,4 @@ render: | address: 44039 # SMA Modbus Profile: Inverter.WModCfg.WCtlComCfg.WSptMaxNom type: writemultiple decode: int32 - {{- if .capacity }} capacity: {{ .capacity }} # kWh - {{- end }} diff --git a/templates/definition/meter/sma-si-modbus.yaml b/templates/definition/meter/sma-si-modbus.yaml index 6ce88b10e6..c6f18818ff 100644 --- a/templates/definition/meter/sma-si-modbus.yaml +++ b/templates/definition/meter/sma-si-modbus.yaml @@ -109,6 +109,4 @@ render: | address: 40151 # SMA Modbus Profile: Inverter.WModCfg.WCtlComCfg.WCtlComAct type: writemultiple decode: uint32 - {{- if .capacity }} capacity: {{ .capacity }} # kWh - {{- end }} diff --git a/templates/definition/meter/sofarsolar.yaml b/templates/definition/meter/sofarsolar.yaml index 90aeadf87c..0a3bc552a8 100644 --- a/templates/definition/meter/sofarsolar.yaml +++ b/templates/definition/meter/sofarsolar.yaml @@ -91,7 +91,5 @@ render: | address: 0x0210 # The residual capacity of battery type: holding decode: uint16 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/solaredge-hybrid.yaml b/templates/definition/meter/solaredge-hybrid.yaml index 06cbecbb12..10d0eb894a 100644 --- a/templates/definition/meter/solaredge-hybrid.yaml +++ b/templates/definition/meter/solaredge-hybrid.yaml @@ -205,7 +205,5 @@ render: | address: 0xE010 # StorageRemoteCtrl_DischargeLimit type: writemultiple encoding: float32s - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/solarmax-maxstorage.yaml b/templates/definition/meter/solarmax-maxstorage.yaml index dcee662140..eaf689517d 100644 --- a/templates/definition/meter/solarmax-maxstorage.yaml +++ b/templates/definition/meter/solarmax-maxstorage.yaml @@ -47,7 +47,5 @@ render: | address: 122 # Batterie Soc type: input decode: int16 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/solarwatt-myreserve-matrix.yaml b/templates/definition/meter/solarwatt-myreserve-matrix.yaml index 6cf187e758..2235a54d70 100644 --- a/templates/definition/meter/solarwatt-myreserve-matrix.yaml +++ b/templates/definition/meter/solarwatt-myreserve-matrix.yaml @@ -29,7 +29,5 @@ render: | source: http uri: http://{{ .host }}:{{ .port }}/ jq: .SData.SoC - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/solarwatt.yaml b/templates/definition/meter/solarwatt.yaml index 95fedc001e..529601226b 100644 --- a/templates/definition/meter/solarwatt.yaml +++ b/templates/definition/meter/solarwatt.yaml @@ -49,7 +49,5 @@ render: | source: http uri: http://{{ .host }}/rest/kiwigrid/wizard/devices # EnergyManager jq: .result.items[] | select(.deviceModel[].deviceClass == "com.kiwigrid.devices.location.Location" ) | (.tagValues.WorkReleased.value // 0) / 1000 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/solax-hybrid-cloud.yaml b/templates/definition/meter/solax-hybrid-cloud.yaml index b178ca164f..2089c96b0c 100644 --- a/templates/definition/meter/solax-hybrid-cloud.yaml +++ b/templates/definition/meter/solax-hybrid-cloud.yaml @@ -70,7 +70,5 @@ render: | uri: https://www.solaxcloud.com/proxyApp/proxy/api/getRealtimeInfo.do?tokenId={{ urlEncode .tokenid }}&sn={{ urlEncode .serial }} jq: .result.soc # Solax API inverter.DC.battery.energy.SOC cache: 2m30s - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/solax.yaml b/templates/definition/meter/solax.yaml index 6c7cabcb43..0d8e1e422d 100644 --- a/templates/definition/meter/solax.yaml +++ b/templates/definition/meter/solax.yaml @@ -134,7 +134,5 @@ render: | address: 0x001F # SolarChargeUseMode type: writesingle decode: uint16 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/solis-hybrid-s.yaml b/templates/definition/meter/solis-hybrid-s.yaml index d851f53c19..525de9c74b 100644 --- a/templates/definition/meter/solis-hybrid-s.yaml +++ b/templates/definition/meter/solis-hybrid-s.yaml @@ -128,7 +128,5 @@ render: | address: 33139 # Battery capacity SOC type: input decode: uint16 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/solis-hybrid.yaml b/templates/definition/meter/solis-hybrid.yaml index 5f913f098e..215ab2b861 100644 --- a/templates/definition/meter/solis-hybrid.yaml +++ b/templates/definition/meter/solis-hybrid.yaml @@ -116,7 +116,5 @@ render: | address: 33139 # Battery capacity SOC type: input decode: uint16 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/sonnenbatterie.yaml b/templates/definition/meter/sonnenbatterie.yaml index 63e7bde7ea..3e414f97e0 100644 --- a/templates/definition/meter/sonnenbatterie.yaml +++ b/templates/definition/meter/sonnenbatterie.yaml @@ -120,7 +120,5 @@ render: | - content-type: application/json - Auth-Token: {{ .token }} {{- end }} - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/sonnenbatterie_eco56.yaml b/templates/definition/meter/sonnenbatterie_eco56.yaml index cc51b133a7..a5c7d550a9 100644 --- a/templates/definition/meter/sonnenbatterie_eco56.yaml +++ b/templates/definition/meter/sonnenbatterie_eco56.yaml @@ -48,7 +48,5 @@ render: | source: http uri: http://{{ .host }}:{{ .port }}/rest/devices/battery jq: .M30 # SOC relative to usable capacity (.M05 # display SOC) - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/sungrow-hybrid.yaml b/templates/definition/meter/sungrow-hybrid.yaml index 7afb144eb2..66df5237df 100644 --- a/templates/definition/meter/sungrow-hybrid.yaml +++ b/templates/definition/meter/sungrow-hybrid.yaml @@ -245,7 +245,5 @@ render: | address: 13051 # Charge/discharge power type: writesingle decode: uint16 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/sunspec-inverter-control.yaml b/templates/definition/meter/sunspec-inverter-control.yaml index 364f4410cc..7d4f14c358 100644 --- a/templates/definition/meter/sunspec-inverter-control.yaml +++ b/templates/definition/meter/sunspec-inverter-control.yaml @@ -103,7 +103,5 @@ render: | source: sunspec {{- include "modbus" . | indent 10 }} value: 124:0:OutWRte - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} diff --git a/templates/definition/meter/varta.yaml b/templates/definition/meter/varta.yaml index f3986a5444..a68b33607a 100644 --- a/templates/definition/meter/varta.yaml +++ b/templates/definition/meter/varta.yaml @@ -52,7 +52,5 @@ render: | address: 1068 # SOC type: holding decode: int16 - {{- if .capacity }} capacity: {{ .capacity }} # kWh {{- end }} - {{- end }} From 90105452495d8db41e362da45c1d6759ed2efd05 Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 11 Sep 2024 18:18:18 +0200 Subject: [PATCH 005/116] chore: put grid first (#15990) --- templates/definition/meter/deye-storage.yaml | 52 ++++++------- templates/definition/meter/sma-hybrid.yaml | 78 ++++++++++---------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/templates/definition/meter/deye-storage.yaml b/templates/definition/meter/deye-storage.yaml index 85a9aa3f1b..94a3828990 100644 --- a/templates/definition/meter/deye-storage.yaml +++ b/templates/definition/meter/deye-storage.yaml @@ -17,6 +17,32 @@ params: advanced: true render: | type: custom + {{- if eq .usage "grid" }} + power: + source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 169 # "Total grid power" + type: holding + decode: int16 + energy: + source: calc + add: + - source: modbus + {{- include "modbus" . | indent 4 }} + register: + address: 78 # "Total_GridBuy_PowerWh_low" + type: holding + decode: uint16 + scale: 0.1 + - source: modbus + {{- include "modbus" . | indent 4 }} + register: + address: 80 # "Total_GridBuy_PowerWh" + type: holding + decode: uint16 + scale: 6553.6 + {{- end }} {{- if eq .usage "pv" }} power: source: calc @@ -79,29 +105,3 @@ render: | decode: uint16 capacity: {{ .capacity }} # kWh {{- end }} - {{- if eq .usage "grid" }} - power: - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 169 # "Total grid power" - type: holding - decode: int16 - energy: - source: calc - add: - - source: modbus - {{- include "modbus" . | indent 4 }} - register: - address: 78 # "Total_GridBuy_PowerWh_low" - type: holding - decode: uint16 - scale: 0.1 - - source: modbus - {{- include "modbus" . | indent 4 }} - register: - address: 80 # "Total_GridBuy_PowerWh" - type: holding - decode: uint16 - scale: 6553.6 - {{- end }} diff --git a/templates/definition/meter/sma-hybrid.yaml b/templates/definition/meter/sma-hybrid.yaml index f6bddf9b1e..b01fe0e0ea 100644 --- a/templates/definition/meter/sma-hybrid.yaml +++ b/templates/definition/meter/sma-hybrid.yaml @@ -24,6 +24,45 @@ params: advanced: true render: | type: custom + {{- if eq .usage "grid" }} + power: + source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 30865 # SMA Modbus Profile: Metering.GridMs.TotWIn + type: input + decode: int32nan + energy: + source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 30581 # SMA Modbus Profile: Metering.GridMs.TotWhIn + type: holding + decode: int32nan + scale: 0.001 + currents: + - source: modbus + {{- include "modbus" . | indent 4 }} + register: + address: 31435 # SMA Modbus Profile: Metering.GridMs.A.phsA + type: input + decode: int32nan + scale: 0.001 + - source: modbus + {{- include "modbus" . | indent 4 }} + register: + address: 31437 # SMA Modbus Profile: Metering.GridMs.A.phsB + type: input + decode: int32nan + scale: 0.001 + - source: modbus + {{- include "modbus" . | indent 4 }} + register: + address: 31439 # SMA Modbus Profile: Metering.GridMs.A.phsC + type: input + decode: int32nan + scale: 0.001 + {{- end }} {{- if eq .usage "pv" }} power: source: calc @@ -145,42 +184,3 @@ render: | decode: uint32 capacity: {{ .capacity }} # kWh {{- end }} - {{- if eq .usage "grid" }} - power: - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 30865 # SMA Modbus Profile: Metering.GridMs.TotWIn - type: input - decode: int32nan - energy: - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 30581 # SMA Modbus Profile: Metering.GridMs.TotWhIn - type: holding - decode: int32nan - scale: 0.001 - currents: - - source: modbus - {{- include "modbus" . | indent 4 }} - register: - address: 31435 # SMA Modbus Profile: Metering.GridMs.A.phsA - type: input - decode: int32nan - scale: 0.001 - - source: modbus - {{- include "modbus" . | indent 4 }} - register: - address: 31437 # SMA Modbus Profile: Metering.GridMs.A.phsB - type: input - decode: int32nan - scale: 0.001 - - source: modbus - {{- include "modbus" . | indent 4 }} - register: - address: 31439 # SMA Modbus Profile: Metering.GridMs.A.phsC - type: input - decode: int32nan - scale: 0.001 - {{- end }} From 4fa6f8ada52e52c16f7259859c05d2923cd80a6b Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 11 Sep 2024 18:45:07 +0200 Subject: [PATCH 006/116] Deye Hybrid: add default socs (#15987) --- templates/definition/meter/deye-hybrid-hp3.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/templates/definition/meter/deye-hybrid-hp3.yaml b/templates/definition/meter/deye-hybrid-hp3.yaml index 93c1e2c8c6..abca91156f 100644 --- a/templates/definition/meter/deye-hybrid-hp3.yaml +++ b/templates/definition/meter/deye-hybrid-hp3.yaml @@ -19,9 +19,11 @@ params: advanced: true - name: minsoc type: number + default: 20 advanced: true - name: maxsoc type: number + default: 95 advanced: true render: | type: custom @@ -252,7 +254,7 @@ render: | address: 172 type: writemultiple decode: int32s - minsoc: {{.minsoc}} - maxsoc: {{.maxsoc}} + minsoc: {{ .minsoc }} + maxsoc: {{ .maxsoc }} capacity: {{ .capacity }} # kWh {{- end }} From a44ba0d20d0b2a9b704a7f800290d6333ea43ea2 Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 11 Sep 2024 20:11:47 +0200 Subject: [PATCH 007/116] Modbus: fix an issue where modbus tcp transaction ids were reused --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8aff5152cc..a1af48da55 100644 --- a/go.mod +++ b/go.mod @@ -200,7 +200,7 @@ require ( replace gopkg.in/yaml.v3 => github.com/andig/yaml v0.0.0-20240531135838-1ff5761ab467 -replace github.com/grid-x/modbus => github.com/evcc-io/modbus v0.0.0-20240503125516-9fd99fe0e438 +replace github.com/grid-x/modbus => github.com/evcc-io/modbus v0.0.0-20240911180928-7b1464a53285 replace github.com/lorenzodonini/ocpp-go => github.com/evcc-io/ocpp-go v0.0.0-20240730071053-d69e53b0fce9 diff --git a/go.sum b/go.sum index 80d4101afb..fe28c7b0f4 100644 --- a/go.sum +++ b/go.sum @@ -140,8 +140,8 @@ github.com/enbility/zeroconf/v2 v2.0.0-20240827101515-f3956627c450/go.mod h1:1sU github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evcc-io/modbus v0.0.0-20240503125516-9fd99fe0e438 h1:I14MN2UauarS2Lo+prnNXEj31MxJS1mEfLUrEnOUBsw= -github.com/evcc-io/modbus v0.0.0-20240503125516-9fd99fe0e438/go.mod h1:WpbUAyptAAi0VAriSRopZa6uhiJOJCTz7KFvgGtNRXc= +github.com/evcc-io/modbus v0.0.0-20240911180928-7b1464a53285 h1:+zUVVXpybAsLXRY4KuTiMye/v5jCOxKG0heTSTHLW2Y= +github.com/evcc-io/modbus v0.0.0-20240911180928-7b1464a53285/go.mod h1:WpbUAyptAAi0VAriSRopZa6uhiJOJCTz7KFvgGtNRXc= github.com/evcc-io/ocpp-go v0.0.0-20240730071053-d69e53b0fce9 h1:FLv1vmLnfc8DanI5U1qOTe1Zr0OgZ/tuOvHALtZ2sOI= github.com/evcc-io/ocpp-go v0.0.0-20240730071053-d69e53b0fce9/go.mod h1:ZynYDWGw6CslG3vyPuucLsy6AyE+h3XXYlr39jhNiQY= github.com/evcc-io/tesla-proxy-client v0.0.0-20240221194046-4168b3759701 h1:3JplY3KS6KMDVDNAU+3+KWmSWmoHIU34qwuIpW6SiHk= From ef6ad884c6b723ff7f16cf77c465dec065d3421b Mon Sep 17 00:00:00 2001 From: Tobias Huber <133576574+TobiasHuber1980@users.noreply.github.com> Date: Fri, 13 Sep 2024 09:47:24 +0200 Subject: [PATCH 008/116] fix typo (#16035) --- i18n/de.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/de.toml b/i18n/de.toml index f4ab3adf19..4c35887213 100644 --- a/i18n/de.toml +++ b/i18n/de.toml @@ -256,7 +256,7 @@ greenEnergySub1 = "über evcc geladen" greenEnergySub2 = "seit Oktober 2022" greenShare = "Sonnenanteil" greenShareSub1 = "Strom bereitgestellt durch" -greenShareSub2 = "von PV und Speicher" +greenShareSub2 = "PV und Speicher" power = "Ladeleistung" powerSub1 = "{activeClients} von {totalClients} Nutzern" powerSub2 = "laden ..." From ad9edb84ebd7f9dbcfe0d9f622ae39e0fff843b5 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Fri, 13 Sep 2024 13:39:40 +0200 Subject: [PATCH 009/116] Fix smart cost zero status (#16064) --- assets/js/components/BatterySettingsModal.vue | 2 +- assets/js/components/ChargingPlanWarnings.vue | 2 +- assets/js/components/Energyflow/Energyflow.vue | 2 +- assets/js/components/Loadpoint.vue | 2 +- assets/js/components/Site.vue | 2 +- assets/js/components/VehicleStatus.vue | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/assets/js/components/BatterySettingsModal.vue b/assets/js/components/BatterySettingsModal.vue index edc5916f76..317abc88bb 100644 --- a/assets/js/components/BatterySettingsModal.vue +++ b/assets/js/components/BatterySettingsModal.vue @@ -272,7 +272,7 @@ export default { bufferStartSoc: Number, batteryDischargeControl: Boolean, battery: { type: Array, default: () => [] }, - batteryGridChargeLimit: Number, + batteryGridChargeLimit: { type: Number, default: null }, smartCostType: String, tariffGrid: Number, currency: String, diff --git a/assets/js/components/ChargingPlanWarnings.vue b/assets/js/components/ChargingPlanWarnings.vue index d44914342b..79d91ad7c9 100644 --- a/assets/js/components/ChargingPlanWarnings.vue +++ b/assets/js/components/ChargingPlanWarnings.vue @@ -109,7 +109,7 @@ export default { return this.fmtWh(this.planEnergy * 1e3); }, costLimitExists: function () { - return this.smartCostLimit !== 0; + return this.smartCostLimit !== null; }, costLimitText: function () { if (this.isCo2) { diff --git a/assets/js/components/Energyflow/Energyflow.vue b/assets/js/components/Energyflow/Energyflow.vue index 772bcdb31b..fa15f38e2e 100644 --- a/assets/js/components/Energyflow/Energyflow.vue +++ b/assets/js/components/Energyflow/Energyflow.vue @@ -337,7 +337,7 @@ export default { return this.fmtPricePerKWh(this.tariffGrid, this.currency, true); }, batteryGridChargeLimitFmt() { - if (this.batteryGridChargeLimit === null || this.batteryGridChargeLimit === undefined) { + if (this.batteryGridChargeLimit === null) { return; } if (this.co2Available) { diff --git a/assets/js/components/Loadpoint.vue b/assets/js/components/Loadpoint.vue index 636f80cd09..31fbdc608c 100644 --- a/assets/js/components/Loadpoint.vue +++ b/assets/js/components/Loadpoint.vue @@ -192,7 +192,7 @@ export default { phaseRemaining: Number, pvRemaining: Number, pvAction: String, - smartCostLimit: { type: Number, default: 0 }, + smartCostLimit: { type: Number, default: null }, smartCostType: String, smartCostActive: Boolean, smartCostNextStart: String, diff --git a/assets/js/components/Site.vue b/assets/js/components/Site.vue index 7e904a7a5d..f53260ea11 100644 --- a/assets/js/components/Site.vue +++ b/assets/js/components/Site.vue @@ -72,7 +72,7 @@ export default { batteryPower: Number, batterySoc: Number, batteryDischargeControl: Boolean, - batteryGridChargeLimit: Number, + batteryGridChargeLimit: { type: Number, default: null }, batteryGridChargeActive: Boolean, batteryMode: String, battery: Array, diff --git a/assets/js/components/VehicleStatus.vue b/assets/js/components/VehicleStatus.vue index e1a3bba162..37eaaa10b1 100644 --- a/assets/js/components/VehicleStatus.vue +++ b/assets/js/components/VehicleStatus.vue @@ -214,7 +214,7 @@ export default { pvRemainingInterpolated: Number, smartCostActive: Boolean, smartCostDisabled: Boolean, - smartCostLimit: Number, + smartCostLimit: { type: Number, default: null }, smartCostNextStart: String, smartCostType: String, tariffCo2: Number, @@ -422,7 +422,7 @@ export default { }); }, smartCostVisible() { - return !!this.smartCostLimit; + return this.smartCostLimit !== null; }, smartCostTooltipContent() { if (!this.smartCostVisible) { From 7837bacb886f2502a2f2fd1d480a199fc9a3978c Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 13 Sep 2024 14:53:00 +0200 Subject: [PATCH 010/116] Modbus: fix sunspec protocol always treated as tcp (#16086) --- provider/modbus_sunspec.go | 2 +- util/modbus/modbus.go | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/provider/modbus_sunspec.go b/provider/modbus_sunspec.go index 6b5df68869..90e64c8afc 100644 --- a/provider/modbus_sunspec.go +++ b/provider/modbus_sunspec.go @@ -47,7 +47,7 @@ func NewModbusSunspecFromConfig(other map[string]interface{}) (Provider, error) modbus.Lock() defer modbus.Unlock() - conn, err := modbus.NewConnection(cc.URI, cc.Device, cc.Comset, cc.Baudrate, modbus.Tcp, cc.ID) + conn, err := modbus.NewConnection(cc.URI, cc.Device, cc.Comset, cc.Baudrate, cc.Settings.Protocol(), cc.ID) if err != nil { return nil, err } diff --git a/util/modbus/modbus.go b/util/modbus/modbus.go index 1c881f8feb..2448418e98 100644 --- a/util/modbus/modbus.go +++ b/util/modbus/modbus.go @@ -134,10 +134,11 @@ func physicalConnection(proto Protocol, cfg Settings) (*meterConnection, error) return nil, errors.New("invalid modbus configuration: need baudrate and comset") } - if proto == Ascii { - return registeredConnection(cfg.Device, Ascii, meters.NewASCII(cfg.Device, cfg.Baudrate, cfg.Comset)) - } else { - return registeredConnection(cfg.Device, Rtu, meters.NewRTU(cfg.Device, cfg.Baudrate, cfg.Comset)) + switch proto { + case Ascii: + return registeredConnection(cfg.Device, proto, meters.NewASCII(cfg.Device, cfg.Baudrate, cfg.Comset)) + default: + return registeredConnection(cfg.Device, proto, meters.NewRTU(cfg.Device, cfg.Baudrate, cfg.Comset)) } } @@ -145,13 +146,13 @@ func physicalConnection(proto Protocol, cfg Settings) (*meterConnection, error) switch proto { case Udp: - return registeredConnection(uri, Udp, meters.NewRTUOverUDP(uri)) + return registeredConnection(uri, proto, meters.NewRTUOverUDP(uri)) case Rtu: - return registeredConnection(uri, Rtu, meters.NewRTUOverTCP(uri)) + return registeredConnection(uri, proto, meters.NewRTUOverTCP(uri)) case Ascii: - return registeredConnection(uri, Ascii, meters.NewASCIIOverTCP(uri)) + return registeredConnection(uri, proto, meters.NewASCIIOverTCP(uri)) default: - return registeredConnection(uri, Tcp, meters.NewTCP(uri)) + return registeredConnection(uri, proto, meters.NewTCP(uri)) } } From 0fcc2154d0ca498d0a13f59e1ed0d4bb2fbd5f30 Mon Sep 17 00:00:00 2001 From: premultiply <4681172+premultiply@users.noreply.github.com> Date: Sat, 14 Sep 2024 09:15:15 +0200 Subject: [PATCH 011/116] Delta: fix Status & add StatusReason (#15983) --- charger/delta.go | 119 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 86 insertions(+), 33 deletions(-) diff --git a/charger/delta.go b/charger/delta.go index 4b921fe93e..caa9f4208e 100644 --- a/charger/delta.go +++ b/charger/delta.go @@ -16,14 +16,15 @@ import ( // Delta charger implementation type Delta struct { - log *util.Logger - conn *modbus.Connection - lp loadpoint.API - mu sync.Mutex - curr float64 - base uint16 - enabled bool - isBasic bool + log *util.Logger + conn *modbus.Connection + lp loadpoint.API + mu sync.Mutex + curr float64 + base uint16 + enabled bool + statusG func() (api.ChargeStatus, error) + statusReasonG func() (api.Reason, error) } const ( @@ -102,9 +103,14 @@ func NewDelta(uri, device, comset string, baudrate int, proto modbus.Protocol, s wb.base = connector * 1000 - // check for basic or smart register set - if _, err := wb.conn.ReadInputRegisters(wb.base+deltaRegEvseChargerState, 1); err != nil { - wb.isBasic = true + // used limited (converted?) status register + wb.statusG = wb.statusOCPP + wb.statusReasonG = wb.statusReasonOCPP + + // check if native status register is available + if _, err := wb.conn.ReadInputRegisters(wb.base+deltaRegEvseChargerState, 1); err == nil { + wb.statusG = wb.statusDelta + wb.statusReasonG = wb.statusReasonDelta } b, err := wb.conn.ReadHoldingRegisters(deltaRegCommunicationTimeoutEnabled, 1) @@ -140,7 +146,52 @@ func (wb *Delta) heartbeat(timeout time.Duration) { } // Status implements the api.Charger interface -func (wb *Delta) Status() (api.ChargeStatus, error) { +func (wb *Delta) statusDelta() (api.ChargeStatus, error) { + b, err := wb.conn.ReadInputRegisters(wb.base+deltaRegEvseChargerState, 1) + if err != nil { + return api.StatusNone, err + } + + // 0: Charging process not started (no vehicle connected) + // 1: Connected, waiting for release (by RFID or local) + // 2: Charging process starts + // 3: Charging + // 4: Suspended (loading paused) + // 5: Charging process successfully completed (vehicle still plugged in) + // 6: Charging process completed by user (vehicle still plugged in) + // 7: Charging ended with error (vehicle still connected) + + switch s := encoding.Uint16(b); s { + case 0, 1, 2: + return api.StatusA, nil + case 3: + return api.StatusC, nil + case 4, 5, 6, 7: + return api.StatusB, nil + default: + return api.StatusNone, fmt.Errorf("invalid status: %0x", s) + } +} + +// statusReason implements the api.StatusReasoner interface +func (wb *Delta) statusReasonDelta() (api.Reason, error) { + b, err := wb.conn.ReadInputRegisters(wb.base+deltaRegEvseChargerState, 1) + if err != nil { + return api.ReasonUnknown, err + } + + switch encoding.Uint16(b) { + case 1: + return api.ReasonWaitingForAuthorization, nil + case 7: + return api.ReasonDisconnectRequired, nil + } + + return api.ReasonUnknown, nil +} + +// Status implements the api.Charger interface +func (wb *Delta) statusOCPP() (api.ChargeStatus, error) { b, err := wb.conn.ReadInputRegisters(wb.base+deltaRegEvseState, 1) if err != nil { return api.StatusNone, err @@ -156,44 +207,46 @@ func (wb *Delta) Status() (api.ChargeStatus, error) { // 7: Suspended EVSE // 8: Not ready // 9: Faulted + switch s := encoding.Uint16(b); s { case 0, 1, 2: return api.StatusA, nil - case 3: - if wb.isBasic { - return api.StatusA, nil - } - return api.StatusB, nil - case 5, 6, 7, 9: - return api.StatusB, nil case 4: return api.StatusC, nil + case 3, 5, 6, 7, 9: + return api.StatusB, nil default: return api.StatusNone, fmt.Errorf("invalid status: %0x", s) } } -var _ api.StatusReasoner = (*Delta)(nil) - // statusReason implements the api.StatusReasoner interface -func (wb *Delta) StatusReason() (api.Reason, error) { - if !wb.isBasic { - b, err := wb.conn.ReadInputRegisters(wb.base+deltaRegEvseState, 1) - if err != nil { - return api.ReasonUnknown, err - } +func (wb *Delta) statusReasonOCPP() (api.Reason, error) { + b, err := wb.conn.ReadInputRegisters(wb.base+deltaRegEvseState, 1) + if err != nil { + return api.ReasonUnknown, err + } - switch s := encoding.Uint16(b); s { - case 3: - return api.ReasonWaitingForAuthorization, nil - case 5: - return api.ReasonDisconnectRequired, nil - } + switch encoding.Uint16(b) { + case 3: + return api.ReasonWaitingForAuthorization, nil + case 5, 9: + return api.ReasonDisconnectRequired, nil } return api.ReasonUnknown, nil } +func (wb *Delta) Status() (api.ChargeStatus, error) { + return wb.statusG() +} + +var _ api.StatusReasoner = (*Delta)(nil) + +func (wb *Delta) StatusReason() (api.Reason, error) { + return wb.statusReasonG() +} + // Enabled implements the api.Charger interface func (wb *Delta) Enabled() (bool, error) { b, err := wb.conn.ReadHoldingRegisters(wb.base+deltaRegEvseChargingPowerLimit, 2) From 624b1a81b0d694fbe5e15a332aed042c21c86e49 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 11:52:45 +0200 Subject: [PATCH 012/116] Ocpp: add detailed test logging (#16099) --- charger/ocpp/const.go | 4 ++-- charger/ocpp_test.go | 22 ++++++++++----------- charger/ocpp_test_handler.go | 15 -------------- charger/ocpp_test_logger.go | 38 ++++++++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 29 deletions(-) create mode 100644 charger/ocpp_test_logger.go diff --git a/charger/ocpp/const.go b/charger/ocpp/const.go index be8458eaec..3eab0a0e7e 100644 --- a/charger/ocpp/const.go +++ b/charger/ocpp/const.go @@ -2,9 +2,9 @@ package ocpp import "time" -const ( - Timeout = 30 * time.Second // default request / response timeout on protocol level +var Timeout = 30 * time.Second // default request / response timeout on protocol level +const ( // Core profile keys KeyMeterValueSampleInterval = "MeterValueSampleInterval" KeyMeterValuesSampledData = "MeterValuesSampledData" diff --git a/charger/ocpp_test.go b/charger/ocpp_test.go index dfe602c9a1..ce6efe4c6f 100644 --- a/charger/ocpp_test.go +++ b/charger/ocpp_test.go @@ -12,6 +12,7 @@ import ( "github.com/lorenzodonini/ocpp-go/ocpp1.6/core" "github.com/lorenzodonini/ocpp-go/ocpp1.6/remotetrigger" "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" + "github.com/lorenzodonini/ocpp-go/ocppj" "github.com/stretchr/testify/suite" ) @@ -30,6 +31,12 @@ type ocppTestSuite struct { } func (suite *ocppTestSuite) SetupSuite() { + // setup cs so we can overwrite logger afterwards + _ = ocpp.Instance() + ocppj.SetLogger(&ocppLogger{suite.T()}) + + ocpp.Timeout = 5 * time.Second + suite.clock = clock.NewMock() suite.NotNil(ocpp.Instance()) } @@ -59,24 +66,20 @@ func (suite *ocppTestSuite) startChargePoint(id string, connectorId int) ocpp16. func (suite *ocppTestSuite) handleTrigger(cp ocpp16.ChargePoint, connectorId int, msg remotetrigger.MessageTrigger) { switch msg { case core.BootNotificationFeatureName: - if res, err := cp.BootNotification("model", "vendor"); err != nil { + if _, err := cp.BootNotification("model", "vendor"); err != nil { suite.T().Log("BootNotification:", err) - } else { - suite.T().Log("BootNotification:", res) } case core.ChangeAvailabilityFeatureName: fallthrough case core.StatusNotificationFeatureName: - if res, err := cp.StatusNotification(connectorId, core.NoError, core.ChargePointStatusCharging); err != nil { + if _, err := cp.StatusNotification(connectorId, core.NoError, core.ChargePointStatusCharging); err != nil { suite.T().Log("StatusNotification:", err) - } else { - suite.T().Log("StatusNotification:", res) } case core.MeterValuesFeatureName: - if res, err := cp.MeterValues(connectorId, []types.MeterValue{ + if _, err := cp.MeterValues(connectorId, []types.MeterValue{ { Timestamp: types.NewDateTime(suite.clock.Now()), SampledValue: []types.SampledValue{ @@ -86,12 +89,7 @@ func (suite *ocppTestSuite) handleTrigger(cp ocpp16.ChargePoint, connectorId int }, }); err != nil { suite.T().Log("MeterValues:", err) - } else { - suite.T().Log("MeterValues:", res) } - - default: - suite.T().Log(msg) } } diff --git a/charger/ocpp_test_handler.go b/charger/ocpp_test_handler.go index 082dd3168f..1069dedb04 100644 --- a/charger/ocpp_test_handler.go +++ b/charger/ocpp_test_handler.go @@ -1,8 +1,6 @@ package charger import ( - "fmt" - "github.com/lorenzodonini/ocpp-go/ocpp1.6/core" "github.com/lorenzodonini/ocpp-go/ocpp1.6/remotetrigger" "github.com/lorenzodonini/ocpp-go/ocpp1.6/smartcharging" @@ -17,27 +15,22 @@ type ChargePointHandler struct { func (handler *ChargePointHandler) OnChangeAvailability(request *core.ChangeAvailabilityRequest) (confirmation *core.ChangeAvailabilityConfirmation, err error) { defer func() { handler.triggerC <- core.ChangeAvailabilityFeatureName }() - fmt.Printf("%T %+v\n", request, request) return core.NewChangeAvailabilityConfirmation(core.AvailabilityStatusAccepted), nil } func (handler *ChargePointHandler) OnChangeConfiguration(request *core.ChangeConfigurationRequest) (confirmation *core.ChangeConfigurationConfirmation, err error) { - fmt.Printf("%T %+v\n", request, request) return core.NewChangeConfigurationConfirmation(core.ConfigurationStatusAccepted), nil } func (handler *ChargePointHandler) OnClearCache(request *core.ClearCacheRequest) (confirmation *core.ClearCacheConfirmation, err error) { - fmt.Printf("%T %+v\n", request, request) return core.NewClearCacheConfirmation(core.ClearCacheStatusAccepted), nil } func (handler *ChargePointHandler) OnDataTransfer(request *core.DataTransferRequest) (confirmation *core.DataTransferConfirmation, err error) { - fmt.Printf("%T %+v\n", request, request) return core.NewDataTransferConfirmation(core.DataTransferStatusAccepted), nil } func (handler *ChargePointHandler) OnGetConfiguration(request *core.GetConfigurationRequest) (confirmation *core.GetConfigurationConfirmation, err error) { - fmt.Printf("%T %+v\n", request, request) one := "1" meter := "Power.Active.Import,Energy.Active.Import.Register" return core.NewGetConfigurationConfirmation([]core.ConfigurationKey{ @@ -52,44 +45,36 @@ func (handler *ChargePointHandler) OnGetConfiguration(request *core.GetConfigura } func (handler *ChargePointHandler) OnRemoteStartTransaction(request *core.RemoteStartTransactionRequest) (confirmation *core.RemoteStartTransactionConfirmation, err error) { - fmt.Printf("%T %+v\n", request, request) return core.NewRemoteStartTransactionConfirmation(types.RemoteStartStopStatusAccepted), nil } func (handler *ChargePointHandler) OnRemoteStopTransaction(request *core.RemoteStopTransactionRequest) (confirmation *core.RemoteStopTransactionConfirmation, err error) { - fmt.Printf("%T %+v\n", request, request) return core.NewRemoteStopTransactionConfirmation(types.RemoteStartStopStatusAccepted), nil } func (handler *ChargePointHandler) OnReset(request *core.ResetRequest) (confirmation *core.ResetConfirmation, err error) { - fmt.Printf("%T %+v\n", request, request) return core.NewResetConfirmation(core.ResetStatusAccepted), nil } func (handler *ChargePointHandler) OnUnlockConnector(request *core.UnlockConnectorRequest) (confirmation *core.UnlockConnectorConfirmation, err error) { - fmt.Printf("%T %+v\n", request, request) return core.NewUnlockConnectorConfirmation(core.UnlockStatusUnlocked), nil } func (handler *ChargePointHandler) OnTriggerMessage(request *remotetrigger.TriggerMessageRequest) (confirmation *remotetrigger.TriggerMessageConfirmation, err error) { defer func() { handler.triggerC <- request.RequestedMessage }() - fmt.Printf("%T %+v\n", request, request) return remotetrigger.NewTriggerMessageConfirmation(remotetrigger.TriggerMessageStatusAccepted), nil } // smart charging func (handler *ChargePointHandler) OnSetChargingProfile(request *smartcharging.SetChargingProfileRequest) (*smartcharging.SetChargingProfileConfirmation, error) { - fmt.Printf("%T %+v\n", request, request) return smartcharging.NewSetChargingProfileConfirmation(smartcharging.ChargingProfileStatusAccepted), nil } func (handler *ChargePointHandler) OnClearChargingProfile(request *smartcharging.ClearChargingProfileRequest) (*smartcharging.ClearChargingProfileConfirmation, error) { - fmt.Printf("%T %+v\n", request, request) return smartcharging.NewClearChargingProfileConfirmation(smartcharging.ClearChargingProfileStatusAccepted), nil } func (handler *ChargePointHandler) OnGetCompositeSchedule(request *smartcharging.GetCompositeScheduleRequest) (*smartcharging.GetCompositeScheduleConfirmation, error) { - fmt.Printf("%T %+v\n", request, request) return smartcharging.NewGetCompositeScheduleConfirmation(smartcharging.GetCompositeScheduleStatusAccepted), nil } diff --git a/charger/ocpp_test_logger.go b/charger/ocpp_test_logger.go new file mode 100644 index 0000000000..8fad7e12ec --- /dev/null +++ b/charger/ocpp_test_logger.go @@ -0,0 +1,38 @@ +package charger + +import ( + "fmt" + "strings" + "testing" +) + +type ocppLogger struct { + t *testing.T +} + +func print(t *testing.T, s string) { + var ok bool + if s, ok = strings.CutPrefix(s, "sent JSON message to"); ok { + s = "send" + s + } else if s, ok = strings.CutPrefix(s, "received JSON message from"); ok { + s = "recv" + s + } else { + ok = true + } + if ok { + t.Log(s) + } +} + +func (l *ocppLogger) Debug(args ...interface{}) { print(l.t, fmt.Sprint(args...)) } +func (l *ocppLogger) Debugf(format string, args ...interface{}) { + print(l.t, fmt.Sprintf(format, args...)) +} +func (l *ocppLogger) Info(args ...interface{}) { print(l.t, fmt.Sprint(args...)) } +func (l *ocppLogger) Infof(format string, args ...interface{}) { + print(l.t, fmt.Sprintf(format, args...)) +} +func (l *ocppLogger) Error(args ...interface{}) { print(l.t, fmt.Sprint(args...)) } +func (l *ocppLogger) Errorf(format string, args ...interface{}) { + print(l.t, fmt.Sprintf(format, args...)) +} From 1273ef9ab622c9d12cfef497016bdffcb8648c18 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 13:54:32 +0200 Subject: [PATCH 013/116] Ocpp: fix availability timeout (#16100) --- charger/ocpp/helper.go | 8 +++++++- charger/ocpp/instance.go | 6 +----- charger/ocpp_test.go | 25 +++++++++++++++++++++++-- charger/ocpp_test_handler.go | 7 +++++++ charger/ocpp_test_logger.go | 14 ++------------ 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/charger/ocpp/helper.go b/charger/ocpp/helper.go index db16d9a906..da86760f9c 100644 --- a/charger/ocpp/helper.go +++ b/charger/ocpp/helper.go @@ -1,12 +1,15 @@ package ocpp import ( + "errors" "slices" "strings" "time" "github.com/evcc-io/evcc/api" + "github.com/lorenzodonini/ocpp-go/ocpp" "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" + "github.com/lorenzodonini/ocpp-go/ocppj" ) // wait waits for a CP roundtrip with timeout @@ -15,7 +18,10 @@ func wait(err error, rc chan error) error { select { case err = <-rc: close(rc) - case <-time.After(Timeout): + } + + oe := new(ocpp.Error) + if errors.As(err, &oe) && oe.Code == ocppj.GenericError { err = api.ErrTimeout } } diff --git a/charger/ocpp/instance.go b/charger/ocpp/instance.go index 94624a367b..4220fc50c2 100644 --- a/charger/ocpp/instance.go +++ b/charger/ocpp/instance.go @@ -24,15 +24,11 @@ func Instance() *CS { once.Do(func() { log := util.NewLogger("ocpp") - timeoutConfig := ws.NewServerTimeoutConfig() - timeoutConfig.PingWait = 90 * time.Second - server := ws.NewServer() - server.SetTimeoutConfig(timeoutConfig) server.SetCheckOriginHandler(func(r *http.Request) bool { return true }) dispatcher := ocppj.NewDefaultServerDispatcher(ocppj.NewFIFOQueueMap(0)) - dispatcher.SetTimeout(time.Minute) + dispatcher.SetTimeout(Timeout) endpoint := ocppj.NewServer(server, dispatcher, nil, core.Profile, remotetrigger.Profile, smartcharging.Profile) endpoint.SetInvalidMessageHook(func(client ws.Channel, err *ocpp.Error, rawMessage string, parsedFields []interface{}) *ocpp.Error { diff --git a/charger/ocpp_test.go b/charger/ocpp_test.go index ce6efe4c6f..6aef283c85 100644 --- a/charger/ocpp_test.go +++ b/charger/ocpp_test.go @@ -31,16 +31,21 @@ type ocppTestSuite struct { } func (suite *ocppTestSuite) SetupSuite() { + ocpp.Timeout = 5 * time.Second + // setup cs so we can overwrite logger afterwards _ = ocpp.Instance() ocppj.SetLogger(&ocppLogger{suite.T()}) - ocpp.Timeout = 5 * time.Second - suite.clock = clock.NewMock() suite.NotNil(ocpp.Instance()) } +func (suite *ocppTestSuite) SetupTest() { + // default delays + ocppDelays = make(map[string]time.Duration) +} + func (suite *ocppTestSuite) startChargePoint(id string, connectorId int) ocpp16.ChargePoint { // set a handler for all callback functions handler := &ChargePointHandler{ @@ -223,3 +228,19 @@ func (suite *ocppTestSuite) TestAutoStart() { err = c1.Enable(false) suite.Require().NoError(err) } + +func (suite *ocppTestSuite) TestTimeout() { + // 1st charge point- remote + cp1 := suite.startChargePoint("test-4", 1) + suite.Require().NoError(cp1.Start(ocppTestUrl)) + suite.Require().True(cp1.IsConnected()) + + // timeout change availability request + ocppDelays[core.ChangeAvailabilityFeatureName] = time.Minute + + // 1st charge point- local + _, err := NewOCPP("test-4", 1, "", "", 0, false, false, ocppTestConnectTimeout) + + // TODO fix test - this should NOT error + suite.Require().Error(err) +} diff --git a/charger/ocpp_test_handler.go b/charger/ocpp_test_handler.go index 1069dedb04..0ef2abb979 100644 --- a/charger/ocpp_test_handler.go +++ b/charger/ocpp_test_handler.go @@ -1,6 +1,8 @@ package charger import ( + "time" + "github.com/lorenzodonini/ocpp-go/ocpp1.6/core" "github.com/lorenzodonini/ocpp-go/ocpp1.6/remotetrigger" "github.com/lorenzodonini/ocpp-go/ocpp1.6/smartcharging" @@ -11,10 +13,15 @@ type ChargePointHandler struct { triggerC chan remotetrigger.MessageTrigger } +var ocppDelays = make(map[string]time.Duration) + // core func (handler *ChargePointHandler) OnChangeAvailability(request *core.ChangeAvailabilityRequest) (confirmation *core.ChangeAvailabilityConfirmation, err error) { defer func() { handler.triggerC <- core.ChangeAvailabilityFeatureName }() + if d, ok := ocppDelays[core.ChangeAvailabilityFeatureName]; ok { + time.Sleep(d) + } return core.NewChangeAvailabilityConfirmation(core.AvailabilityStatusAccepted), nil } diff --git a/charger/ocpp_test_logger.go b/charger/ocpp_test_logger.go index 8fad7e12ec..ab6618a99b 100644 --- a/charger/ocpp_test_logger.go +++ b/charger/ocpp_test_logger.go @@ -2,8 +2,8 @@ package charger import ( "fmt" - "strings" "testing" + "time" ) type ocppLogger struct { @@ -11,17 +11,7 @@ type ocppLogger struct { } func print(t *testing.T, s string) { - var ok bool - if s, ok = strings.CutPrefix(s, "sent JSON message to"); ok { - s = "send" + s - } else if s, ok = strings.CutPrefix(s, "received JSON message from"); ok { - s = "recv" + s - } else { - ok = true - } - if ok { - t.Log(s) - } + t.Log((time.Now().Format(time.DateTime)), s) } func (l *ocppLogger) Debug(args ...interface{}) { print(l.t, fmt.Sprint(args...)) } From e2a5f4485afb970fba7610965b7d8b2b2de5b850 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 14:34:21 +0200 Subject: [PATCH 014/116] Ocpp: refactor testcase (#16103) --- charger/ocpp_test.go | 44 ++++++++++++++++++++++-------------- charger/ocpp_test_handler.go | 7 ------ go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/charger/ocpp_test.go b/charger/ocpp_test.go index 6aef283c85..2339c388f9 100644 --- a/charger/ocpp_test.go +++ b/charger/ocpp_test.go @@ -8,11 +8,17 @@ import ( "github.com/benbjohnson/clock" "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/charger/ocpp" + ocppapi "github.com/lorenzodonini/ocpp-go/ocpp" ocpp16 "github.com/lorenzodonini/ocpp-go/ocpp1.6" "github.com/lorenzodonini/ocpp-go/ocpp1.6/core" + "github.com/lorenzodonini/ocpp-go/ocpp1.6/firmware" + "github.com/lorenzodonini/ocpp-go/ocpp1.6/localauth" "github.com/lorenzodonini/ocpp-go/ocpp1.6/remotetrigger" + "github.com/lorenzodonini/ocpp-go/ocpp1.6/reservation" + "github.com/lorenzodonini/ocpp-go/ocpp1.6/smartcharging" "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" "github.com/lorenzodonini/ocpp-go/ocppj" + "github.com/lorenzodonini/ocpp-go/ws" "github.com/stretchr/testify/suite" ) @@ -41,19 +47,20 @@ func (suite *ocppTestSuite) SetupSuite() { suite.NotNil(ocpp.Instance()) } -func (suite *ocppTestSuite) SetupTest() { - // default delays - ocppDelays = make(map[string]time.Duration) -} - -func (suite *ocppTestSuite) startChargePoint(id string, connectorId int) ocpp16.ChargePoint { +func (suite *ocppTestSuite) startChargePoint(id string, connectorId int) (ocpp16.ChargePoint, *ocppj.Client) { // set a handler for all callback functions handler := &ChargePointHandler{ triggerC: make(chan remotetrigger.MessageTrigger, 1), } + // ocppj endpoint with handler + client := ws.NewClient() + client.SetRequestedSubProtocol(types.V16Subprotocol) + dispatcher := ocppj.NewDefaultClientDispatcher(ocppj.NewFIFOClientQueue(0)) + endpoint := ocppj.NewClient(id, client, dispatcher, nil, core.Profile, localauth.Profile, firmware.Profile, reservation.Profile, remotetrigger.Profile, smartcharging.Profile) + // create charge point with handler - cp := ocpp16.NewChargePoint(id, nil, nil) + cp := ocpp16.NewChargePoint(id, endpoint, client) cp.SetCoreHandler(handler) cp.SetRemoteTriggerHandler(handler) cp.SetSmartChargingHandler(handler) @@ -65,7 +72,7 @@ func (suite *ocppTestSuite) startChargePoint(id string, connectorId int) ocpp16. } }() - return cp + return cp, endpoint } func (suite *ocppTestSuite) handleTrigger(cp ocpp16.ChargePoint, connectorId int, msg remotetrigger.MessageTrigger) { @@ -100,7 +107,7 @@ func (suite *ocppTestSuite) handleTrigger(cp ocpp16.ChargePoint, connectorId int func (suite *ocppTestSuite) TestConnect() { // 1st charge point- remote - cp1 := suite.startChargePoint("test-1", 1) + cp1, _ := suite.startChargePoint("test-1", 1) suite.Require().NoError(cp1.Start(ocppTestUrl)) suite.Require().True(cp1.IsConnected()) @@ -149,7 +156,7 @@ func (suite *ocppTestSuite) TestConnect() { } // 2nd charge point - remote - cp2 := suite.startChargePoint("test-2", 1) + cp2, _ := suite.startChargePoint("test-2", 1) suite.Require().NoError(cp2.Start(ocppTestUrl)) suite.Require().True(cp2.IsConnected()) @@ -167,7 +174,7 @@ func (suite *ocppTestSuite) TestConnect() { } // error on unconfigured 2nd charge point - cp3 := suite.startChargePoint("unconfigured", 1) + cp3, _ := suite.startChargePoint("unconfigured", 1) _, err = cp3.BootNotification("model", "vendor") suite.Require().Error(err) @@ -191,7 +198,7 @@ WAIT_DISCONNECT: func (suite *ocppTestSuite) TestAutoStart() { // 1st charge point- remote - cp1 := suite.startChargePoint("test-3", 1) + cp1, _ := suite.startChargePoint("test-3", 1) suite.Require().NoError(cp1.Start(ocppTestUrl)) suite.Require().True(cp1.IsConnected()) @@ -231,16 +238,19 @@ func (suite *ocppTestSuite) TestAutoStart() { func (suite *ocppTestSuite) TestTimeout() { // 1st charge point- remote - cp1 := suite.startChargePoint("test-4", 1) + cp1, ocppjClient := suite.startChargePoint("test-4", 1) suite.Require().NoError(cp1.Start(ocppTestUrl)) suite.Require().True(cp1.IsConnected()) - // timeout change availability request - ocppDelays[core.ChangeAvailabilityFeatureName] = time.Minute + handler := ocppjClient.GetRequestHandler() + ocppjClient.SetRequestHandler(func(request ocppapi.Request, requestId string, action string) { + if action != core.ChangeAvailabilityFeatureName { + handler(request, requestId, action) + } + }) // 1st charge point- local _, err := NewOCPP("test-4", 1, "", "", 0, false, false, ocppTestConnectTimeout) - // TODO fix test - this should NOT error - suite.Require().Error(err) + suite.Require().NoError(err) } diff --git a/charger/ocpp_test_handler.go b/charger/ocpp_test_handler.go index 0ef2abb979..1069dedb04 100644 --- a/charger/ocpp_test_handler.go +++ b/charger/ocpp_test_handler.go @@ -1,8 +1,6 @@ package charger import ( - "time" - "github.com/lorenzodonini/ocpp-go/ocpp1.6/core" "github.com/lorenzodonini/ocpp-go/ocpp1.6/remotetrigger" "github.com/lorenzodonini/ocpp-go/ocpp1.6/smartcharging" @@ -13,15 +11,10 @@ type ChargePointHandler struct { triggerC chan remotetrigger.MessageTrigger } -var ocppDelays = make(map[string]time.Duration) - // core func (handler *ChargePointHandler) OnChangeAvailability(request *core.ChangeAvailabilityRequest) (confirmation *core.ChangeAvailabilityConfirmation, err error) { defer func() { handler.triggerC <- core.ChangeAvailabilityFeatureName }() - if d, ok := ocppDelays[core.ChangeAvailabilityFeatureName]; ok { - time.Sleep(d) - } return core.NewChangeAvailabilityConfirmation(core.AvailabilityStatusAccepted), nil } diff --git a/go.mod b/go.mod index a1af48da55..be24457ed9 100644 --- a/go.mod +++ b/go.mod @@ -202,7 +202,7 @@ replace gopkg.in/yaml.v3 => github.com/andig/yaml v0.0.0-20240531135838-1ff5761a replace github.com/grid-x/modbus => github.com/evcc-io/modbus v0.0.0-20240911180928-7b1464a53285 -replace github.com/lorenzodonini/ocpp-go => github.com/evcc-io/ocpp-go v0.0.0-20240730071053-d69e53b0fce9 +replace github.com/lorenzodonini/ocpp-go => github.com/evcc-io/ocpp-go v0.0.0-20240914122959-0d109e403130 replace github.com/enbility/ship-go => github.com/enbility/ship-go v0.0.0-20240909200111-0d37cebbfc21 diff --git a/go.sum b/go.sum index fe28c7b0f4..2c9deba1de 100644 --- a/go.sum +++ b/go.sum @@ -142,8 +142,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evcc-io/modbus v0.0.0-20240911180928-7b1464a53285 h1:+zUVVXpybAsLXRY4KuTiMye/v5jCOxKG0heTSTHLW2Y= github.com/evcc-io/modbus v0.0.0-20240911180928-7b1464a53285/go.mod h1:WpbUAyptAAi0VAriSRopZa6uhiJOJCTz7KFvgGtNRXc= -github.com/evcc-io/ocpp-go v0.0.0-20240730071053-d69e53b0fce9 h1:FLv1vmLnfc8DanI5U1qOTe1Zr0OgZ/tuOvHALtZ2sOI= -github.com/evcc-io/ocpp-go v0.0.0-20240730071053-d69e53b0fce9/go.mod h1:ZynYDWGw6CslG3vyPuucLsy6AyE+h3XXYlr39jhNiQY= +github.com/evcc-io/ocpp-go v0.0.0-20240914122959-0d109e403130 h1:U4xSZBknKsMDFQtLU3gdkDUylfN9kRUj01offtqs8lY= +github.com/evcc-io/ocpp-go v0.0.0-20240914122959-0d109e403130/go.mod h1:ZynYDWGw6CslG3vyPuucLsy6AyE+h3XXYlr39jhNiQY= github.com/evcc-io/tesla-proxy-client v0.0.0-20240221194046-4168b3759701 h1:3JplY3KS6KMDVDNAU+3+KWmSWmoHIU34qwuIpW6SiHk= github.com/evcc-io/tesla-proxy-client v0.0.0-20240221194046-4168b3759701/go.mod h1:zWtAweBqXJTk3HSrPSecz3Q3a2hAUQ4vOE6paJfn03I= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= From 8b5d5bb2217a85873c3c0c92045bad7bfa4d86a4 Mon Sep 17 00:00:00 2001 From: premultiply <4681172+premultiply@users.noreply.github.com> Date: Sat, 14 Sep 2024 14:35:25 +0200 Subject: [PATCH 015/116] Keba: simplify Status() and fix StatusReason() (#16003) --- charger/keba-modbus.go | 71 +++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/charger/keba-modbus.go b/charger/keba-modbus.go index 2d4fa53629..359767476a 100644 --- a/charger/keba-modbus.go +++ b/charger/keba-modbus.go @@ -167,55 +167,68 @@ func (wb *Keba) heartbeat(timeout time.Duration) { } } -// Status implements the api.Charger interface -func (wb *Keba) Status() (api.ChargeStatus, error) { +func (wb *Keba) isConnected() (bool, error) { b, err := wb.conn.ReadHoldingRegisters(kebaRegCableState, 2) - if err != nil { - return api.StatusNone, err - } - switch status := binary.BigEndian.Uint32(b); status { - case 0, 1, 3: - return api.StatusA, nil + // 0: No cable is plugged. + // 1: Cable is connected to the charging station (not to the electric vehicle). + // 3: Cable is connected to the charging station and locked (not to the electric vehicle). + // 5: Cable is connected to the charging station and the electric vehicle (not locked). + // 7: Cable is connected to the charging station and the electric vehicle and locked (charging). - case 5: - return api.StatusB, nil + return binary.BigEndian.Uint32(b)&5 != 0, err +} - case 7: - b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) - if err != nil { - return api.StatusNone, err - } - if binary.BigEndian.Uint32(b) == 3 { - return api.StatusC, err - } - return api.StatusB, nil +func (wb *Keba) getChargingState() (uint32, error) { + b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) + + // 0: Start-up of the charging station + // 1: The charging station is not ready for charging. The charging station is not connected to an electric vehicle, it is locked by the authorization function or another mechanism. + // 2: The charging station is ready for charging and waits for a reaction from the electric vehicle. + // 3: A charging process is active. + // 4: An error has occurred. + // 5: The charging process is temporarily interrupted because the temperature is too high or the wallbox is in suspended mode. + + return binary.BigEndian.Uint32(b), err +} + +// Status implements the api.Charger interface +func (wb *Keba) Status() (api.ChargeStatus, error) { + if connected, err := wb.isConnected(); err != nil || !connected { + return api.StatusA, err + } - default: - return api.StatusNone, fmt.Errorf("invalid status: %d", status) + s, err := wb.getChargingState() + if err != nil { + return api.StatusA, err } + if s == 3 { + return api.StatusC, nil + } + return api.StatusB, nil } // statusReason implements the api.StatusReasoner interface func (wb *Keba) statusReason() (api.Reason, error) { - res := api.ReasonUnknown + if connected, err := wb.isConnected(); err != nil || !connected { + return api.ReasonUnknown, err + } - b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) - if err == nil && binary.BigEndian.Uint32(b) == 1 { - res = api.ReasonWaitingForAuthorization + if s, err := wb.getChargingState(); err != nil || s != 1 { + return api.ReasonUnknown, err } - return res, err + return api.ReasonWaitingForAuthorization, nil } // Enabled implements the api.Charger interface func (wb *Keba) Enabled() (bool, error) { - b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) + s, err := wb.getChargingState() if err != nil { return false, err } - status := binary.BigEndian.Uint32(b) - return !(status == 5 || status == 1), nil + + return !(s == 5 || s == 1), nil } // Enable implements the api.Charger interface From 9c43aa7d447097dd7390ed81f881e9555d1c8a15 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Sat, 14 Sep 2024 14:35:52 +0200 Subject: [PATCH 016/116] chore: upgrade npm deps, fix audit (#16076) --- .../js/components/Energyflow/Energyflow.vue | 2 +- package-lock.json | 937 ++++++++---------- package.json | 2 +- 3 files changed, 426 insertions(+), 515 deletions(-) diff --git a/assets/js/components/Energyflow/Energyflow.vue b/assets/js/components/Energyflow/Energyflow.vue index fa15f38e2e..52c69a0387 100644 --- a/assets/js/components/Energyflow/Energyflow.vue +++ b/assets/js/components/Energyflow/Energyflow.vue @@ -130,7 +130,7 @@ /> =6.9.0" @@ -439,12 +439,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz", - "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.4" + "@babel/types": "^7.25.6" }, "bin": { "parser": "bin/babel-parser.js" @@ -608,12 +608,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -623,12 +623,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1682,9 +1682,9 @@ "license": "MIT" }, "node_modules/@babel/runtime": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz", - "integrity": "sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -1708,16 +1708,16 @@ } }, "node_modules/@babel/traverse": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz", - "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.4", - "@babel/parser": "^7.25.4", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", "@babel/template": "^7.25.0", - "@babel/types": "^7.25.4", + "@babel/types": "^7.25.6", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1726,9 +1726,9 @@ } }, "node_modules/@babel/types": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz", - "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.24.8", @@ -1740,9 +1740,9 @@ } }, "node_modules/@codemirror/commands": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.6.0.tgz", - "integrity": "sha512-qnY+b7j1UNcTS31Eenuc/5YJB6gQOzkUoNmJQc0rznwqSRpeaWWpjkWy2C/MPTcePpsKJEM26hXrOXl1+nceXg==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.6.1.tgz", + "integrity": "sha512-iBfKbyIoXS1FGdsKcZmnrxmbc8VcbMrSgD7AVrsnX+WyAYjmUDWvE93dt5D874qS4CCVu4O1JpbagHdXbbLiOw==", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", @@ -2474,13 +2474,13 @@ "license": "BSD-3-Clause" }, "node_modules/@intlify/core-base": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.0.tgz", - "integrity": "sha512-zJn0imh9HIsZZUtt9v8T16PeVstPv6bP2YzlrYJwoF8F30gs4brZBwW2KK6EI5WYKFi3NeqX6+UU4gniz5TkGg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-10.0.1.tgz", + "integrity": "sha512-6kpRGjhos95ph7QmEtP4tnWFTW102s71CLQAQwfsIGqOAcoJhzcYFpzIQ0gKXzqAIXsMD/hwM5qJ4ewqMHw3gg==", "license": "MIT", "dependencies": { - "@intlify/message-compiler": "9.14.0", - "@intlify/shared": "9.14.0" + "@intlify/message-compiler": "10.0.1", + "@intlify/shared": "10.0.1" }, "engines": { "node": ">= 16" @@ -2490,12 +2490,12 @@ } }, "node_modules/@intlify/message-compiler": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.14.0.tgz", - "integrity": "sha512-sXNsoMI0YsipSXW8SR75drmVK56tnJHoYbPXUv2Cf9lz6FzvwsosFm6JtC1oQZI/kU+n7qx0qRrEWkeYFTgETA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-10.0.1.tgz", + "integrity": "sha512-fPeykrcgVT5eOIlshTHiPCN8FV3AZyBOdMS3XaXzfQ6eL5wqfc29I/EdIv5YXVW5X8e/BgYeWjBC0Cuznsl/2g==", "license": "MIT", "dependencies": { - "@intlify/shared": "9.14.0", + "@intlify/shared": "10.0.1", "source-map-js": "^1.0.2" }, "engines": { @@ -2506,9 +2506,9 @@ } }, "node_modules/@intlify/shared": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.14.0.tgz", - "integrity": "sha512-r+N8KRQL7LgN1TMTs1A2svfuAU0J94Wu9wWdJVJqYsoMMLIeJxrPjazihfHpmJqfgZq0ah3Y9Q4pgWV2O90Fyg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.1.tgz", + "integrity": "sha512-b4h7IWdZl710DnAhET8lgfgZ4Y9A2IZx/gbli3Ec/zHtYCoPqLHmiM7kUNBrSZj7d/SSjcMMZHuz5I09x3PYZw==", "license": "MIT", "engines": { "node": ">= 16" @@ -2535,9 +2535,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "license": "MIT", "engines": { "node": ">=12" @@ -2731,12 +2731,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.46.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.46.1.tgz", - "integrity": "sha512-Fq6SwLujA/DOIvNC2EL/SojJnkKf/rAwJ//APpJJHRyMi1PdKrY3Az+4XNQ51N4RTbItbIByQ0jgd1tayq1aeA==", + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.0.tgz", + "integrity": "sha512-SgAdlSwYVpToI4e/IH19IHHWvoijAYH5hu2MWSXptRypLSnzj51PcGD+rsOXFayde4P9ZLi+loXVwArg6IUkCA==", "license": "Apache-2.0", "dependencies": { - "playwright": "1.46.1" + "playwright": "1.47.0" }, "bin": { "playwright": "cli.js" @@ -2784,9 +2784,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.1.tgz", - "integrity": "sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.3.tgz", + "integrity": "sha512-MmKSfaB9GX+zXl6E8z4koOr/xU63AMVleLEa64v7R0QF/ZloMs5vcD1sHgM64GXXS1csaJutG+ddtzcueI/BLg==", "cpu": [ "arm" ], @@ -2797,9 +2797,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.1.tgz", - "integrity": "sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.3.tgz", + "integrity": "sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==", "cpu": [ "arm64" ], @@ -2810,9 +2810,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.1.tgz", - "integrity": "sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.3.tgz", + "integrity": "sha512-P0UxIOrKNBFTQaXTxOH4RxuEBVCgEA5UTNV6Yz7z9QHnUJ7eLX9reOd/NYMO3+XZO2cco19mXTxDMXxit4R/eQ==", "cpu": [ "arm64" ], @@ -2823,9 +2823,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.1.tgz", - "integrity": "sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.3.tgz", + "integrity": "sha512-L1M0vKGO5ASKntqtsFEjTq/fD91vAqnzeaF6sfNAy55aD+Hi2pBI5DKwCO+UNDQHWsDViJLqshxOahXyLSh3EA==", "cpu": [ "x64" ], @@ -2836,9 +2836,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.1.tgz", - "integrity": "sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.3.tgz", + "integrity": "sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==", "cpu": [ "arm" ], @@ -2849,9 +2849,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.1.tgz", - "integrity": "sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.3.tgz", + "integrity": "sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==", "cpu": [ "arm" ], @@ -2862,9 +2862,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.1.tgz", - "integrity": "sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.3.tgz", + "integrity": "sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==", "cpu": [ "arm64" ], @@ -2875,9 +2875,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.1.tgz", - "integrity": "sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.3.tgz", + "integrity": "sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==", "cpu": [ "arm64" ], @@ -2888,9 +2888,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.1.tgz", - "integrity": "sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.3.tgz", + "integrity": "sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==", "cpu": [ "ppc64" ], @@ -2901,9 +2901,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.1.tgz", - "integrity": "sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.3.tgz", + "integrity": "sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==", "cpu": [ "riscv64" ], @@ -2914,9 +2914,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.1.tgz", - "integrity": "sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.3.tgz", + "integrity": "sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==", "cpu": [ "s390x" ], @@ -2927,9 +2927,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.1.tgz", - "integrity": "sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.3.tgz", + "integrity": "sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==", "cpu": [ "x64" ], @@ -2940,9 +2940,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.1.tgz", - "integrity": "sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.3.tgz", + "integrity": "sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==", "cpu": [ "x64" ], @@ -2953,9 +2953,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.1.tgz", - "integrity": "sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.3.tgz", + "integrity": "sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==", "cpu": [ "arm64" ], @@ -2966,9 +2966,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.1.tgz", - "integrity": "sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.3.tgz", + "integrity": "sha512-nMIdKnfZfzn1Vsk+RuOvl43ONTZXoAPUUxgcU0tXooqg4YrAqzfKzVenqqk2g5efWh46/D28cKFrOzDSW28gTA==", "cpu": [ "ia32" ], @@ -2979,9 +2979,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.1.tgz", - "integrity": "sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.3.tgz", + "integrity": "sha512-fOvu7PCQjAj4eWDEuD8Xz5gpzFqXzGlxHZozHP4b9Jxv9APtdxL6STqztDzMLuRXEc4UpXGGhx029Xgm91QBeA==", "cpu": [ "x64" ], @@ -2991,6 +2991,12 @@ "win32" ] }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "license": "MIT" + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -3086,9 +3092,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz", - "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==", + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -3327,22 +3333,22 @@ "license": "ISC" }, "node_modules/@unhead/dom": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.10.0.tgz", - "integrity": "sha512-LdgtOlyMHOyuQNsUKM+1d8ViiiY4LxjCPJlgUU/5CwgqeRYf4LWFu8oRMQfSQVTusbPwwvr3MolM9iTUu2I4BQ==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.11.2.tgz", + "integrity": "sha512-e5Ilqa1ktwGJGhFt3jEI78LywNuvqOR4GdEa+sV2OuKbldWBoS8DosCf7jzwEIPYgn2ubDQ0ygn9JH+m/x88gA==", "license": "MIT", "dependencies": { - "@unhead/schema": "1.10.0", - "@unhead/shared": "1.10.0" + "@unhead/schema": "1.11.2", + "@unhead/shared": "1.11.2" }, "funding": { "url": "https://github.com/sponsors/harlan-zw" } }, "node_modules/@unhead/schema": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@unhead/schema/-/schema-1.10.0.tgz", - "integrity": "sha512-hmgkFdLzm/VPLAXBF89Iry4Wz/6FpHMfMKCnAdihAt1Ublsi04RrA0hQuAiuGG2CZiKL4VCxtmV++UXj/kyakA==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@unhead/schema/-/schema-1.11.2.tgz", + "integrity": "sha512-ALyIIA0084JjGQJD6tJetQdqVNw/V6d2LaCC06jSm+JUqxsRWRZcSbNZUg5xr0T4xQPrefZYrGp76PbOdotPbQ==", "license": "MIT", "dependencies": { "hookable": "^5.5.3", @@ -3353,27 +3359,28 @@ } }, "node_modules/@unhead/shared": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@unhead/shared/-/shared-1.10.0.tgz", - "integrity": "sha512-Lv7pP0AoWJy+YaiWd4kGD+TK78ahPUwnIRx6YCC6FjPmE0KCqooeDS4HbInYaklLlEMQZislXyIwLczK2DTWiw==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@unhead/shared/-/shared-1.11.2.tgz", + "integrity": "sha512-Zg56xBrqkr9f9m3/+G/2CzbLba6g3/M2myWmyuZtn/ncUk3K2IXvXvlZAzMHx4yO++Xeik2QUWpHEdXRh+PxAA==", "license": "MIT", "dependencies": { - "@unhead/schema": "1.10.0" + "@unhead/schema": "1.11.2" }, "funding": { "url": "https://github.com/sponsors/harlan-zw" } }, "node_modules/@unhead/vue": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-1.10.0.tgz", - "integrity": "sha512-Cv9BViaOwCBdXy3bsTvJ10Rs808FSSq/ZfeBXzOjOxt08sbubf6Mr5opBdOlv/i1bzyFVIAqe5ABmrhC9mB80w==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-1.11.2.tgz", + "integrity": "sha512-m4GnwOd1ltXiSxp4ahIT6lziVyg6dgqKyLyWxrRWuPjZ8nXsPcpIOCjVwYB1MK0UBKMuIlgeuzVeDrTY9+APbA==", "license": "MIT", "dependencies": { - "@unhead/schema": "1.10.0", - "@unhead/shared": "1.10.0", + "@unhead/schema": "1.11.2", + "@unhead/shared": "1.11.2", + "defu": "^6.1.4", "hookable": "^5.5.3", - "unhead": "1.10.0" + "unhead": "1.11.2" }, "funding": { "url": "https://github.com/sponsors/harlan-zw" @@ -3409,9 +3416,9 @@ } }, "node_modules/@vitejs/plugin-vue": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.2.tgz", - "integrity": "sha512-nY9IwH12qeiJqumTCLJLE7IiNx7HZ39cbHaysEUd+Myvbz9KAqd2yq+U01Kab1R/H1BmiyM2ShTYlNH32Fzo3A==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.3.tgz", + "integrity": "sha512-3xbWsKEKXYlmX82aOHufFQVnkbMC/v8fLpWwh6hWOUrK5fbbtBh9Q/WWse27BFgSy2/e2c0fz5Scgya9h2GLhw==", "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" @@ -3422,13 +3429,13 @@ } }, "node_modules/@vitest/expect": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.0.5.tgz", - "integrity": "sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.0.tgz", + "integrity": "sha512-N3/xR4fSu0+6sVZETEtPT1orUs2+Y477JOXTcU3xKuu3uBlsgbD7/7Mz2LZ1Jr1XjwilEWlrIgSCj4N1+5ZmsQ==", "license": "MIT", "dependencies": { - "@vitest/spy": "2.0.5", - "@vitest/utils": "2.0.5", + "@vitest/spy": "2.1.0", + "@vitest/utils": "2.1.0", "chai": "^5.1.1", "tinyrainbow": "^1.2.0" }, @@ -3436,10 +3443,46 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/mocker": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.0.tgz", + "integrity": "sha512-ZxENovUqhzl+QiOFpagiHUNUuZ1qPd5yYTCYHomGIZOFArzn4mgX2oxZmiAItJWAaXHG6bbpb/DpSPhlk5DgtA==", + "license": "MIT", + "dependencies": { + "@vitest/spy": "^2.1.0-beta.1", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.11" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/spy": "2.1.0", + "msw": "^2.3.5", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/@vitest/pretty-format": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.0.5.tgz", - "integrity": "sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.0.tgz", + "integrity": "sha512-7sxf2F3DNYatgmzXXcTh6cq+/fxwB47RIQqZJFoSH883wnVAoccSRT6g+dTKemUBo8Q5N4OYYj1EBXLuRKvp3Q==", "license": "MIT", "dependencies": { "tinyrainbow": "^1.2.0" @@ -3449,12 +3492,12 @@ } }, "node_modules/@vitest/runner": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.0.5.tgz", - "integrity": "sha512-TfRfZa6Bkk9ky4tW0z20WKXFEwwvWhRY+84CnSEtq4+3ZvDlJyY32oNTJtM7AW9ihW90tX/1Q78cb6FjoAs+ig==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.0.tgz", + "integrity": "sha512-D9+ZiB8MbMt7qWDRJc4CRNNUlne/8E1X7dcKhZVAbcOKG58MGGYVDqAq19xlhNfMFZsW0bpVKgztBwks38Ko0w==", "license": "MIT", "dependencies": { - "@vitest/utils": "2.0.5", + "@vitest/utils": "2.1.0", "pathe": "^1.1.2" }, "funding": { @@ -3462,13 +3505,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.0.5.tgz", - "integrity": "sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.0.tgz", + "integrity": "sha512-x69CygGMzt9VCO283K2/FYQ+nBrOj66OTKpsPykjCR4Ac3lLV+m85hj9reaIGmjBSsKzVvbxWmjWE3kF5ha3uQ==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.0.5", - "magic-string": "^0.30.10", + "@vitest/pretty-format": "2.1.0", + "magic-string": "^0.30.11", "pathe": "^1.1.2" }, "funding": { @@ -3476,9 +3519,9 @@ } }, "node_modules/@vitest/spy": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.0.5.tgz", - "integrity": "sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.0.tgz", + "integrity": "sha512-IXX5NkbdgTYTog3F14i2LgnBc+20YmkXMx0IWai84mcxySUDRgm0ihbOfR4L0EVRBDFG85GjmQQEZNNKVVpkZw==", "license": "MIT", "dependencies": { "tinyspy": "^3.0.0" @@ -3488,13 +3531,12 @@ } }, "node_modules/@vitest/utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.0.5.tgz", - "integrity": "sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.0.tgz", + "integrity": "sha512-rreyfVe0PuNqJfKYUwfPDfi6rrp0VSu0Wgvp5WBqJonP+4NvXHk48X6oBam1Lj47Hy6jbJtnMj3OcRdrkTP0tA==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.0.5", - "estree-walker": "^3.0.3", + "@vitest/pretty-format": "2.1.0", "loupe": "^3.1.1", "tinyrainbow": "^1.2.0" }, @@ -3502,69 +3544,60 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/utils/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, "node_modules/@vue/compiler-core": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.38.tgz", - "integrity": "sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.4.tgz", + "integrity": "sha512-oNwn+BAt3n9dK9uAYvI+XGlutwuTq/wfj4xCBaZCqwwVIGtD7D6ViihEbyYZrDHIHTDE3Q6oL3/hqmAyFEy9DQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.24.7", - "@vue/shared": "3.4.38", + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.4", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.38.tgz", - "integrity": "sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.4.tgz", + "integrity": "sha512-yP9RRs4BDLOLfldn6ah+AGCNovGjMbL9uHvhDHf5wan4dAHLnFGOkqtfE7PPe4HTXIqE7l/NILdYw53bo1C8jw==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.4.38", - "@vue/shared": "3.4.38" + "@vue/compiler-core": "3.5.4", + "@vue/shared": "3.5.4" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.38.tgz", - "integrity": "sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.4.tgz", + "integrity": "sha512-P+yiPhL+NYH7m0ZgCq7AQR2q7OIE+mpAEgtkqEeH9oHSdIRvUO+4X6MPvblJIWcoe4YC5a2Gdf/RsoyP8FFiPQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.24.7", - "@vue/compiler-core": "3.4.38", - "@vue/compiler-dom": "3.4.38", - "@vue/compiler-ssr": "3.4.38", - "@vue/shared": "3.4.38", + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.4", + "@vue/compiler-dom": "3.5.4", + "@vue/compiler-ssr": "3.5.4", + "@vue/shared": "3.5.4", "estree-walker": "^2.0.2", - "magic-string": "^0.30.10", - "postcss": "^8.4.40", + "magic-string": "^0.30.11", + "postcss": "^8.4.44", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.38.tgz", - "integrity": "sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.4.tgz", + "integrity": "sha512-acESdTXsxPnYr2C4Blv0ggx5zIFMgOzZmYU2UgvIff9POdRGbRNBHRyzHAnizcItvpgerSKQbllUc9USp3V7eg==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.4.38", - "@vue/shared": "3.4.38" + "@vue/compiler-dom": "3.5.4", + "@vue/shared": "3.5.4" } }, "node_modules/@vue/devtools-api": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.3.tgz", - "integrity": "sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==", + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", "license": "MIT" }, "node_modules/@vue/eslint-config-prettier": { @@ -3606,53 +3639,53 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.38.tgz", - "integrity": "sha512-4vl4wMMVniLsSYYeldAKzbk72+D3hUnkw9z8lDeJacTxAkXeDAP1uE9xr2+aKIN0ipOL8EG2GPouVTH6yF7Gnw==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.4.tgz", + "integrity": "sha512-HKKbEuP7tYSGCq4e4nK6ZW6l5hyG66OUetefBp4budUyjvAYsnQDf+bgFzg2RAgnH0CInyqXwD9y47jwJEHrQw==", "license": "MIT", "dependencies": { - "@vue/shared": "3.4.38" + "@vue/shared": "3.5.4" } }, "node_modules/@vue/runtime-core": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.38.tgz", - "integrity": "sha512-21z3wA99EABtuf+O3IhdxP0iHgkBs1vuoCAsCKLVJPEjpVqvblwBnTj42vzHRlWDCyxu9ptDm7sI2ZMcWrQqlA==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.4.tgz", + "integrity": "sha512-f3ek2sTA0AFu0n+w+kCtz567Euqqa3eHewvo4klwS7mWfSj/A+UmYTwsnUFo35KeyAFY60JgrCGvEBsu1n/3LA==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.4.38", - "@vue/shared": "3.4.38" + "@vue/reactivity": "3.5.4", + "@vue/shared": "3.5.4" } }, "node_modules/@vue/runtime-dom": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.38.tgz", - "integrity": "sha512-afZzmUreU7vKwKsV17H1NDThEEmdYI+GCAK/KY1U957Ig2NATPVjCROv61R19fjZNzMmiU03n79OMnXyJVN0UA==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.4.tgz", + "integrity": "sha512-ofyc0w6rbD5KtjhP1i9hGOKdxGpvmuB1jprP7Djlj0X7R5J/oLwuNuE98GJ8WW31Hu2VxQHtk/LYTAlW8xrJdw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.4.38", - "@vue/runtime-core": "3.4.38", - "@vue/shared": "3.4.38", + "@vue/reactivity": "3.5.4", + "@vue/runtime-core": "3.5.4", + "@vue/shared": "3.5.4", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.38.tgz", - "integrity": "sha512-NggOTr82FbPEkkUvBm4fTGcwUY8UuTsnWC/L2YZBmvaQ4C4Jl/Ao4HHTB+l7WnFCt5M/dN3l0XLuyjzswGYVCA==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.4.tgz", + "integrity": "sha512-FbjV6DJLgKRetMYFBA1UXCroCiED/Ckr53/ba9wivyd7D/Xw9fpo0T6zXzCnxQwyvkyrL7y6plgYhWhNjGxY5g==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.4.38", - "@vue/shared": "3.4.38" + "@vue/compiler-ssr": "3.5.4", + "@vue/shared": "3.5.4" }, "peerDependencies": { - "vue": "3.4.38" + "vue": "3.5.4" } }, "node_modules/@vue/shared": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.38.tgz", - "integrity": "sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.4.tgz", + "integrity": "sha512-L2MCDD8l7yC62Te5UUyPVpmexhL9ipVnYRw9CsWfm/BGRL5FwDX4a25bcJ/OJSD3+Hx+k/a8LDKcG2AFdJV3BA==", "license": "MIT" }, "node_modules/@vue/test-utils": { @@ -3719,9 +3752,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -3952,9 +3985,9 @@ } }, "node_modules/axios": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", - "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -4029,9 +4062,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -4042,7 +4075,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -4227,9 +4260,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001653", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz", - "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==", + "version": "1.0.30001660", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz", + "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==", "funding": [ { "type": "opencollective", @@ -4706,12 +4739,12 @@ } }, "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -4931,9 +4964,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.13", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", - "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", + "version": "1.5.22", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.22.tgz", + "integrity": "sha512-tKYm5YHPU1djz0O+CGJ+oJIvimtsCcwR2Z9w7Skh08lUdyzXY5djods3q+z2JkWdb7tCcmM//eVavSRAiaPRNg==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -5135,9 +5168,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", "engines": { "node": ">=6" @@ -5267,9 +5300,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.2.tgz", - "integrity": "sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz", + "integrity": "sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ==", "license": "MIT", "dependencies": { "debug": "^3.2.7" @@ -5312,26 +5345,27 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", + "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", "license": "MIT", "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", "array.prototype.flat": "^1.3.2", "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", + "eslint-module-utils": "^2.9.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", "semver": "^6.3.1", "tsconfig-paths": "^3.15.0" }, @@ -5473,9 +5507,9 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "9.27.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.27.0.tgz", - "integrity": "sha512-5Dw3yxEyuBSXTzT5/Ge1X5kIkRTQ3nvBn/VwPwInNiZBSJOO/timWMUaflONnFBzU6NhB68lxnCda7ULV5N7LA==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.28.0.tgz", + "integrity": "sha512-ShrihdjIhOTxs+MfWun6oJWuk+g/LAhN+CiuOl/jjkG3l0F2AuK5NMTaWqyvBgkFtpYmyks6P4603mLmhNJW8g==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", @@ -5483,7 +5517,7 @@ "natural-compare": "^1.4.0", "nth-check": "^2.1.1", "postcss-selector-parser": "^6.0.15", - "semver": "^7.6.0", + "semver": "^7.6.3", "vue-eslint-parser": "^9.4.3", "xml-name-validator": "^4.0.0" }, @@ -5782,29 +5816,6 @@ "node": ">=0.10.0" } }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, "node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", @@ -5978,9 +5989,9 @@ "license": "Apache-2.0" }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "funding": [ { "type": "individual", @@ -6152,18 +6163,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-symbol-description": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", @@ -6319,9 +6318,9 @@ } }, "node_modules/happy-dom": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.0.0.tgz", - "integrity": "sha512-DsvANUcxxY20iCo3Yllm7dqwzPVPduGfVFxa7mONwMBLczFeQgkN0LpDir1kIY322JMh+hrcPV3aGLyHCESDlA==", + "version": "15.7.4", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.7.4.tgz", + "integrity": "sha512-r1vadDYGMtsHAAsqhDuk4IpPvr6N8MGKy5ntBo7tSdim+pWDxus2PNqOcOt8LuDZ4t3KJHE+gCuzupcx/GKnyQ==", "license": "MIT", "dependencies": { "entities": "^4.5.0", @@ -6538,15 +6537,6 @@ "node": ">= 6" } }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=16.17.0" - } - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -6879,18 +6869,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -7175,9 +7153,9 @@ } }, "node_modules/launch-editor": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.1.tgz", - "integrity": "sha512-elBx2l/tp9z99X5H/qev8uyDywVh0VXAwEbjk8kJhnc5grOFkGh7aW6q55me9xnYbss261XtnUrysZ+XvGbhQA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", "license": "MIT", "dependencies": { "picocolors": "^1.0.0", @@ -7370,12 +7348,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -7419,18 +7391,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -7502,9 +7462,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/nanoid": { @@ -7571,33 +7531,6 @@ "node": ">=0.10.0" } }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -7725,21 +7658,6 @@ "wrappy": "1" } }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/open": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", @@ -7953,9 +7871,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "license": "ISC" }, "node_modules/picomatch": { @@ -7982,12 +7900,12 @@ } }, "node_modules/playwright": { - "version": "1.46.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.1.tgz", - "integrity": "sha512-oPcr1yqoXLCkgKtD5eNUPLiN40rYEM39odNpIb6VE6S7/15gJmA1NzVv6zJYusV0e7tzvkU/utBFNa/Kpxmwng==", + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.0.tgz", + "integrity": "sha512-jOWiRq2pdNAX/mwLiwFYnPHpEZ4rM+fRSQpRHwEwZlP2PUANvL3+aJOF/bvISMhFD30rqMxUB4RJx9aQbfh4Ww==", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.46.1" + "playwright-core": "1.47.0" }, "bin": { "playwright": "cli.js" @@ -8000,9 +7918,9 @@ } }, "node_modules/playwright-core": { - "version": "1.46.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.1.tgz", - "integrity": "sha512-h9LqIQaAv+CYvWzsZ+h3RsrqCStkBHlgo6/TJlFst3cOTlLghBQlJwPOZKQJTKNaD3QIB7aAVQ+gfWbN3NXB7A==", + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.0.tgz", + "integrity": "sha512-1DyHT8OqkcfCkYUD9zzUTfg7EfTd+6a8MkD/NWOvjo0u/SCNd5YmY/lJwFvUZOxJbWNds+ei7ic2+R/cRz/PDg==", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -8035,9 +7953,9 @@ } }, "node_modules/postcss": { - "version": "8.4.41", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", - "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", + "version": "8.4.45", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz", + "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==", "funding": [ { "type": "opencollective", @@ -8157,12 +8075,12 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -8231,9 +8149,9 @@ "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "license": "MIT", "dependencies": { "regenerate": "^1.4.2" @@ -8435,9 +8353,9 @@ } }, "node_modules/rollup": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.1.tgz", - "integrity": "sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.3.tgz", + "integrity": "sha512-7sqRtBNnEbcBtMeRVc6VRsJMmpI+JU1z9VTvW8D4gXIYQFz0aLcsE6rRkyghZkLfEgUZgVvOG7A5CVz/VW5GIA==", "license": "MIT", "dependencies": { "@types/estree": "1.0.5" @@ -8450,22 +8368,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.21.1", - "@rollup/rollup-android-arm64": "4.21.1", - "@rollup/rollup-darwin-arm64": "4.21.1", - "@rollup/rollup-darwin-x64": "4.21.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.21.1", - "@rollup/rollup-linux-arm-musleabihf": "4.21.1", - "@rollup/rollup-linux-arm64-gnu": "4.21.1", - "@rollup/rollup-linux-arm64-musl": "4.21.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.21.1", - "@rollup/rollup-linux-riscv64-gnu": "4.21.1", - "@rollup/rollup-linux-s390x-gnu": "4.21.1", - "@rollup/rollup-linux-x64-gnu": "4.21.1", - "@rollup/rollup-linux-x64-musl": "4.21.1", - "@rollup/rollup-win32-arm64-msvc": "4.21.1", - "@rollup/rollup-win32-ia32-msvc": "4.21.1", - "@rollup/rollup-win32-x64-msvc": "4.21.1", + "@rollup/rollup-android-arm-eabi": "4.21.3", + "@rollup/rollup-android-arm64": "4.21.3", + "@rollup/rollup-darwin-arm64": "4.21.3", + "@rollup/rollup-darwin-x64": "4.21.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.21.3", + "@rollup/rollup-linux-arm-musleabihf": "4.21.3", + "@rollup/rollup-linux-arm64-gnu": "4.21.3", + "@rollup/rollup-linux-arm64-musl": "4.21.3", + "@rollup/rollup-linux-powerpc64le-gnu": "4.21.3", + "@rollup/rollup-linux-riscv64-gnu": "4.21.3", + "@rollup/rollup-linux-s390x-gnu": "4.21.3", + "@rollup/rollup-linux-x64-gnu": "4.21.3", + "@rollup/rollup-linux-x64-musl": "4.21.3", + "@rollup/rollup-win32-arm64-msvc": "4.21.3", + "@rollup/rollup-win32-ia32-msvc": "4.21.3", + "@rollup/rollup-win32-x64-msvc": "4.21.3", "fsevents": "~2.3.2" } }, @@ -8812,9 +8730,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -8903,9 +8821,9 @@ "license": "MIT" }, "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "license": "MIT", "engines": { "node": ">=12" @@ -9021,18 +8939,6 @@ "node": ">=0.10.0" } }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -9104,9 +9010,9 @@ "license": "MIT" }, "node_modules/terser": { - "version": "5.31.6", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", - "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.32.0.tgz", + "integrity": "sha512-v3Gtw3IzpBJ0ugkxEX8U0W6+TnPKRRCWGh1jC/iM/e3Ki5+qvO1L1EAZ56bZasc64aXHwRHNIQEzm6//i5cemQ==", "license": "BSD-2-Clause", "peer": true, "dependencies": { @@ -9141,6 +9047,12 @@ "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "license": "MIT" }, + "node_modules/tinyexec": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.0.tgz", + "integrity": "sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==", + "license": "MIT" + }, "node_modules/tinypool": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz", @@ -9160,9 +9072,9 @@ } }, "node_modules/tinyspy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.0.tgz", - "integrity": "sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -9411,9 +9323,9 @@ } }, "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -9457,14 +9369,14 @@ "license": "MIT" }, "node_modules/unhead": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/unhead/-/unhead-1.10.0.tgz", - "integrity": "sha512-nv75Hvhu0asuD/rbP6b3tSRJUltxmThq/iZU5rLCGEkCqTkFk7ruQGNk+TRtx/RCYqL0R/IzIY9aqvhNOGe3mg==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/unhead/-/unhead-1.11.2.tgz", + "integrity": "sha512-k/MA5yzPh5M4pksDzOXf2GBJn0XV4quWao1q173NF7NL3Ji4RQ3ZxvZcwA/nGr7wu3+twJIRoKti3Otc4JMNyw==", "license": "MIT", "dependencies": { - "@unhead/dom": "1.10.0", - "@unhead/schema": "1.10.0", - "@unhead/shared": "1.10.0", + "@unhead/dom": "1.11.2", + "@unhead/schema": "1.11.2", + "@unhead/shared": "1.11.2", "hookable": "^5.5.3" }, "funding": { @@ -9472,9 +9384,9 @@ } }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "license": "MIT", "engines": { "node": ">=4" @@ -9494,9 +9406,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "license": "MIT", "engines": { "node": ">=4" @@ -9612,13 +9524,13 @@ } }, "node_modules/vite": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz", - "integrity": "sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.5.tgz", + "integrity": "sha512-pXqR0qtb2bTwLkev4SE3r4abCNioP3GkjvIDLlzziPpXtHgiJIjuKl+1GN6ESOT3wMjG3JTeARopj2SwYaHTOA==", "license": "MIT", "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.41", + "postcss": "^8.4.43", "rollup": "^4.20.0" }, "bin": { @@ -9710,29 +9622,29 @@ } }, "node_modules/vitest": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.0.5.tgz", - "integrity": "sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.0.tgz", + "integrity": "sha512-XuuEeyNkqbfr0FtAvd9vFbInSSNY1ykCQTYQ0sj9wPy4hx+1gR7gqVNdW0AX2wrrM1wWlN5fnJDjF9xG6mYRSQ==", "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.3.0", - "@vitest/expect": "2.0.5", - "@vitest/pretty-format": "^2.0.5", - "@vitest/runner": "2.0.5", - "@vitest/snapshot": "2.0.5", - "@vitest/spy": "2.0.5", - "@vitest/utils": "2.0.5", + "@vitest/expect": "2.1.0", + "@vitest/mocker": "2.1.0", + "@vitest/pretty-format": "^2.1.0", + "@vitest/runner": "2.1.0", + "@vitest/snapshot": "2.1.0", + "@vitest/spy": "2.1.0", + "@vitest/utils": "2.1.0", "chai": "^5.1.1", - "debug": "^4.3.5", - "execa": "^8.0.1", - "magic-string": "^0.30.10", + "debug": "^4.3.6", + "magic-string": "^0.30.11", "pathe": "^1.1.2", "std-env": "^3.7.0", - "tinybench": "^2.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.0", "tinypool": "^1.0.0", "tinyrainbow": "^1.2.0", "vite": "^5.0.0", - "vite-node": "2.0.5", + "vite-node": "2.1.0", "why-is-node-running": "^2.3.0" }, "bin": { @@ -9747,8 +9659,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "2.0.5", - "@vitest/ui": "2.0.5", + "@vitest/browser": "2.1.0", + "@vitest/ui": "2.1.0", "happy-dom": "*", "jsdom": "*" }, @@ -9774,15 +9686,14 @@ } }, "node_modules/vitest/node_modules/vite-node": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.0.5.tgz", - "integrity": "sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.0.tgz", + "integrity": "sha512-+ybYqBVUjYyIscoLzMWodus2enQDZOpGhcU6HdOVD6n8WZdk12w1GFL3mbnxLs7hPtRtqs1Wo5YF6/Tsr6fmhg==", "license": "MIT", "dependencies": { "cac": "^6.7.14", - "debug": "^4.3.5", + "debug": "^4.3.6", "pathe": "^1.1.2", - "tinyrainbow": "^1.2.0", "vite": "^5.0.0" }, "bin": { @@ -9796,16 +9707,16 @@ } }, "node_modules/vue": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.38.tgz", - "integrity": "sha512-f0ZgN+mZ5KFgVv9wz0f4OgVKukoXtS3nwET4c2vLBGQR50aI8G0cqbFtLlX9Yiyg3LFGBitruPHt2PxwTduJEw==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.4.tgz", + "integrity": "sha512-3yAj2gkmiY+i7+22A1PWM+kjOVXjU74UPINcTiN7grIVPyFFI0lpGwHlV/4xydDmobaBn7/xmi+YG8HeSlCTcg==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.4.38", - "@vue/compiler-sfc": "3.4.38", - "@vue/runtime-dom": "3.4.38", - "@vue/server-renderer": "3.4.38", - "@vue/shared": "3.4.38" + "@vue/compiler-dom": "3.5.4", + "@vue/compiler-sfc": "3.5.4", + "@vue/runtime-dom": "3.5.4", + "@vue/server-renderer": "3.5.4", + "@vue/shared": "3.5.4" }, "peerDependencies": { "typescript": "*" @@ -9817,9 +9728,9 @@ } }, "node_modules/vue-component-type-helpers": { - "version": "2.0.29", - "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.0.29.tgz", - "integrity": "sha512-58i+ZhUAUpwQ+9h5Hck0D+jr1qbYl4voRt5KffBx8qzELViQ4XdT/Tuo+mzq8u63teAG8K0lLaOiL5ofqW38rg==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.1.6.tgz", + "integrity": "sha512-ng11B8B/ZADUMMOsRbqv0arc442q7lifSubD0v8oDXIFoMg/mXwAPUunrroIDkY+mcD0dHKccdaznSVp8EoX3w==", "license": "MIT" }, "node_modules/vue-eslint-parser": { @@ -9865,13 +9776,13 @@ "license": "MIT" }, "node_modules/vue-i18n": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.14.0.tgz", - "integrity": "sha512-LxmpRuCt2rI8gqU+kxeflRZMQn4D5+4M3oP3PWZdowW/ePJraHqhF7p4CuaME52mUxdw3Mmy2yAUKgfZYgCRjA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-10.0.1.tgz", + "integrity": "sha512-SQVlSm/1S6AaG1wexvwq3ebXUrrkx75ZHD78UAs4/rYD/X3tsQxfm6ElpT4ZPegJQEgRtOJjGripqSrfqAENtg==", "license": "MIT", "dependencies": { - "@intlify/core-base": "9.14.0", - "@intlify/shared": "9.14.0", + "@intlify/core-base": "10.0.1", + "@intlify/shared": "10.0.1", "@vue/devtools-api": "^6.5.0" }, "engines": { @@ -9885,12 +9796,12 @@ } }, "node_modules/vue-router": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.3.tgz", - "integrity": "sha512-sv6wmNKx2j3aqJQDMxLFzs/u/mjA9Z5LCgy6BE0f7yFWMjrPLnS/sPNn8ARY/FXw6byV18EFutn5lTO6+UsV5A==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.5.tgz", + "integrity": "sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==", "license": "MIT", "dependencies": { - "@vue/devtools-api": "^6.6.3" + "@vue/devtools-api": "^6.6.4" }, "funding": { "url": "https://github.com/sponsors/posva" @@ -9918,12 +9829,12 @@ } }, "node_modules/wait-on": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-8.0.0.tgz", - "integrity": "sha512-fNE5SXinLr2Bt7cJvjvLg2PcXfqznlqRvtE3f8AqYdRZ9BhE+XpsCp1mwQbRoO7s1q7uhAuCw0Ro3mG/KdZjEw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-8.0.1.tgz", + "integrity": "sha512-1wWQOyR2LVVtaqrcIL2+OM+x7bkpmzVROa0Nf6FryXkS+er5Sa1kzFGjzZRqLnHa3n1rACFLeTwUqE1ETL9Mig==", "license": "MIT", "dependencies": { - "axios": "^1.7.4", + "axios": "^1.7.7", "joi": "^17.13.3", "lodash": "^4.17.21", "minimist": "^1.2.8", @@ -10155,9 +10066,9 @@ } }, "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "license": "MIT", "engines": { "node": ">=12" diff --git a/package.json b/package.json index b04865ddad..49d90ed1b6 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "vue": "^3.2.29", "vue-eslint-parser": "^9.1.0", "vue-hot-reload-api": "^2.3.4", - "vue-i18n": "^9.2.2", + "vue-i18n": "^10.0.1", "vue-router": "^4.0.12", "wait-on": "^8.0.0" }, From 3b3ac4df59a50279e24abfc2c37e05f1d7acbf4f Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 14:37:24 +0200 Subject: [PATCH 017/116] Saj-H2: add battery control (#15988) --- templates/definition/meter/saj-h2.yaml | 110 +++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/templates/definition/meter/saj-h2.yaml b/templates/definition/meter/saj-h2.yaml index 6eec38791d..f7a890544e 100644 --- a/templates/definition/meter/saj-h2.yaml +++ b/templates/definition/meter/saj-h2.yaml @@ -15,6 +15,18 @@ params: comset: 8N1 - name: capacity advanced: true + # battery control + - name: defaultmode + default: 2 + advanced: true + - name: minsoc + type: number + default: 20 + advanced: true + - name: maxsoc + type: number + default: 95 + advanced: true render: | type: custom {{- if eq .usage "grid" }} @@ -97,5 +109,103 @@ render: | type: holding decode: uint16 scale: 0.01 + batterymode: + source: switch + switch: + - case: 1 # normal + set: + source: sequence + set: + - source: const + value: {{ .defaultmode }} + set: + source: modbus + {{- include "modbus" . | indent 10 }} + register: + address: 13895 # AppMode + type: writeholding + decode: int16 + - source: const + value: {{ .minsoc }} + set: + source: modbus + {{- include "modbus" . | indent 10 }} + register: + address: 13905 # BatSocLimitkeep + type: writeholding + decode: int16 + - case: 2 # hold + set: + source: sequence + set: + - source: const + value: {{ .defaultmode }} + set: + source: modbus + {{- include "modbus" . | indent 10 }} + register: + address: 13895 # AppMode + type: writeholding + decode: int16 + - source: const + value: {{ .maxsoc }} + set: + source: modbus + {{- include "modbus" . | indent 10 }} + register: + address: 13905 # BatSocLimitkeep + type: writeholding + decode: int16 + - case: 3 # charge + set: + source: sequence + set: + - source: const + value: 1 # time_mode + set: + source: modbus + {{- include "modbus" . | indent 10 }} + register: + address: 13895 # AppMode + type: writeholding + decode: int16 + - source: const + value: 1 # enable + set: + source: modbus + {{- include "modbus" . | indent 10 }} + register: + address: 13828 # Charge_time_enable_control + type: writeholding + decode: int16 + - source: const + value: 0 # start (00:00) + set: + source: modbus + {{- include "modbus" . | indent 10 }} + register: + address: 13830 # First_charge_start_time + type: writeholding + decode: int16 + - source: const + value: 0x173B # end (23:59) + set: + source: modbus + {{- include "modbus" . | indent 10 }} + register: + address: 13831 # First_charge_end_time + type: writeholding + decode: int16 + - source: const + value: 0x7F64 # end (0xFF / 100%) + set: + source: modbus + {{- include "modbus" . | indent 10 }} + register: + address: 13832 # First_charge_power_time + type: writeholding + decode: int16 + minsoc: {{ .minsoc }} + maxsoc: {{ .maxsoc }} capacity: {{ .capacity }} # kWh {{- end }} From cbafc3e0c3566c619c6cc5b40fbcfb07594f5d4d Mon Sep 17 00:00:00 2001 From: premultiply <4681172+premultiply@users.noreply.github.com> Date: Sat, 14 Sep 2024 14:38:02 +0200 Subject: [PATCH 018/116] Ocpp: generate globally unique transaction ids (#15951) --- charger/ocpp/connector.go | 5 ++--- charger/ocpp/connector_core.go | 27 ++------------------------- charger/ocpp/cs.go | 12 +++++++++++- charger/ocpp/instance.go | 1 + 4 files changed, 16 insertions(+), 29 deletions(-) diff --git a/charger/ocpp/connector.go b/charger/ocpp/connector.go index 461e716d67..862b3f02c6 100644 --- a/charger/ocpp/connector.go +++ b/charger/ocpp/connector.go @@ -29,9 +29,8 @@ type Connector struct { meterUpdated time.Time measurements map[types.Measurand]types.SampledValue - txnCount int // change initial value to the last known global transaction. Needs persistence - txnId int - idTag string + txnId int + idTag string remoteIdTag string } diff --git a/charger/ocpp/connector_core.go b/charger/ocpp/connector_core.go index 66ddd38e6b..df0d38d2dd 100644 --- a/charger/ocpp/connector_core.go +++ b/charger/ocpp/connector_core.go @@ -64,7 +64,7 @@ func (conn *Connector) MeterValues(request *core.MeterValuesRequest) (*core.Mete (conn.status.Status == core.ChargePointStatusCharging || conn.status.Status == core.ChargePointStatusSuspendedEV || conn.status.Status == core.ChargePointStatusSuspendedEVSE) { - conn.log.DEBUG.Printf("hijacking transaction: %d", *request.TransactionId) + conn.log.DEBUG.Printf("recovered transaction: %d", *request.TransactionId) conn.txnId = *request.TransactionId } @@ -91,19 +91,7 @@ func (conn *Connector) StartTransaction(request *core.StartTransactionRequest) ( conn.mu.Lock() defer conn.mu.Unlock() - // expired request - if request.Timestamp != nil && conn.clock.Since(request.Timestamp.Time) > Timeout { - res := &core.StartTransactionConfirmation{ - IdTagInfo: &types.IdTagInfo{ - Status: types.AuthorizationStatusExpired, // reject - }, - } - - return res, nil - } - - conn.txnCount++ - conn.txnId = conn.txnCount + conn.txnId = instance.NewTransactionID() conn.idTag = request.IdTag res := &core.StartTransactionConfirmation{ @@ -140,17 +128,6 @@ func (conn *Connector) StopTransaction(request *core.StopTransactionRequest) (*c conn.mu.Lock() defer conn.mu.Unlock() - // expired request - if request.Timestamp != nil && conn.clock.Since(request.Timestamp.Time) > Timeout { - res := &core.StopTransactionConfirmation{ - IdTagInfo: &types.IdTagInfo{ - Status: types.AuthorizationStatusExpired, // reject - }, - } - - return res, nil - } - conn.txnId = 0 conn.idTag = "" diff --git a/charger/ocpp/cs.go b/charger/ocpp/cs.go index 70e0d19869..72be4ac001 100644 --- a/charger/ocpp/cs.go +++ b/charger/ocpp/cs.go @@ -13,7 +13,8 @@ type CS struct { mu sync.Mutex log *util.Logger ocpp16.CentralSystem - cps map[string]*CP + cps map[string]*CP + txnId int } // Register registers a charge point with the central system. @@ -106,3 +107,12 @@ func (cs *CS) ChargePointDisconnected(chargePoint ocpp16.ChargePointConnection) cp.connect(false) } } + +// NewTransactionID returns a CS-wide unique transactionId +func (cs *CS) NewTransactionID() int { + cs.mu.Lock() + defer cs.mu.Unlock() + + cs.txnId++ + return cs.txnId +} diff --git a/charger/ocpp/instance.go b/charger/ocpp/instance.go index 4220fc50c2..ec6315f132 100644 --- a/charger/ocpp/instance.go +++ b/charger/ocpp/instance.go @@ -42,6 +42,7 @@ func Instance() *CS { log: log, cps: make(map[string]*CP), CentralSystem: cs, + txnId: int(time.Now().UTC().Unix()), } ocppj.SetLogger(instance) From 62e252d2df11bee3a7adea43bde42fee2e5aa7e5 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 14:38:22 +0200 Subject: [PATCH 019/116] Smart Hello: add charge state (#15939) --- vehicle/smart/hello/provider.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/vehicle/smart/hello/provider.go b/vehicle/smart/hello/provider.go index 7935fd5307..115aad4fa8 100644 --- a/vehicle/smart/hello/provider.go +++ b/vehicle/smart/hello/provider.go @@ -30,6 +30,21 @@ func (v *Provider) Soc() (float64, error) { return float64(res.AdditionalVehicleStatus.ElectricVehicleStatus.ChargeLevel), err } +var _ api.ChargeState = (*Provider)(nil) + +// Status implements the api.ChargeState interface +func (v *Provider) Status() (api.ChargeStatus, error) { + res, err := v.statusG() + switch res.AdditionalVehicleStatus.ElectricVehicleStatus.ChargerState { + case 1, 3: + return api.StatusB, err + case 2: + return api.StatusC, err + default: + return api.StatusA, err + } +} + var _ api.VehicleRange = (*Provider)(nil) // Range implements the api.VehicleRange interface From 5f79df4f0e363b224609fe1ad30bbc021537c40e Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 16:54:43 +0200 Subject: [PATCH 020/116] Add Wattsonic (#16104) --- templates/definition/meter/wattsonic.yaml | 112 ++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 templates/definition/meter/wattsonic.yaml diff --git a/templates/definition/meter/wattsonic.yaml b/templates/definition/meter/wattsonic.yaml new file mode 100644 index 0000000000..d0d0b4e50e --- /dev/null +++ b/templates/definition/meter/wattsonic.yaml @@ -0,0 +1,112 @@ +template: wattsonic +products: + - brand: Wattsonic + - brand: Sunway + - brand: Solinteng + - brand: A-Tronix + - brand: St-ems +params: + - name: usage + choice: ["grid", "pv", "battery"] + allinone: true + - name: modbus + choice: ["rs485"] + port: 502 + id: 247 + - name: capacity + advanced: true + - name: delay + default: 100ms + advanced: true +render: | + type: custom + {{- if eq .usage "grid" }} + power: # power (W) + source: modbus + {{- include "modbus" . | indent 2 }} + delay: {{ .delay }} + register: + address: 11000 # Total Power on Meter + type: holding + decode: int32 + scale: -1 + currents: + - source: modbus + {{- include "modbus" . | indent 4 }} + delay: {{ .delay }} + register: + address: 11010 # Grid Phase A Current + type: holding + decode: uint16 + scale: 0.1 + - source: modbus + {{- include "modbus" . | indent 4 }} + delay: {{ .delay }} + register: + address: 11012 # Grid Phase B Current + type: holding + decode: uint16 + scale: 0.1 + - source: modbus + {{- include "modbus" . | indent 4 }} + delay: {{ .delay }} + register: + address: 11014 # Grid Phase C Current + type: holding + decode: uint16 + scale: 0.1 + powers: + - source: modbus + {{- include "modbus" . | indent 4 }} + delay: {{ .delay }} + register: + address: 10994 # Phase A Power on Meter + type: holding + decode: int32 + scale: -1 + - source: modbus + {{- include "modbus" . | indent 4 }} + delay: {{ .delay }} + register: + address: 10996 # Phase B Power on Meter + type: holding + decode: int32 + scale: -1 + - source: modbus + {{- include "modbus" . | indent 4 }} + delay: {{ .delay }} + register: + address: 10998 # Phase C Power on Meter + type: holding + decode: int32 + scale: -1 + {{- end }} + {{- if eq .usage "pv" }} + power: # power (W) + source: modbus + {{- include "modbus" . | indent 2 }} + delay: {{ .delay }} + register: + address: 11028 # PV Input Total Power + type: holding + decode: int32 + {{- end }} + {{- if eq .usage "battery" }} + power: # power (W) + source: modbus + {{- include "modbus" . | indent 2 }} + delay: {{ .delay }} + register: + address: 40258 # Total_Backup_P + type: holding + decode: int32 + soc: + source: modbus + {{- include "modbus" . | indent 2 }} + delay: {{ .delay }} + register: + address: 43000 # SOC + type: holding + decode: int16 + capacity: {{ .capacity }} # kWh + {{- end }} From b9aff6a6ebd2a04e17af2f071071a97851615f57 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 17:02:52 +0200 Subject: [PATCH 021/116] Revert "Keba: simplify Status() and fix StatusReason() (#16003)" This reverts commit 8b5d5bb2217a85873c3c0c92045bad7bfa4d86a4. --- charger/keba-modbus.go | 71 +++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 42 deletions(-) diff --git a/charger/keba-modbus.go b/charger/keba-modbus.go index 359767476a..2d4fa53629 100644 --- a/charger/keba-modbus.go +++ b/charger/keba-modbus.go @@ -167,68 +167,55 @@ func (wb *Keba) heartbeat(timeout time.Duration) { } } -func (wb *Keba) isConnected() (bool, error) { +// Status implements the api.Charger interface +func (wb *Keba) Status() (api.ChargeStatus, error) { b, err := wb.conn.ReadHoldingRegisters(kebaRegCableState, 2) + if err != nil { + return api.StatusNone, err + } - // 0: No cable is plugged. - // 1: Cable is connected to the charging station (not to the electric vehicle). - // 3: Cable is connected to the charging station and locked (not to the electric vehicle). - // 5: Cable is connected to the charging station and the electric vehicle (not locked). - // 7: Cable is connected to the charging station and the electric vehicle and locked (charging). - - return binary.BigEndian.Uint32(b)&5 != 0, err -} - -func (wb *Keba) getChargingState() (uint32, error) { - b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) - - // 0: Start-up of the charging station - // 1: The charging station is not ready for charging. The charging station is not connected to an electric vehicle, it is locked by the authorization function or another mechanism. - // 2: The charging station is ready for charging and waits for a reaction from the electric vehicle. - // 3: A charging process is active. - // 4: An error has occurred. - // 5: The charging process is temporarily interrupted because the temperature is too high or the wallbox is in suspended mode. + switch status := binary.BigEndian.Uint32(b); status { + case 0, 1, 3: + return api.StatusA, nil - return binary.BigEndian.Uint32(b), err -} + case 5: + return api.StatusB, nil -// Status implements the api.Charger interface -func (wb *Keba) Status() (api.ChargeStatus, error) { - if connected, err := wb.isConnected(); err != nil || !connected { - return api.StatusA, err - } + case 7: + b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) + if err != nil { + return api.StatusNone, err + } + if binary.BigEndian.Uint32(b) == 3 { + return api.StatusC, err + } + return api.StatusB, nil - s, err := wb.getChargingState() - if err != nil { - return api.StatusA, err + default: + return api.StatusNone, fmt.Errorf("invalid status: %d", status) } - if s == 3 { - return api.StatusC, nil - } - return api.StatusB, nil } // statusReason implements the api.StatusReasoner interface func (wb *Keba) statusReason() (api.Reason, error) { - if connected, err := wb.isConnected(); err != nil || !connected { - return api.ReasonUnknown, err - } + res := api.ReasonUnknown - if s, err := wb.getChargingState(); err != nil || s != 1 { - return api.ReasonUnknown, err + b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) + if err == nil && binary.BigEndian.Uint32(b) == 1 { + res = api.ReasonWaitingForAuthorization } - return api.ReasonWaitingForAuthorization, nil + return res, err } // Enabled implements the api.Charger interface func (wb *Keba) Enabled() (bool, error) { - s, err := wb.getChargingState() + b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) if err != nil { return false, err } - - return !(s == 5 || s == 1), nil + status := binary.BigEndian.Uint32(b) + return !(status == 5 || status == 1), nil } // Enable implements the api.Charger interface From 5430d22e1c663870a5b713717d59b88375ea09eb Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 17:06:41 +0200 Subject: [PATCH 022/116] Ocpp: extend logging --- charger/ocpp/cs_log.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/charger/ocpp/cs_log.go b/charger/ocpp/cs_log.go index 1a95cedb18..b4c6138317 100644 --- a/charger/ocpp/cs_log.go +++ b/charger/ocpp/cs_log.go @@ -2,19 +2,18 @@ package ocpp import ( "fmt" - "strings" ) func (cs *CS) print(s string) { - var ok bool - if s, ok = strings.CutPrefix(s, "sent JSON message to"); ok { - s = "send" + s - } else if s, ok = strings.CutPrefix(s, "received JSON message from"); ok { - s = "recv" + s - } - if ok { - cs.log.TRACE.Println(s) - } + // var ok bool + // if s, ok = strings.CutPrefix(s, "sent JSON message to"); ok { + // s = "send" + s + // } else if s, ok = strings.CutPrefix(s, "received JSON message from"); ok { + // s = "recv" + s + // } + // if ok { + cs.log.TRACE.Println(s) + // } } func (cs *CS) Debug(args ...interface{}) { From 54846df2b04123292073ba7472f6a35100057806 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 20:29:06 +0200 Subject: [PATCH 023/116] chore: use rand/v2 --- provider/mqtt/client.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/provider/mqtt/client.go b/provider/mqtt/client.go index 69702b7d68..c8b195739f 100644 --- a/provider/mqtt/client.go +++ b/provider/mqtt/client.go @@ -3,7 +3,7 @@ package mqtt import ( "crypto/tls" "fmt" - "math/rand" + "math/rand/v2" "strings" "sync" "sync/atomic" @@ -20,8 +20,7 @@ var Instance *Client // ClientID created unique mqtt client id func ClientID() string { - pid := rand.Int31() - return fmt.Sprintf("evcc-%d", pid) + return fmt.Sprintf("evcc-%d", rand.Int32()) } // Config is the public configuration From b9c6d2788cef8783717cb2451d13732f57bf4d6a Mon Sep 17 00:00:00 2001 From: Felsblick <148649255+Felsblick@users.noreply.github.com> Date: Sat, 14 Sep 2024 20:32:49 +0200 Subject: [PATCH 024/116] Delta AC Max Basic: fix status (#16112) --- charger/delta.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charger/delta.go b/charger/delta.go index caa9f4208e..e81c9467b3 100644 --- a/charger/delta.go +++ b/charger/delta.go @@ -162,11 +162,11 @@ func (wb *Delta) statusDelta() (api.ChargeStatus, error) { // 7: Charging ended with error (vehicle still connected) switch s := encoding.Uint16(b); s { - case 0, 1, 2: + case 0: return api.StatusA, nil case 3: return api.StatusC, nil - case 4, 5, 6, 7: + case 1, 2, 4, 5, 6, 7: return api.StatusB, nil default: return api.StatusNone, fmt.Errorf("invalid status: %0x", s) From 78b7bfd6c36ac20145f90d537eb1f2e41e16b1be Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 21:00:00 +0200 Subject: [PATCH 025/116] SolarMax: add battery discharge control (#16110) --- provider/error.go | 45 ++++++++++++ provider/random.go | 46 ++++++++++++ .../definition/meter/solarmax-maxstorage.yaml | 72 +++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 provider/error.go create mode 100644 provider/random.go diff --git a/provider/error.go b/provider/error.go new file mode 100644 index 0000000000..96087ccb9d --- /dev/null +++ b/provider/error.go @@ -0,0 +1,45 @@ +package provider + +import ( + "fmt" + + "github.com/evcc-io/evcc/util" +) + +type errorProvider struct { + err error +} + +func init() { + registry.Add("error", NewErrorFromConfig) +} + +// NewErrorFromConfig creates error provider +func NewErrorFromConfig(other map[string]interface{}) (Provider, error) { + var cc struct { + Error string + } + + if err := util.DecodeOther(other, &cc); err != nil { + return nil, err + } + + err := knownErrors([]byte(cc.Error)) + if err == nil { + return nil, fmt.Errorf("unknown error: %s", cc.Error) + } + + o := &errorProvider{ + err: err, + } + + return o, nil +} + +var _ SetIntProvider = (*errorProvider)(nil) + +func (o *errorProvider) IntSetter(param string) (func(int64) error, error) { + return func(int64) error { + return o.err + }, nil +} diff --git a/provider/random.go b/provider/random.go new file mode 100644 index 0000000000..e749b582b9 --- /dev/null +++ b/provider/random.go @@ -0,0 +1,46 @@ +package provider + +import ( + "math" + "math/rand/v2" + + "github.com/evcc-io/evcc/util" +) + +type randomProvider struct { + set Config +} + +func init() { + registry.Add("random", NewRandomFromConfig) +} + +// NewRandomFromConfig creates random provider +func NewRandomFromConfig(other map[string]interface{}) (Provider, error) { + var cc struct { + Set Config + } + + if err := util.DecodeOther(other, &cc); err != nil { + return nil, err + } + + o := &randomProvider{ + set: cc.Set, + } + + return o, nil +} + +var _ SetIntProvider = (*randomProvider)(nil) + +func (o *randomProvider) IntSetter(param string) (func(int64) error, error) { + set, err := NewIntSetterFromConfig(param, o.set) + if err != nil { + return nil, err + } + + return func(int64) error { + return set(rand.Int64N(math.MaxInt64-1) + 1) + }, nil +} diff --git a/templates/definition/meter/solarmax-maxstorage.yaml b/templates/definition/meter/solarmax-maxstorage.yaml index eaf689517d..dccbbf679d 100644 --- a/templates/definition/meter/solarmax-maxstorage.yaml +++ b/templates/definition/meter/solarmax-maxstorage.yaml @@ -47,5 +47,77 @@ render: | address: 122 # Batterie Soc type: input decode: int16 + batterymode: + source: watchdog + timeout: {{ .watchdog }} + reset: 1 # reset watchdog on normal + set: + source: switch + switch: + - case: 1 # normal + set: + source: sequence + set: + - source: const + value: 7000 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 140 + type: writemultiple + decode: int16 + - source: const + value: 7000 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 141 + type: writemultiple + decode: int16 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 142 + type: writemultiple + decode: int16 + - case: 2 # hold + set: + source: sequence + set: + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 140 + type: writemultiple + decode: int16 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 141 + type: writemultiple + decode: int16 + - source: random + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 142 + type: writemultiple + decode: int16 + - case: 3 # charge (not implemented) + set: + source: error + error: ErrNotImplemented capacity: {{ .capacity }} # kWh {{- end }} From 213eeafd0b00edd379c5a60ea2e7d69b96413a9f Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 21:27:53 +0200 Subject: [PATCH 026/116] chore: docs --- templates/definition/meter/solarmax-maxstorage.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/definition/meter/solarmax-maxstorage.yaml b/templates/definition/meter/solarmax-maxstorage.yaml index dccbbf679d..2a7ac887f1 100644 --- a/templates/definition/meter/solarmax-maxstorage.yaml +++ b/templates/definition/meter/solarmax-maxstorage.yaml @@ -3,6 +3,7 @@ products: - brand: SolarMax description: generic: MAX.STORAGE / MAX.STORAGE Ultimate +capabilities: ["battery-control"] params: - name: usage choice: ["grid", "pv", "battery"] From 4bbaf0de472ddb0dba0a085c6e2184f8f3fda5af Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 21:30:53 +0200 Subject: [PATCH 027/116] chore: fix error type --- templates/definition/meter/solarmax-maxstorage.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/definition/meter/solarmax-maxstorage.yaml b/templates/definition/meter/solarmax-maxstorage.yaml index 2a7ac887f1..7bdb19940f 100644 --- a/templates/definition/meter/solarmax-maxstorage.yaml +++ b/templates/definition/meter/solarmax-maxstorage.yaml @@ -119,6 +119,6 @@ render: | - case: 3 # charge (not implemented) set: source: error - error: ErrNotImplemented + error: ErrNotAvailable capacity: {{ .capacity }} # kWh {{- end }} From 01a5e2381cf8ea3d4055a1ed92c6a51926cc94ca Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 14 Sep 2024 21:37:10 +0200 Subject: [PATCH 028/116] Site: support battery mode not available (usually charge mode) --- core/site_battery.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/site_battery.go b/core/site_battery.go index a8da20aee3..f98f58eb5b 100644 --- a/core/site_battery.go +++ b/core/site_battery.go @@ -1,6 +1,8 @@ package core import ( + "errors" + "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/core/keys" "github.com/evcc-io/evcc/core/loadpoint" @@ -60,7 +62,7 @@ func (site *Site) requiredBatteryMode(batteryGridChargeActive bool, rate api.Rat func (site *Site) applyBatteryMode(mode api.BatteryMode) error { for _, meter := range site.batteryMeters { if batCtrl, ok := meter.(api.BatteryController); ok { - if err := batCtrl.SetBatteryMode(mode); err != nil { + if err := batCtrl.SetBatteryMode(mode); err != nil && !errors.Is(err, api.ErrNotAvailable) { return err } } From f7b83fa8f5f4ef258b5bee15c07ba1f2fd68f683 Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 15 Sep 2024 10:48:15 +0200 Subject: [PATCH 029/116] chore: fix default value --- templates/definition/meter/solarmax-maxstorage.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/templates/definition/meter/solarmax-maxstorage.yaml b/templates/definition/meter/solarmax-maxstorage.yaml index 7bdb19940f..2c6971fbec 100644 --- a/templates/definition/meter/solarmax-maxstorage.yaml +++ b/templates/definition/meter/solarmax-maxstorage.yaml @@ -13,6 +13,11 @@ params: id: 1 - name: capacity advanced: true + # battery control + - name: watchdog + type: duration + default: 60s + advanced: true render: | type: custom power: From f3fb1c1ae25571a3e9edfb82e95b8366a7290ba8 Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 15 Sep 2024 11:50:20 +0200 Subject: [PATCH 030/116] Fronius SolarApi: mark charge mode as not available (#16121) --- .../definition/meter/fronius-solarapi-v1.yaml | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/templates/definition/meter/fronius-solarapi-v1.yaml b/templates/definition/meter/fronius-solarapi-v1.yaml index 1aef223a54..78983f5342 100644 --- a/templates/definition/meter/fronius-solarapi-v1.yaml +++ b/templates/definition/meter/fronius-solarapi-v1.yaml @@ -76,18 +76,22 @@ render: | user: {{ .user }} password: {{ .password }} body: '{"timeofuse":[{"Active":true,"Power":0,"ScheduleType":"DISCHARGE_MAX","TimeTable":{"Start":"00:00","End":"23:59"},"Weekdays":{"Mon":true,"Tue":true,"Wed":true,"Thu":true,"Fri":true,"Sat":true,"Sun":true}}]}' - - case: 3 # charge + - case: 3 # charge (not implemented -> normal) set: - source: http - uri: http://{{ .host }}/config/timeofuse - method: POST - headers: - - content-type: application/json - auth: - type: digest - user: {{ .user }} - password: {{ .password }} - body: '{"timeofuse":[]}' + source: sequence + set: + - source: http + uri: http://{{ .host }}/config/timeofuse + method: POST + headers: + - content-type: application/json + auth: + type: digest + user: {{ .user }} + password: {{ .password }} + body: '{"timeofuse":[]}' + - source: error + error: ErrNotAvailable {{- end }} capacity: {{ .capacity }} # kWh {{- end }} From 229b2cf4e2bdae599f7dc37aa912f80914812b8f Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 15 Sep 2024 12:55:54 +0200 Subject: [PATCH 031/116] chore: minor --- core/loadpoint_plan.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/loadpoint_plan.go b/core/loadpoint_plan.go index c4e23faac8..389ecbb5b4 100644 --- a/core/loadpoint_plan.go +++ b/core/loadpoint_plan.go @@ -87,9 +87,9 @@ func (lp *Loadpoint) plannerActive() (active bool) { lp.setPlanActive(active) }() - var planStart time.Time - var planEnd time.Time + var planStart, planEnd time.Time var planOverrun time.Duration + defer func() { lp.publish(keys.PlanProjectedStart, planStart) lp.publish(keys.PlanProjectedEnd, planEnd) @@ -100,6 +100,7 @@ func (lp *Loadpoint) plannerActive() (active bool) { if planTime.IsZero() { return false } + // keep overrunning plans as long as a vehicle is connected if lp.clock.Until(planTime) < 0 && (!lp.planActive || !lp.connected()) { lp.log.DEBUG.Println("plan: deleting expired plan") From 009a9c2cb95948a64d2108d2713a3a9bbddc9f13 Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 15 Sep 2024 13:48:49 +0200 Subject: [PATCH 032/116] Ocpp: always send confirmation (#15950) --- charger/ocpp/cp_core.go | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/charger/ocpp/cp_core.go b/charger/ocpp/cp_core.go index ddb6dcb8a9..390c95800d 100644 --- a/charger/ocpp/cp_core.go +++ b/charger/ocpp/cp_core.go @@ -85,12 +85,11 @@ func (cp *CP) MeterValues(request *core.MeterValuesRequest) (*core.MeterValuesCo default: } - conn := cp.connectorByID(request.ConnectorId) - if conn == nil { - return nil, ErrInvalidConnector + if conn := cp.connectorByID(request.ConnectorId); conn != nil { + conn.MeterValues(request) } - return conn.MeterValues(request) + return new(core.MeterValuesConfirmation), nil } func (cp *CP) StartTransaction(request *core.StartTransactionRequest) (*core.StartTransactionConfirmation, error) { @@ -98,12 +97,11 @@ func (cp *CP) StartTransaction(request *core.StartTransactionRequest) (*core.Sta return nil, ErrInvalidRequest } - conn := cp.connectorByID(request.ConnectorId) - if conn == nil { - return nil, ErrInvalidConnector + if conn := cp.connectorByID(request.ConnectorId); conn != nil { + return conn.StartTransaction(request) } - return conn.StartTransaction(request) + return new(core.StartTransactionConfirmation), nil } func (cp *CP) StopTransaction(request *core.StopTransactionRequest) (*core.StopTransactionConfirmation, error) { @@ -111,16 +109,15 @@ func (cp *CP) StopTransaction(request *core.StopTransactionRequest) (*core.StopT return nil, ErrInvalidRequest } - conn := cp.connectorByTransactionID(request.TransactionId) - if conn == nil { - res := &core.StopTransactionConfirmation{ - IdTagInfo: &types.IdTagInfo{ - Status: types.AuthorizationStatusAccepted, // accept old pending stop message during startup - }, - } + if conn := cp.connectorByTransactionID(request.TransactionId); conn != nil { + return conn.StopTransaction(request) + } - return res, nil + res := &core.StopTransactionConfirmation{ + IdTagInfo: &types.IdTagInfo{ + Status: types.AuthorizationStatusAccepted, // accept old pending stop message during startup + }, } - return conn.StopTransaction(request) + return res, nil } From c2731746758ca5d58bec77adc309363ea95e1882 Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 15 Sep 2024 14:00:07 +0200 Subject: [PATCH 033/116] Keba: fix status reason (#16130) --- charger/keba-modbus.go | 73 ++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/charger/keba-modbus.go b/charger/keba-modbus.go index 2d4fa53629..bdbb7d9326 100644 --- a/charger/keba-modbus.go +++ b/charger/keba-modbus.go @@ -167,55 +167,74 @@ func (wb *Keba) heartbeat(timeout time.Duration) { } } -// Status implements the api.Charger interface -func (wb *Keba) Status() (api.ChargeStatus, error) { +func (wb *Keba) isConnected() (bool, error) { b, err := wb.conn.ReadHoldingRegisters(kebaRegCableState, 2) if err != nil { - return api.StatusNone, err + return false, err } - switch status := binary.BigEndian.Uint32(b); status { - case 0, 1, 3: - return api.StatusA, nil + // 0: No cable is plugged. + // 1: Cable is connected to the charging station (not to the electric vehicle). + // 3: Cable is connected to the charging station and locked (not to the electric vehicle). + // 5: Cable is connected to the charging station and the electric vehicle (not locked). + // 7: Cable is connected to the charging station and the electric vehicle and locked (charging). - case 5: - return api.StatusB, nil + return binary.BigEndian.Uint32(b)&(1<<2) != 0, err +} - case 7: - b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) - if err != nil { - return api.StatusNone, err - } - if binary.BigEndian.Uint32(b) == 3 { - return api.StatusC, err - } - return api.StatusB, nil +func (wb *Keba) getChargingState() (uint32, error) { + b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) + if err != nil { + return 0, err + } + + // 0: Start-up of the charging station + // 1: The charging station is not ready for charging. The charging station is not connected to an electric vehicle, it is locked by the authorization function or another mechanism. + // 2: The charging station is ready for charging and waits for a reaction from the electric vehicle. + // 3: A charging process is active. + // 4: An error has occurred. + // 5: The charging process is temporarily interrupted because the temperature is too high or the wallbox is in suspended mode. - default: - return api.StatusNone, fmt.Errorf("invalid status: %d", status) + return binary.BigEndian.Uint32(b), nil +} + +// Status implements the api.Charger interface +func (wb *Keba) Status() (api.ChargeStatus, error) { + if connected, err := wb.isConnected(); err != nil || !connected { + return api.StatusA, err + } + + s, err := wb.getChargingState() + if err != nil { + return api.StatusA, err + } + if s == 3 { + return api.StatusC, nil } + return api.StatusB, nil } // statusReason implements the api.StatusReasoner interface func (wb *Keba) statusReason() (api.Reason, error) { - res := api.ReasonUnknown + if connected, err := wb.isConnected(); err != nil || !connected { + return api.ReasonUnknown, err + } - b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) - if err == nil && binary.BigEndian.Uint32(b) == 1 { - res = api.ReasonWaitingForAuthorization + if s, err := wb.getChargingState(); err != nil || s != 1 { + return api.ReasonUnknown, err } - return res, err + return api.ReasonWaitingForAuthorization, nil } // Enabled implements the api.Charger interface func (wb *Keba) Enabled() (bool, error) { - b, err := wb.conn.ReadHoldingRegisters(kebaRegChargingState, 2) + s, err := wb.getChargingState() if err != nil { return false, err } - status := binary.BigEndian.Uint32(b) - return !(status == 5 || status == 1), nil + + return !(s == 5 || s == 1), nil } // Enable implements the api.Charger interface From bab0d67d933e173aebdfaaf71b6929075084d27d Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 15 Sep 2024 14:02:57 +0200 Subject: [PATCH 034/116] SMA: fix Sunny Boy Storage 1.5/2.0/2.5 (#16106) --- .../meter/sma-sbs-15-25-modbus.yaml | 228 ++++++++++++++++++ templates/definition/meter/sma-si-modbus.yaml | 3 - 2 files changed, 228 insertions(+), 3 deletions(-) create mode 100644 templates/definition/meter/sma-sbs-15-25-modbus.yaml diff --git a/templates/definition/meter/sma-sbs-15-25-modbus.yaml b/templates/definition/meter/sma-sbs-15-25-modbus.yaml new file mode 100644 index 0000000000..5d116c0629 --- /dev/null +++ b/templates/definition/meter/sma-sbs-15-25-modbus.yaml @@ -0,0 +1,228 @@ +template: sma-sbs-15-25-modbus +products: + - brand: SMA + description: + generic: Sunny Boy Storage 1.5/2.0/2.5 (Modbus) +capabilities: ["battery-control"] +params: + - name: usage + choice: ["battery"] + - name: modbus + choice: ["tcpip"] + port: 502 + id: 3 + help: + en: The Modbus TCP-Server needs to be enabled on this inverter + de: Der Modbus TCP-Server muss an diesem Wechselrichter aktiviert sein + - name: capacity + advanced: true + - name: watchdog + type: duration + default: 60s + advanced: true +render: | + type: custom + power: + source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 30775 + type: input + decode: int32nan + energy: + source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 30513 + type: holding + decode: uint64nan + scale: 0.001 + soc: + source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 30845 + type: holding + decode: uint32nan + batterymode: + source: watchdog + timeout: {{ .watchdog }} + reset: 1 # reset watchdog on normal + set: + source: switch + switch: + - case: 1 # normal + set: + source: sequence + set: + - source: const + value: 2424 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40236 + type: writemultiple + decode: uint32 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40793 + type: writemultiple + decode: uint32 + - source: const + value: 2500 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40795 + type: writemultiple + decode: uint32 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40797 + type: writemultiple + decode: uint32 + - source: const + value: 2650 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40799 + type: writemultiple + decode: uint32 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40801 + type: writemultiple + decode: uint32 + - case: 2 # hold + set: + source: sequence + set: + - source: const + value: 2424 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40236 + type: writemultiple + decode: uint32 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40793 + type: writemultiple + decode: uint32 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40795 + type: writemultiple + decode: uint32 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40797 + type: writemultiple + decode: uint32 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40799 + type: writemultiple + decode: uint32 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40801 + type: writemultiple + decode: uint32 + - case: 3 # charge + set: + source: sequence + set: + - source: const + value: 2289 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40236 + type: writemultiple + decode: uint32 + - source: const + value: 2500 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40793 + type: writemultiple + decode: uint32 + - source: const + value: 2500 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40795 + type: writemultiple + decode: uint32 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40797 + type: writemultiple + decode: uint32 + - source: const + value: 2650 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40799 + type: writemultiple + decode: uint32 + - source: const + value: 0 + set: + source: modbus + {{- include "modbus" . | indent 12 }} + register: + address: 40801 + type: writemultiple + decode: uint32 + capacity: {{ .capacity }} # kWh diff --git a/templates/definition/meter/sma-si-modbus.yaml b/templates/definition/meter/sma-si-modbus.yaml index c6f18818ff..bb0b0810ac 100644 --- a/templates/definition/meter/sma-si-modbus.yaml +++ b/templates/definition/meter/sma-si-modbus.yaml @@ -3,9 +3,6 @@ products: - brand: SMA description: generic: Sunny Island (Modbus) - - brand: SMA - description: - generic: Sunny Boy Storage 1.5/2.0/2.5 (Modbus) capabilities: ["battery-control"] params: - name: usage From 22db14bb4cda186d4588cf167cfde24cd39d8c51 Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 15 Sep 2024 16:18:27 +0200 Subject: [PATCH 035/116] Modbus: always assume RTU for serial devices (#16134) --- meter/mbmd.go | 5 +++-- util/modbus/modbus.go | 2 +- util/modbus/modbus_test.go | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/meter/mbmd.go b/meter/mbmd.go index 29876ea5eb..a0497ebc45 100644 --- a/meter/mbmd.go +++ b/meter/mbmd.go @@ -53,8 +53,9 @@ func NewModbusMbmdFromConfig(other map[string]interface{}) (api.Meter, error) { // assume RTU if not set and this is a known RS485 meter model if cc.RTU == nil { - b := modbus.IsRS485(cc.Model) - cc.RTU = &b + if rtu := modbus.IsRS485(cc.Model); rtu { + cc.RTU = &rtu + } } modbus.Lock() diff --git a/util/modbus/modbus.go b/util/modbus/modbus.go index 2448418e98..3514db37d9 100644 --- a/util/modbus/modbus.go +++ b/util/modbus/modbus.go @@ -47,7 +47,7 @@ func (s Settings) Protocol() Protocol { switch { case s.UDP: return Udp - case s.RTU != nil && *s.RTU: + case s.Device != "" || s.RTU != nil && *s.RTU: return Rtu default: return Tcp diff --git a/util/modbus/modbus_test.go b/util/modbus/modbus_test.go index 70a18082e3..4ee4b04346 100644 --- a/util/modbus/modbus_test.go +++ b/util/modbus/modbus_test.go @@ -3,6 +3,7 @@ package modbus import ( "testing" + "github.com/samber/lo" "github.com/stretchr/testify/require" ) @@ -23,3 +24,20 @@ func TestParsePoint(t *testing.T) { require.Equal(t, tc.ops, ops) } } + +func TestSettingsProtocol(t *testing.T) { + tc := []struct { + Settings + res Protocol + }{ + {Settings{UDP: true}, Udp}, + {Settings{RTU: lo.ToPtr(true)}, Rtu}, + {Settings{Device: "foo"}, Rtu}, + {Settings{URI: "foo"}, Tcp}, + {Settings{}, Tcp}, + } + + for _, tc := range tc { + require.Equal(t, tc.res, tc.Protocol(), tc) + } +} From 81a315928db0a15460fed7412788d76a88437de4 Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 15 Sep 2024 16:38:53 +0200 Subject: [PATCH 036/116] chore: fix wording --- templates/definition/meter/sma-hybrid.yaml | 4 ++-- templates/definition/meter/sma-inverter-modbus.yaml | 4 ++-- templates/definition/meter/sma-sbs-15-25-modbus.yaml | 4 ++-- templates/definition/meter/sma-sbs-modbus.yaml | 4 ++-- templates/definition/meter/sma-si-modbus.yaml | 4 ++-- templates/definition/meter/sma-webbox.yaml | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/templates/definition/meter/sma-hybrid.yaml b/templates/definition/meter/sma-hybrid.yaml index b01fe0e0ea..a9160c16b1 100644 --- a/templates/definition/meter/sma-hybrid.yaml +++ b/templates/definition/meter/sma-hybrid.yaml @@ -14,8 +14,8 @@ params: port: 502 id: 3 help: - en: The Modbus TCP-Server needs to be enabled on this Smart Energy inverter - de: Der Modbus TCP-Server muss an diesem Smart Energy Wechselrichter aktiviert sein + en: ModbusTCP server needs to be enabled. + de: Der ModbusTCP Server muss aktiviert sein. - name: capacity advanced: true - name: watchdog diff --git a/templates/definition/meter/sma-inverter-modbus.yaml b/templates/definition/meter/sma-inverter-modbus.yaml index f596b13c9e..6073ae1af0 100644 --- a/templates/definition/meter/sma-inverter-modbus.yaml +++ b/templates/definition/meter/sma-inverter-modbus.yaml @@ -11,8 +11,8 @@ params: port: 502 id: 3 help: - en: The Modbus TCP-Server needs to be enabled on this inverter - de: Der Modbus TCP-Server muss an diesem Wechselrichter aktiviert sein + en: ModbusTCP server needs to be enabled. + de: Der ModbusTCP Server muss aktiviert sein. render: | type: custom power: diff --git a/templates/definition/meter/sma-sbs-15-25-modbus.yaml b/templates/definition/meter/sma-sbs-15-25-modbus.yaml index 5d116c0629..326218fda0 100644 --- a/templates/definition/meter/sma-sbs-15-25-modbus.yaml +++ b/templates/definition/meter/sma-sbs-15-25-modbus.yaml @@ -12,8 +12,8 @@ params: port: 502 id: 3 help: - en: The Modbus TCP-Server needs to be enabled on this inverter - de: Der Modbus TCP-Server muss an diesem Wechselrichter aktiviert sein + en: ModbusTCP server needs to be enabled. + de: Der ModbusTCP Server muss aktiviert sein. - name: capacity advanced: true - name: watchdog diff --git a/templates/definition/meter/sma-sbs-modbus.yaml b/templates/definition/meter/sma-sbs-modbus.yaml index 2ab7120325..e7fb103dcc 100644 --- a/templates/definition/meter/sma-sbs-modbus.yaml +++ b/templates/definition/meter/sma-sbs-modbus.yaml @@ -12,8 +12,8 @@ params: port: 502 id: 3 help: - en: The Modbus TCP-Server needs to be enabled on this inverter - de: Der Modbus TCP-Server muss an diesem Wechselrichter aktiviert sein + en: ModbusTCP server needs to be enabled. + de: Der ModbusTCP Server muss aktiviert sein. - name: capacity advanced: true - name: watchdog diff --git a/templates/definition/meter/sma-si-modbus.yaml b/templates/definition/meter/sma-si-modbus.yaml index bb0b0810ac..df2d684bfe 100644 --- a/templates/definition/meter/sma-si-modbus.yaml +++ b/templates/definition/meter/sma-si-modbus.yaml @@ -12,8 +12,8 @@ params: port: 502 id: 3 help: - en: The Modbus TCP-Server needs to be enabled on this inverter - de: Der Modbus TCP-Server muss an diesem Wechselrichter aktiviert sein + en: ModbusTCP server needs to be enabled. + de: Der ModbusTCP Server muss aktiviert sein. - name: capacity advanced: true - name: watchdog diff --git a/templates/definition/meter/sma-webbox.yaml b/templates/definition/meter/sma-webbox.yaml index 409334b52a..76892c3a8b 100644 --- a/templates/definition/meter/sma-webbox.yaml +++ b/templates/definition/meter/sma-webbox.yaml @@ -12,8 +12,8 @@ params: port: 502 id: 2 help: - en: The Modbus TCP-Server needs to be enabled on this WebBox - de: Der Modbus TCP-Server muss auf dieser WebBox aktiviert sein + en: ModbusTCP server needs to be enabled. + de: Der ModbusTCP Server muss aktiviert sein. render: | type: custom {{- if eq .usage "pv" }} From 62c26ec6540f486c843f6a1f80385e921da1efe2 Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 15 Sep 2024 18:51:19 +0200 Subject: [PATCH 037/116] myPV Elwa2: refactor (#15466) --- charger/mypv-elwa2.go | 214 ++++++++++++++++++++ templates/definition/charger/ac-elwa-2.yaml | 52 +---- 2 files changed, 215 insertions(+), 51 deletions(-) create mode 100644 charger/mypv-elwa2.go diff --git a/charger/mypv-elwa2.go b/charger/mypv-elwa2.go new file mode 100644 index 0000000000..82c3893334 --- /dev/null +++ b/charger/mypv-elwa2.go @@ -0,0 +1,214 @@ +package charger + +// LICENSE + +// Copyright (c) 2024 andig + +// This module is NOT covered by the MIT license. All rights reserved. + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import ( + "encoding/binary" + "sync/atomic" + "time" + + "github.com/evcc-io/evcc/api" + "github.com/evcc-io/evcc/util" + "github.com/evcc-io/evcc/util/modbus" + "github.com/evcc-io/evcc/util/sponsor" +) + +// MyPvElwa2 charger implementation +type MyPvElwa2 struct { + log *util.Logger + conn *modbus.Connection + power uint32 +} + +const ( + elwaRegSetPower = 1000 + elwaRegTemp = 1001 + elwaRegTempLimit = 1002 + elwaRegStatus = 1003 + elwaRegPower = 1074 +) + +func init() { + registry.Add("ac-elwa-2", NewMyPvElwa2FromConfig) +} + +// https://github.com/evcc-io/evcc/discussions/12761 + +// NewMyPvElwa2FromConfig creates a MyPvElwa2 charger from generic config +func NewMyPvElwa2FromConfig(other map[string]interface{}) (api.Charger, error) { + cc := modbus.TcpSettings{ + ID: 1, + } + + if err := util.DecodeOther(other, &cc); err != nil { + return nil, err + } + + return NewMyPvElwa2(cc.URI, cc.ID) +} + +// NewMyPvElwa2 creates myPV AC Elwa 2 charger +func NewMyPvElwa2(uri string, slaveID uint8) (api.Charger, error) { + conn, err := modbus.NewConnection(uri, "", "", 0, modbus.Tcp, slaveID) + if err != nil { + return nil, err + } + + if !sponsor.IsAuthorized() { + return nil, api.ErrSponsorRequired + } + + log := util.NewLogger("ac-elwa-2") + conn.Logger(log.TRACE) + + wb := &MyPvElwa2{ + log: log, + conn: conn, + } + + go wb.heartbeat(30 * time.Second) + + return wb, nil +} + +var _ api.IconDescriber = (*MyPvElwa2)(nil) + +// Icon implements the api.IconDescriber interface +func (v *MyPvElwa2) Icon() string { + return "waterheater" +} + +var _ api.FeatureDescriber = (*MyPvElwa2)(nil) + +// Features implements the api.FeatureDescriber interface +func (wb *MyPvElwa2) Features() []api.Feature { + return []api.Feature{api.IntegratedDevice, api.Heating} +} + +func (wb *MyPvElwa2) heartbeat(timeout time.Duration) { + for range time.Tick(timeout) { + if power := uint16(atomic.LoadUint32(&wb.power)); power > 0 { + enabled, err := wb.Enabled() + if err == nil && enabled { + err = wb.setPower(power) + } + if err != nil { + wb.log.ERROR.Println("heartbeat:", err) + } + } + } +} + +// Status implements the api.Charger interface +func (wb *MyPvElwa2) Status() (api.ChargeStatus, error) { + res := api.StatusA + b, err := wb.conn.ReadInputRegisters(elwaRegStatus, 1) + if err != nil { + return res, err + } + + res = api.StatusB + if binary.BigEndian.Uint16(b) == 2 { + res = api.StatusC + } + + return res, nil +} + +// Enabled implements the api.Charger interface +func (wb *MyPvElwa2) Enabled() (bool, error) { + b, err := wb.conn.ReadHoldingRegisters(elwaRegSetPower, 1) + if err != nil { + return false, err + } + + return binary.BigEndian.Uint16(b) > 0, nil +} + +func (wb *MyPvElwa2) setPower(power uint16) error { + b := make([]byte, 2) + binary.BigEndian.PutUint16(b, power) + + _, err := wb.conn.WriteMultipleRegisters(elwaRegSetPower, 1, b) + return err +} + +// Enable implements the api.Charger interface +func (wb *MyPvElwa2) Enable(enable bool) error { + var power uint16 + if enable { + power = uint16(atomic.LoadUint32(&wb.power)) + } + + return wb.setPower(power) +} + +// MaxCurrent implements the api.Charger interface +func (wb *MyPvElwa2) MaxCurrent(current int64) error { + return wb.MaxCurrentMillis(float64(current)) +} + +var _ api.ChargerEx = (*MyPvElwa2)(nil) + +// MaxCurrentMillis implements the api.ChargerEx interface +func (wb *MyPvElwa2) MaxCurrentMillis(current float64) error { + power := uint16(230 * current) + + err := wb.setPower(power) + if err == nil { + atomic.StoreUint32(&wb.power, uint32(power)) + } + + return err +} + +var _ api.Meter = (*MyPvElwa2)(nil) + +// CurrentPower implements the api.Meter interface +func (wb *MyPvElwa2) CurrentPower() (float64, error) { + b, err := wb.conn.ReadInputRegisters(elwaRegPower, 1) + if err != nil { + return 0, err + } + + return float64(binary.BigEndian.Uint16(b)), nil +} + +var _ api.Battery = (*MyPvElwa2)(nil) + +// CurrentPower implements the api.Meter interface +func (wb *MyPvElwa2) Soc() (float64, error) { + b, err := wb.conn.ReadInputRegisters(elwaRegTemp, 1) + if err != nil { + return 0, err + } + + return float64(binary.BigEndian.Uint16(b)) / 10, nil +} + +var _ api.SocLimiter = (*MyPvElwa2)(nil) + +// GetLimitSoc implements the api.SocLimiter interface +func (wb *MyPvElwa2) GetLimitSoc() (int64, error) { + b, err := wb.conn.ReadInputRegisters(elwaRegTempLimit, 1) + if err != nil { + return 0, err + } + + return int64(binary.BigEndian.Uint16(b)) / 10, nil +} diff --git a/templates/definition/charger/ac-elwa-2.yaml b/templates/definition/charger/ac-elwa-2.yaml index 8d9060ee61..1806f1eb7c 100644 --- a/templates/definition/charger/ac-elwa-2.yaml +++ b/templates/definition/charger/ac-elwa-2.yaml @@ -7,54 +7,4 @@ params: - name: modbus choice: ["tcpip"] render: | - type: custom - enable: - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 1000 - type: writeholding - decode: uint16 - enabled: - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 1000 - type: holding - decode: uint16 - maxcurrent: - source: go - script: | - 230 * maxcurrent - out: - - name: power - type: int - config: - source: modbus - {{- include "modbus" . | indent 8 }} - register: - address: 1000 - type: writeholding - decode: uint16 - status: - source: combined - plugged: - source: const - value: 1 - charging: - source: modbus - {{- include "modbus" . | indent 4 }} - register: - address: 1074 # alternativ 1003 mit bit pattern - type: holding - decode: uint16 - soc: - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 1001 - type: holding - decode: uint16 - scale: 0.1 - features: ["integrateddevice", "heating"] - icon: waterheater + {{- include "modbus" . }} From 2771e8a45a20e82b6a80d8282dc98d37516baf48 Mon Sep 17 00:00:00 2001 From: VolkerK62 <99199865+VolkerK62@users.noreply.github.com> Date: Sun, 15 Sep 2024 18:51:59 +0200 Subject: [PATCH 038/116] Clarify grid meter usage (#16140) --- evcc.dist.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evcc.dist.yaml b/evcc.dist.yaml index 07f944f554..0cf81148fe 100644 --- a/evcc.dist.yaml +++ b/evcc.dist.yaml @@ -114,7 +114,7 @@ site: loadpoints: - title: Garage # display name for UI charger: wallbe # charger - meter: charge # charge meter + meter: charge # external charge meter (if charger has no meter included). NOT grid or pv meter. mode: "off" # default charge mode to apply when vehicle is disconnected; use "off" to disable by default if charger is publicly available # remaining settings are experts-only and best left at default values From 484248ebee2a9b4732b79bc3669d157aad2945df Mon Sep 17 00:00:00 2001 From: thebrainkafka Date: Mon, 16 Sep 2024 09:13:40 +0200 Subject: [PATCH 039/116] chore: update docs (#16145) --- templates/definition/meter/solarmax-maxstorage.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/templates/definition/meter/solarmax-maxstorage.yaml b/templates/definition/meter/solarmax-maxstorage.yaml index 2c6971fbec..7bf178ad12 100644 --- a/templates/definition/meter/solarmax-maxstorage.yaml +++ b/templates/definition/meter/solarmax-maxstorage.yaml @@ -4,6 +4,10 @@ products: description: generic: MAX.STORAGE / MAX.STORAGE Ultimate capabilities: ["battery-control"] +requirements: + description: + de: Für Batteriesteuerung muss über den Solarmax Support die Funktion "Connectivity+" freigeschaltet werden. Verfügbar ab Software 3.4.4. Ohne Freischaltung bleibt die Funktion ohne Wirkung. Netzladung ist generell nicht verfügbar. + en: For batter control, the "Connectivity+" function must be activated via the Solarmax support. Available from software version 3.4.4. Without activation, the function remains without effect. Grid charging is generally not available. params: - name: usage choice: ["grid", "pv", "battery"] From 3eb1ae0c4eff98e1d833e67a86c66d4c0c0336ac Mon Sep 17 00:00:00 2001 From: andig Date: Mon, 16 Sep 2024 10:35:15 +0200 Subject: [PATCH 040/116] chore: fix type --- templates/definition/charger/ac-elwa-2.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/definition/charger/ac-elwa-2.yaml b/templates/definition/charger/ac-elwa-2.yaml index 1806f1eb7c..856cc31ed7 100644 --- a/templates/definition/charger/ac-elwa-2.yaml +++ b/templates/definition/charger/ac-elwa-2.yaml @@ -7,4 +7,5 @@ params: - name: modbus choice: ["tcpip"] render: | + type: ac-elwa-2 {{- include "modbus" . }} From f20855fc9dc3d0fdf84e3baf081b93841617a34a Mon Sep 17 00:00:00 2001 From: andig Date: Mon, 16 Sep 2024 19:01:15 +0200 Subject: [PATCH 041/116] Ocpp: re-add current getter (#16153) --- charger/ocpp.go | 12 +- charger/ocpp_decorators.go | 1002 +++++++++++++++++++++++++++++++++--- 2 files changed, 941 insertions(+), 73 deletions(-) diff --git a/charger/ocpp.go b/charger/ocpp.go index b2a8cb5322..3b894d3431 100644 --- a/charger/ocpp.go +++ b/charger/ocpp.go @@ -104,15 +104,15 @@ func NewOCPPFromConfig(other map[string]interface{}) (api.Charger, error) { phasesS = c.phases1p3p } - // var currentG func() (float64, error) - // if c.cp.HasMeasurement(types.MeasurandCurrentOffered) { - // currentG = c.conn.GetMaxCurrent - // } + var currentG func() (float64, error) + if c.cp.HasMeasurement(types.MeasurandCurrentOffered) { + currentG = c.conn.GetMaxCurrent + } - return decorateOCPP(c, powerG, totalEnergyG, currentsG, voltagesG, phasesS, socG), nil + return decorateOCPP(c, powerG, totalEnergyG, currentsG, voltagesG, currentG, phasesS, socG), nil } -//go:generate go run ../cmd/tools/decorate.go -f decorateOCPP -b *OCPP -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.PhaseVoltages,Voltages,func() (float64, float64, float64, error)" -t "api.PhaseSwitcher,Phases1p3p,func(int) error" -t "api.Battery,Soc,func() (float64, error)" +//go:generate go run ../cmd/tools/decorate.go -f decorateOCPP -b *OCPP -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.PhaseVoltages,Voltages,func() (float64, float64, float64, error)" -t "api.CurrentGetter,GetMaxCurrent,func() (float64, error)" -t "api.PhaseSwitcher,Phases1p3p,func(int) error" -t "api.Battery,Soc,func() (float64, error)" // NewOCPP creates OCPP charger func NewOCPP(id string, connector int, idTag string, diff --git a/charger/ocpp_decorators.go b/charger/ocpp_decorators.go index c51ac2b9fc..c51933fc38 100644 --- a/charger/ocpp_decorators.go +++ b/charger/ocpp_decorators.go @@ -6,12 +6,12 @@ import ( "github.com/evcc-io/evcc/api" ) -func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error), phaseSwitcher func(int) error, battery func() (float64, error)) api.Charger { +func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error), currentGetter func() (float64, error), phaseSwitcher func(int) error, battery func() (float64, error)) api.Charger { switch { - case battery == nil && meter == nil && phaseSwitcher == nil: + case battery == nil && currentGetter == nil && meter == nil && phaseSwitcher == nil: return base - case battery == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: + case battery == nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: return &struct { *OCPP api.Meter @@ -22,7 +22,7 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: + case battery == nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: return &struct { *OCPP api.Meter @@ -37,7 +37,7 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: + case battery == nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: return &struct { *OCPP api.Meter @@ -52,7 +52,7 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: + case battery == nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: return &struct { *OCPP api.Meter @@ -71,7 +71,7 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: + case battery == nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: return &struct { *OCPP api.Meter @@ -86,7 +86,7 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: + case battery == nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: return &struct { *OCPP api.Meter @@ -105,7 +105,7 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: + case battery == nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: return &struct { *OCPP api.Meter @@ -124,7 +124,7 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: + case battery == nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: return &struct { *OCPP api.Meter @@ -147,79 +147,744 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery == nil && meter == nil && phaseSwitcher != nil: + case battery == nil && currentGetter != nil && meter == nil && phaseSwitcher == nil: return &struct { *OCPP + api.CurrentGetter + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.MeterEnergy + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.PhaseCurrents + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.MeterEnergy + api.PhaseCurrents + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.PhaseVoltages + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.MeterEnergy + api.PhaseVoltages + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.PhaseCurrents + api.PhaseVoltages + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.MeterEnergy + api.PhaseCurrents + api.PhaseVoltages + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery == nil && currentGetter == nil && meter == nil && phaseSwitcher != nil: + return &struct { + *OCPP + api.PhaseSwitcher + }{ + OCPP: base, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + + case battery == nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: + return &struct { + *OCPP + api.Meter + api.PhaseSwitcher + }{ + OCPP: base, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + + case battery == nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: + return &struct { + *OCPP + api.Meter + api.MeterEnergy + api.PhaseSwitcher + }{ + OCPP: base, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + + case battery == nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: + return &struct { + *OCPP + api.Meter + api.PhaseCurrents + api.PhaseSwitcher + }{ + OCPP: base, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + + case battery == nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: + return &struct { + *OCPP + api.Meter + api.MeterEnergy + api.PhaseCurrents + api.PhaseSwitcher + }{ + OCPP: base, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + + case battery == nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: + return &struct { + *OCPP + api.Meter + api.PhaseSwitcher + api.PhaseVoltages + }{ + OCPP: base, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery == nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: + return &struct { + *OCPP + api.Meter + api.MeterEnergy + api.PhaseSwitcher + api.PhaseVoltages + }{ + OCPP: base, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery == nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: + return &struct { + *OCPP + api.Meter + api.PhaseCurrents + api.PhaseSwitcher + api.PhaseVoltages + }{ + OCPP: base, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery == nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: + return &struct { + *OCPP + api.Meter + api.MeterEnergy + api.PhaseCurrents + api.PhaseSwitcher + api.PhaseVoltages + }{ + OCPP: base, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery == nil && currentGetter != nil && meter == nil && phaseSwitcher != nil: + return &struct { + *OCPP + api.CurrentGetter + api.PhaseSwitcher + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.PhaseSwitcher + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.MeterEnergy + api.PhaseSwitcher + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.PhaseCurrents + api.PhaseSwitcher + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.MeterEnergy + api.PhaseCurrents + api.PhaseSwitcher + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.PhaseSwitcher + api.PhaseVoltages + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.MeterEnergy + api.PhaseSwitcher + api.PhaseVoltages + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.PhaseCurrents + api.PhaseSwitcher + api.PhaseVoltages + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery == nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: + return &struct { + *OCPP + api.CurrentGetter + api.Meter + api.MeterEnergy + api.PhaseCurrents api.PhaseSwitcher + api.PhaseVoltages + }{ + OCPP: base, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery != nil && currentGetter == nil && meter == nil && phaseSwitcher == nil: + return &struct { + *OCPP + api.Battery + }{ + OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + } + + case battery != nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: + return &struct { + *OCPP + api.Battery + api.Meter + }{ + OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + } + + case battery != nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: + return &struct { + *OCPP + api.Battery + api.Meter + api.MeterEnergy + }{ + OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case battery != nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: + return &struct { + *OCPP + api.Battery + api.Meter + api.PhaseCurrents }{ OCPP: base, - PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ - phaseSwitcher: phaseSwitcher, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, }, } - case battery == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: return &struct { *OCPP + api.Battery api.Meter - api.PhaseSwitcher + api.MeterEnergy + api.PhaseCurrents }{ OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, - PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ - phaseSwitcher: phaseSwitcher, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + } + + case battery != nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: + return &struct { + *OCPP + api.Battery + api.Meter + api.PhaseVoltages + }{ + OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, }, } - case battery == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: return &struct { *OCPP + api.Battery api.Meter api.MeterEnergy - api.PhaseSwitcher + api.PhaseVoltages }{ OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, MeterEnergy: &decorateOCPPMeterEnergyImpl{ meterEnergy: meterEnergy, }, - PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ - phaseSwitcher: phaseSwitcher, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, }, } - case battery == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: return &struct { *OCPP + api.Battery api.Meter api.PhaseCurrents - api.PhaseSwitcher + api.PhaseVoltages }{ OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ phaseCurrents: phaseCurrents, }, - PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ - phaseSwitcher: phaseSwitcher, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, }, } - case battery == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: return &struct { *OCPP + api.Battery api.Meter api.MeterEnergy api.PhaseCurrents - api.PhaseSwitcher + api.PhaseVoltages }{ OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, @@ -229,86 +894,212 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ phaseCurrents: phaseCurrents, }, - PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ - phaseSwitcher: phaseSwitcher, + PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ + phaseVoltages: phaseVoltages, + }, + } + + case battery != nil && currentGetter != nil && meter == nil && phaseSwitcher == nil: + return &struct { + *OCPP + api.Battery + api.CurrentGetter + }{ + OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + } + + case battery != nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: + return &struct { + *OCPP + api.Battery + api.CurrentGetter + api.Meter + }{ + OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, }, } - case battery == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: return &struct { *OCPP + api.Battery + api.CurrentGetter api.Meter - api.PhaseSwitcher - api.PhaseVoltages + api.MeterEnergy }{ OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, - PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ - phaseSwitcher: phaseSwitcher, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case battery != nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: + return &struct { + *OCPP + api.Battery + api.CurrentGetter + api.Meter + api.PhaseCurrents + }{ + OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + } + + case battery != nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: + return &struct { + *OCPP + api.Battery + api.CurrentGetter + api.Meter + api.MeterEnergy + api.PhaseCurrents + }{ + OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, + }, + MeterEnergy: &decorateOCPPMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ + phaseCurrents: phaseCurrents, + }, + } + + case battery != nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: + return &struct { + *OCPP + api.Battery + api.CurrentGetter + api.Meter + api.PhaseVoltages + }{ + OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, + Meter: &decorateOCPPMeterImpl{ + meter: meter, }, PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ phaseVoltages: phaseVoltages, }, } - case battery == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: return &struct { *OCPP + api.Battery + api.CurrentGetter api.Meter api.MeterEnergy - api.PhaseSwitcher api.PhaseVoltages }{ OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, MeterEnergy: &decorateOCPPMeterEnergyImpl{ meterEnergy: meterEnergy, }, - PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ - phaseSwitcher: phaseSwitcher, - }, PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ phaseVoltages: phaseVoltages, }, } - case battery == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: return &struct { *OCPP + api.Battery + api.CurrentGetter api.Meter api.PhaseCurrents - api.PhaseSwitcher api.PhaseVoltages }{ OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ phaseCurrents: phaseCurrents, }, - PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ - phaseSwitcher: phaseSwitcher, - }, PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ phaseVoltages: phaseVoltages, }, } - case battery == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: return &struct { *OCPP + api.Battery + api.CurrentGetter api.Meter api.MeterEnergy api.PhaseCurrents - api.PhaseSwitcher api.PhaseVoltages }{ OCPP: base, + Battery: &decorateOCPPBatteryImpl{ + battery: battery, + }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, @@ -318,30 +1109,32 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ phaseCurrents: phaseCurrents, }, - PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ - phaseSwitcher: phaseSwitcher, - }, PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ phaseVoltages: phaseVoltages, }, } - case battery != nil && meter == nil && phaseSwitcher == nil: + case battery != nil && currentGetter == nil && meter == nil && phaseSwitcher != nil: return &struct { *OCPP api.Battery + api.PhaseSwitcher }{ OCPP: base, Battery: &decorateOCPPBatteryImpl{ battery: battery, }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, } - case battery != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: return &struct { *OCPP api.Battery api.Meter + api.PhaseSwitcher }{ OCPP: base, Battery: &decorateOCPPBatteryImpl{ @@ -350,14 +1143,18 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() Meter: &decorateOCPPMeterImpl{ meter: meter, }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, } - case battery != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages == nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: return &struct { *OCPP api.Battery api.Meter api.MeterEnergy + api.PhaseSwitcher }{ OCPP: base, Battery: &decorateOCPPBatteryImpl{ @@ -369,14 +1166,18 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() MeterEnergy: &decorateOCPPMeterEnergyImpl{ meterEnergy: meterEnergy, }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, } - case battery != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: return &struct { *OCPP api.Battery api.Meter api.PhaseCurrents + api.PhaseSwitcher }{ OCPP: base, Battery: &decorateOCPPBatteryImpl{ @@ -388,15 +1189,19 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ phaseCurrents: phaseCurrents, }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, } - case battery != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages == nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: return &struct { *OCPP api.Battery api.Meter api.MeterEnergy api.PhaseCurrents + api.PhaseSwitcher }{ OCPP: base, Battery: &decorateOCPPBatteryImpl{ @@ -411,13 +1216,17 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ phaseCurrents: phaseCurrents, }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, } - case battery != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: return &struct { *OCPP api.Battery api.Meter + api.PhaseSwitcher api.PhaseVoltages }{ OCPP: base, @@ -427,17 +1236,21 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() Meter: &decorateOCPPMeterImpl{ meter: meter, }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ phaseVoltages: phaseVoltages, }, } - case battery != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher == nil && phaseVoltages != nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: return &struct { *OCPP api.Battery api.Meter api.MeterEnergy + api.PhaseSwitcher api.PhaseVoltages }{ OCPP: base, @@ -450,17 +1263,21 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() MeterEnergy: &decorateOCPPMeterEnergyImpl{ meterEnergy: meterEnergy, }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ phaseVoltages: phaseVoltages, }, } - case battery != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: return &struct { *OCPP api.Battery api.Meter api.PhaseCurrents + api.PhaseSwitcher api.PhaseVoltages }{ OCPP: base, @@ -473,18 +1290,22 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ phaseCurrents: phaseCurrents, }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ phaseVoltages: phaseVoltages, }, } - case battery != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher == nil && phaseVoltages != nil: + case battery != nil && currentGetter == nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: return &struct { *OCPP api.Battery api.Meter api.MeterEnergy api.PhaseCurrents + api.PhaseSwitcher api.PhaseVoltages }{ OCPP: base, @@ -500,30 +1321,38 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() PhaseCurrents: &decorateOCPPPhaseCurrentsImpl{ phaseCurrents: phaseCurrents, }, + PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, PhaseVoltages: &decorateOCPPPhaseVoltagesImpl{ phaseVoltages: phaseVoltages, }, } - case battery != nil && meter == nil && phaseSwitcher != nil: + case battery != nil && currentGetter != nil && meter == nil && phaseSwitcher != nil: return &struct { *OCPP api.Battery + api.CurrentGetter api.PhaseSwitcher }{ OCPP: base, Battery: &decorateOCPPBatteryImpl{ battery: battery, }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, PhaseSwitcher: &decorateOCPPPhaseSwitcherImpl{ phaseSwitcher: phaseSwitcher, }, } - case battery != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: return &struct { *OCPP api.Battery + api.CurrentGetter api.Meter api.PhaseSwitcher }{ @@ -531,6 +1360,9 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() Battery: &decorateOCPPBatteryImpl{ battery: battery, }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, @@ -539,10 +1371,11 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages == nil: return &struct { *OCPP api.Battery + api.CurrentGetter api.Meter api.MeterEnergy api.PhaseSwitcher @@ -551,6 +1384,9 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() Battery: &decorateOCPPBatteryImpl{ battery: battery, }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, @@ -562,10 +1398,11 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: return &struct { *OCPP api.Battery + api.CurrentGetter api.Meter api.PhaseCurrents api.PhaseSwitcher @@ -574,6 +1411,9 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() Battery: &decorateOCPPBatteryImpl{ battery: battery, }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, @@ -585,10 +1425,11 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages == nil: return &struct { *OCPP api.Battery + api.CurrentGetter api.Meter api.MeterEnergy api.PhaseCurrents @@ -598,6 +1439,9 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() Battery: &decorateOCPPBatteryImpl{ battery: battery, }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, @@ -612,10 +1456,11 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: return &struct { *OCPP api.Battery + api.CurrentGetter api.Meter api.PhaseSwitcher api.PhaseVoltages @@ -624,6 +1469,9 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() Battery: &decorateOCPPBatteryImpl{ battery: battery, }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, @@ -635,10 +1483,11 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents == nil && phaseSwitcher != nil && phaseVoltages != nil: return &struct { *OCPP api.Battery + api.CurrentGetter api.Meter api.MeterEnergy api.PhaseSwitcher @@ -648,6 +1497,9 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() Battery: &decorateOCPPBatteryImpl{ battery: battery, }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, @@ -662,10 +1514,11 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy == nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: return &struct { *OCPP api.Battery + api.CurrentGetter api.Meter api.PhaseCurrents api.PhaseSwitcher @@ -675,6 +1528,9 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() Battery: &decorateOCPPBatteryImpl{ battery: battery, }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, @@ -689,10 +1545,11 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() }, } - case battery != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: + case battery != nil && currentGetter != nil && meter != nil && meterEnergy != nil && phaseCurrents != nil && phaseSwitcher != nil && phaseVoltages != nil: return &struct { *OCPP api.Battery + api.CurrentGetter api.Meter api.MeterEnergy api.PhaseCurrents @@ -703,6 +1560,9 @@ func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() Battery: &decorateOCPPBatteryImpl{ battery: battery, }, + CurrentGetter: &decorateOCPPCurrentGetterImpl{ + currentGetter: currentGetter, + }, Meter: &decorateOCPPMeterImpl{ meter: meter, }, @@ -732,6 +1592,14 @@ func (impl *decorateOCPPBatteryImpl) Soc() (float64, error) { return impl.battery() } +type decorateOCPPCurrentGetterImpl struct { + currentGetter func() (float64, error) +} + +func (impl *decorateOCPPCurrentGetterImpl) GetMaxCurrent() (float64, error) { + return impl.currentGetter() +} + type decorateOCPPMeterImpl struct { meter func() (float64, error) } From 42fa9d263ebfe99787c372d446402bf227e0b9e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20He=C3=9F?= Date: Mon, 16 Sep 2024 20:41:51 +0200 Subject: [PATCH 042/116] Easee: obey current limits based on charger configuration (#16116) --- charger/easee.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/charger/easee.go b/charger/easee.go index 063c670737..2d4ffb4c9f 100644 --- a/charger/easee.go +++ b/charger/easee.go @@ -50,6 +50,7 @@ type Easee struct { log *util.Logger mux sync.RWMutex lastEnergyPollMux sync.Mutex + maxChargerCurrent float64 dynamicChargerCurrent float64 current float64 chargerEnabled bool @@ -314,6 +315,8 @@ func (c *Easee) ProductUpdate(i json.RawMessage) { c.phaseMode = value.(int) case easee.OUTPUT_PHASE: c.outputPhase = value.(int) / 10 // API gives 0,10,30 for 0,1,3p + case easee.MAX_CHARGER_CURRENT: + c.maxChargerCurrent = value.(float64) case easee.DYNAMIC_CHARGER_CURRENT: c.dynamicChargerCurrent = value.(float64) @@ -649,6 +652,9 @@ func (c *Easee) waitForDynamicChargerCurrent(targetCurrent float64) error { // MaxCurrent implements the api.Charger interface func (c *Easee) MaxCurrent(current int64) error { cur := float64(current) + if c.maxChargerCurrent != 0 { + cur = min(cur, c.maxChargerCurrent) + } data := easee.ChargerSettings{ DynamicChargerCurrent: &cur, } From 0157ea6276fd0eb838e71487f7b3bdc149153372 Mon Sep 17 00:00:00 2001 From: Tom Jason Schwanke Date: Tue, 17 Sep 2024 21:23:35 +0200 Subject: [PATCH 043/116] Mqtt: add mTLS authentication using certificates to MQTT (#15563) --- assets/js/components/Config/MqttModal.vue | 21 ++++++- .../components/Config/PropertyCertField.vue | 55 +++++++++++++++++++ cmd/configure/helper.go | 17 ++++-- cmd/setup.go | 2 +- i18n/de.toml | 4 ++ i18n/en.toml | 4 ++ provider/mqtt/client.go | 35 +++++++++--- provider/mqtt/registry.go | 6 +- util/templates/includes/mqtt.tpl | 9 +++ 9 files changed, 136 insertions(+), 17 deletions(-) create mode 100644 assets/js/components/Config/PropertyCertField.vue diff --git a/assets/js/components/Config/MqttModal.vue b/assets/js/components/Config/MqttModal.vue index ee22621aae..8949d5d52d 100644 --- a/assets/js/components/Config/MqttModal.vue +++ b/assets/js/components/Config/MqttModal.vue @@ -63,6 +63,23 @@ + + + @@ -70,10 +87,12 @@ diff --git a/assets/js/components/Config/PropertyCertField.vue b/assets/js/components/Config/PropertyCertField.vue new file mode 100644 index 0000000000..9a470115c2 --- /dev/null +++ b/assets/js/components/Config/PropertyCertField.vue @@ -0,0 +1,55 @@ +