From 37c4552e1fa7aa72ac88cd42872fcf393b4db040 Mon Sep 17 00:00:00 2001 From: andig Date: Thu, 7 Nov 2024 21:30:32 +0100 Subject: [PATCH 01/58] Welcome Charge: fix templates (#17132) --- templates/definition/charger/keba-modbus.yaml | 2 +- templates/definition/vehicle/bmw.yaml | 2 +- templates/definition/vehicle/dacia.yaml | 2 +- templates/definition/vehicle/fiat.yaml | 2 +- templates/definition/vehicle/mini.yaml | 2 +- templates/definition/vehicle/seat-cupra.yaml | 2 +- templates/definition/vehicle/smart-hello.yaml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/templates/definition/charger/keba-modbus.yaml b/templates/definition/charger/keba-modbus.yaml index 11cfb4829b..dbaf2fddcf 100644 --- a/templates/definition/charger/keba-modbus.yaml +++ b/templates/definition/charger/keba-modbus.yaml @@ -24,6 +24,6 @@ params: render: | type: keba-modbus {{- include "modbus" . }} - {{- if .welcomecharge }} + {{- if eq .welcomecharge "true" }} features: ["welcomecharge"] {{- end }} diff --git a/templates/definition/vehicle/bmw.yaml b/templates/definition/vehicle/bmw.yaml index 0fb06944bc..04442f15d1 100644 --- a/templates/definition/vehicle/bmw.yaml +++ b/templates/definition/vehicle/bmw.yaml @@ -24,6 +24,6 @@ render: | {{- if ne .region "EU" }} region: {{ .region }} {{- end }} - {{- if .welcomecharge }} + {{- if eq .welcomecharge "true" }} features: ["welcomecharge"] {{- end }} diff --git a/templates/definition/vehicle/dacia.yaml b/templates/definition/vehicle/dacia.yaml index c48e746c25..a62f44f0c8 100644 --- a/templates/definition/vehicle/dacia.yaml +++ b/templates/definition/vehicle/dacia.yaml @@ -10,6 +10,6 @@ render: | type: dacia {{ include "vehicle-base" . }} {{ include "vehicle-identify" . }} - {{- if .welcomecharge }} + {{- if eq .welcomecharge "true" }} features: ["welcomecharge"] {{- end }} diff --git a/templates/definition/vehicle/fiat.yaml b/templates/definition/vehicle/fiat.yaml index d55272f7b7..71923bf9dc 100644 --- a/templates/definition/vehicle/fiat.yaml +++ b/templates/definition/vehicle/fiat.yaml @@ -18,6 +18,6 @@ render: | pin: {{ .pin }} # mandatory to deep refresh Soc {{- end }} {{ include "vehicle-identify" . }} - {{- if .welcomecharge }} + {{- if eq .welcomecharge "true" }} features: ["welcomecharge"] {{- end }} diff --git a/templates/definition/vehicle/mini.yaml b/templates/definition/vehicle/mini.yaml index 2e797d79a4..6b1b7a12f5 100644 --- a/templates/definition/vehicle/mini.yaml +++ b/templates/definition/vehicle/mini.yaml @@ -24,6 +24,6 @@ render: | {{- if ne .region "EU" }} region: {{ .region }} {{- end }} - {{- if .welcomecharge }} + {{- if eq .welcomecharge "true" }} features: ["welcomecharge"] {{- end }} diff --git a/templates/definition/vehicle/seat-cupra.yaml b/templates/definition/vehicle/seat-cupra.yaml index aacb774a8d..6aab57ac07 100644 --- a/templates/definition/vehicle/seat-cupra.yaml +++ b/templates/definition/vehicle/seat-cupra.yaml @@ -12,6 +12,6 @@ render: | type: cupra {{ include "vehicle-base" . }} {{ include "vehicle-identify" . }} - {{- if .welcomecharge }} + {{- if eq .welcomecharge "true" }} features: ["welcomecharge"] {{- end }} diff --git a/templates/definition/vehicle/smart-hello.yaml b/templates/definition/vehicle/smart-hello.yaml index 064990d5e9..61f799ac22 100644 --- a/templates/definition/vehicle/smart-hello.yaml +++ b/templates/definition/vehicle/smart-hello.yaml @@ -12,6 +12,6 @@ render: | type: smart-hello {{ include "vehicle-base" . }} {{ include "vehicle-identify" . }} - {{- if .welcomecharge }} + {{- if eq .welcomecharge "true" }} features: ["welcomecharge"] {{- end }} From 980a447f769d947ab4e28aeec7370743430c4d1a Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 8 Nov 2024 08:23:24 +0100 Subject: [PATCH 02/58] Tariffs: assign tax and charges to formula --- tariff/embed.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tariff/embed.go b/tariff/embed.go index 9da6d63c8a..392f624b75 100644 --- a/tariff/embed.go +++ b/tariff/embed.go @@ -34,6 +34,14 @@ func (t *embed) init() error { return err } + if _, err := vm.Eval(fmt.Sprintf("charges = %f", t.Charges)); err != nil { + return err + } + + if _, err := vm.Eval(fmt.Sprintf("tax = %f", t.Tax)); err != nil { + return err + } + prg, err := vm.Compile(t.Formula) if err != nil { return err From a5020c875040d5a98bcfe3dffa970559c325910b Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 8 Nov 2024 09:43:20 +0100 Subject: [PATCH 03/58] Telegram: fix panic on arm64 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6ce5b6ce5d..50d1ec8d25 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/glebarez/sqlite v1.11.0 github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1 github.com/go-playground/validator/v10 v10.22.1 - github.com/go-telegram/bot v1.10.0 + github.com/go-telegram/bot v1.10.1 github.com/go-viper/mapstructure/v2 v2.2.1 github.com/godbus/dbus/v5 v5.1.0 github.com/gokrazy/updater v0.0.0-20240113102150-4ac511a17e33 diff --git a/go.sum b/go.sum index 35ad3e1dd1..62c1bf242b 100644 --- a/go.sum +++ b/go.sum @@ -209,8 +209,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-telegram/bot v1.10.0 h1:/Y9ZupcZhYQiAOFE1ETCF8P4836XE42nDkLcWHYTg3g= -github.com/go-telegram/bot v1.10.0/go.mod h1:i2TRs7fXWIeaceF3z7KzsMt/he0TwkVC680mvdTFYeM= +github.com/go-telegram/bot v1.10.1 h1:zwbEjz6ZlqBsyT5EqNqZDYX1ogHIiln1lwYpcK3E8XA= +github.com/go-telegram/bot v1.10.1/go.mod h1:i2TRs7fXWIeaceF3z7KzsMt/he0TwkVC680mvdTFYeM= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= From bcc405217a69e789e2059a600008ff5f2e6f798c Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 8 Nov 2024 18:09:15 +0100 Subject: [PATCH 04/58] Planner: fix slot comparison (#17146) --- core/loadpoint_plan.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/loadpoint_plan.go b/core/loadpoint_plan.go index 389ecbb5b4..a437355978 100644 --- a/core/loadpoint_plan.go +++ b/core/loadpoint_plan.go @@ -169,7 +169,7 @@ func (lp *Loadpoint) plannerActive() (active bool) { // don't stop an already running slot if goal was not met lp.log.DEBUG.Println("plan: continuing until end of slot") return true - case requiredDuration < smallGapDuration: + case requiredDuration < smallSlotDuration: lp.log.DEBUG.Printf("plan: continuing for remaining %v", requiredDuration.Round(time.Second)) return true case lp.clock.Until(planStart) < smallGapDuration: From 9887fec26ac46548a9732b7ae2acfb0451db4a06 Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 8 Nov 2024 18:23:59 +0100 Subject: [PATCH 05/58] Site: show vehicle detection warning only if no identifiers configured --- core/site.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/site.go b/core/site.go index 4a7d992b16..8e4a4388cc 100644 --- a/core/site.go +++ b/core/site.go @@ -338,7 +338,7 @@ func (site *Site) DumpConfig() { // verify vehicle detection if vehicles := site.Vehicles().Instances(); len(vehicles) > 1 { for _, v := range vehicles { - if _, ok := v.(api.ChargeState); !ok { + if _, ok := v.(api.ChargeState); !ok && len(v.Identifiers()) == 0 { site.log.WARN.Printf("vehicle '%s' does not support automatic detection", v.Title()) } } From e451464d3dcf18469c023e9e9265c2e349ee9630 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 9 Nov 2024 10:42:23 +0100 Subject: [PATCH 06/58] chore: simplify topics --- server/mqtt.go | 54 +++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/server/mqtt.go b/server/mqtt.go index a676c71b94..27063b0eec 100644 --- a/server/mqtt.go +++ b/server/mqtt.go @@ -173,19 +173,19 @@ func (m *MQTT) Listen(site site.API) error { func (m *MQTT) listenSiteSetters(topic string, site site.API) error { for _, s := range []setter{ - {"/bufferSoc", floatSetter(site.SetBufferSoc)}, - {"/bufferStartSoc", floatSetter(site.SetBufferStartSoc)}, - {"/batteryDischargeControl", boolSetter(site.SetBatteryDischargeControl)}, - {"/prioritySoc", floatSetter(site.SetPrioritySoc)}, - {"/residualPower", floatSetter(site.SetResidualPower)}, - {"/smartCostLimit", floatPtrSetter(pass(func(limit *float64) { + {"bufferSoc", floatSetter(site.SetBufferSoc)}, + {"bufferStartSoc", floatSetter(site.SetBufferStartSoc)}, + {"batteryDischargeControl", boolSetter(site.SetBatteryDischargeControl)}, + {"prioritySoc", floatSetter(site.SetPrioritySoc)}, + {"residualPower", floatSetter(site.SetResidualPower)}, + {"smartCostLimit", floatPtrSetter(pass(func(limit *float64) { for _, lp := range site.Loadpoints() { lp.SetSmartCostLimit(limit) } }))}, - {"/batteryGridChargeLimit", floatPtrSetter(pass(site.SetBatteryGridChargeLimit))}, + {"batteryGridChargeLimit", floatPtrSetter(pass(site.SetBatteryGridChargeLimit))}, } { - if err := m.Handler.ListenSetter(topic+s.topic, s.fun); err != nil { + if err := m.Handler.ListenSetter(topic+"/"+s.topic, s.fun); err != nil { return err } } @@ -195,19 +195,19 @@ func (m *MQTT) listenSiteSetters(topic string, site site.API) error { func (m *MQTT) listenLoadpointSetters(topic string, site site.API, lp loadpoint.API) error { for _, s := range []setter{ - {"/mode", setterFunc(api.ChargeModeString, pass(lp.SetMode))}, - {"/phases", intSetter(lp.SetPhases)}, - {"/limitSoc", intSetter(pass(lp.SetLimitSoc))}, - {"/minCurrent", floatSetter(lp.SetMinCurrent)}, - {"/maxCurrent", floatSetter(lp.SetMaxCurrent)}, - {"/limitEnergy", floatSetter(pass(lp.SetLimitEnergy))}, - {"/enableThreshold", floatSetter(pass(lp.SetEnableThreshold))}, - {"/disableThreshold", floatSetter(pass(lp.SetDisableThreshold))}, - {"/enableDelay", durationSetter(pass(lp.SetEnableDelay))}, - {"/disableDelay", durationSetter(pass(lp.SetDisableDelay))}, - {"/smartCostLimit", floatPtrSetter(pass(lp.SetSmartCostLimit))}, - {"/batteryBoost", boolSetter(lp.SetBatteryBoost)}, - {"/planEnergy", func(payload string) error { + {"mode", setterFunc(api.ChargeModeString, pass(lp.SetMode))}, + {"phases", intSetter(lp.SetPhases)}, + {"limitSoc", intSetter(pass(lp.SetLimitSoc))}, + {"minCurrent", floatSetter(lp.SetMinCurrent)}, + {"maxCurrent", floatSetter(lp.SetMaxCurrent)}, + {"limitEnergy", floatSetter(pass(lp.SetLimitEnergy))}, + {"enableThreshold", floatSetter(pass(lp.SetEnableThreshold))}, + {"disableThreshold", floatSetter(pass(lp.SetDisableThreshold))}, + {"enableDelay", durationSetter(pass(lp.SetEnableDelay))}, + {"disableDelay", durationSetter(pass(lp.SetDisableDelay))}, + {"smartCostLimit", floatPtrSetter(pass(lp.SetSmartCostLimit))}, + {"batteryBoost", boolSetter(lp.SetBatteryBoost)}, + {"planEnergy", func(payload string) error { var plan struct { Time time.Time `json:"time"` Value float64 `json:"value"` @@ -218,7 +218,7 @@ func (m *MQTT) listenLoadpointSetters(topic string, site site.API, lp loadpoint. } return err }}, - {"/vehicle", func(payload string) error { + {"vehicle", func(payload string) error { // https://github.com/evcc-io/evcc/issues/11184 empty payload is swallowed by listener if payload == "-" { lp.SetVehicle(nil) @@ -231,7 +231,7 @@ func (m *MQTT) listenLoadpointSetters(topic string, site site.API, lp loadpoint. return err }}, } { - if err := m.Handler.ListenSetter(topic+s.topic, s.fun); err != nil { + if err := m.Handler.ListenSetter(topic+"/"+s.topic, s.fun); err != nil { return err } } @@ -241,9 +241,9 @@ func (m *MQTT) listenLoadpointSetters(topic string, site site.API, lp loadpoint. func (m *MQTT) listenVehicleSetters(topic string, v vehicle.API) error { for _, s := range []setter{ - {topic + "/limitSoc", intSetter(pass(v.SetLimitSoc))}, - {topic + "/minSoc", intSetter(pass(v.SetMinSoc))}, - {topic + "/planSoc", func(payload string) error { + {"limitSoc", intSetter(pass(v.SetLimitSoc))}, + {"minSoc", intSetter(pass(v.SetMinSoc))}, + {"planSoc", func(payload string) error { var plan struct { Time time.Time `json:"time"` Value int `json:"value"` @@ -255,7 +255,7 @@ func (m *MQTT) listenVehicleSetters(topic string, v vehicle.API) error { return err }}, } { - if err := m.Handler.ListenSetter(s.topic, s.fun); err != nil { + if err := m.Handler.ListenSetter(topic+"/"+s.topic, s.fun); err != nil { return err } } From 6626ac50b0d224d60739667b45b1846fbeec34f3 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 9 Nov 2024 10:58:24 +0100 Subject: [PATCH 07/58] chore: use api error --- tariff/edf-tempo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tariff/edf-tempo.go b/tariff/edf-tempo.go index 2adf03c2ec..2c41fee262 100644 --- a/tariff/edf-tempo.go +++ b/tariff/edf-tempo.go @@ -50,7 +50,7 @@ func NewEdfTempoFromConfig(other map[string]interface{}) (api.Tariff, error) { } if cc.ClientID == "" || cc.ClientSecret == "" { - return nil, errors.New("missing credentials") + return nil, api.ErrMissingCredentials } if err := cc.init(); err != nil { From 355c0e3ffeb92f130291c19e7b2ab18aa3f45b4f Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 9 Nov 2024 11:07:13 +0100 Subject: [PATCH 08/58] Polestar: upgrade api --- vehicle/polestar/identity.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vehicle/polestar/identity.go b/vehicle/polestar/identity.go index 9c5e18fc16..53e6f87c77 100644 --- a/vehicle/polestar/identity.go +++ b/vehicle/polestar/identity.go @@ -24,7 +24,7 @@ const OAuthURI = "https://polestarid.eu.polestar.com" // https://polestarid.eu.polestar.com/.well-known/openid-configuration var OAuth2Config = &oauth2.Config{ - ClientID: "polmystar", + ClientID: "l3oopkc_10", RedirectURL: "https://www.polestar.com/sign-in-callback", Endpoint: oauth2.Endpoint{ AuthURL: OAuthURI + "/as/authorization.oauth2", From 189a3cf57f17c31b18d80dbf547b6d160d26f205 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 9 Nov 2024 12:30:45 +0100 Subject: [PATCH 09/58] Add Zendure (#17149) --- meter/zendure.go | 71 ++++++++++++++++++++ meter/zendure/connection.go | 86 +++++++++++++++++++++++++ meter/zendure/credentials.go | 31 +++++++++ meter/zendure/types.go | 60 +++++++++++++++++ templates/definition/meter/zendure.yaml | 22 +++++++ 5 files changed, 270 insertions(+) create mode 100644 meter/zendure.go create mode 100644 meter/zendure/connection.go create mode 100644 meter/zendure/credentials.go create mode 100644 meter/zendure/types.go create mode 100644 templates/definition/meter/zendure.yaml diff --git a/meter/zendure.go b/meter/zendure.go new file mode 100644 index 0000000000..e3fb541b25 --- /dev/null +++ b/meter/zendure.go @@ -0,0 +1,71 @@ +package meter + +import ( + "fmt" + "time" + + "github.com/evcc-io/evcc/api" + "github.com/evcc-io/evcc/meter/zendure" + "github.com/evcc-io/evcc/util" +) + +func init() { + registry.Add("zendure", NewZendureFromConfig) +} + +type Zendure struct { + usage string + conn *zendure.Connection +} + +// NewZendureFromConfig creates a Zendure meter from generic config +func NewZendureFromConfig(other map[string]interface{}) (api.Meter, error) { + cc := struct { + Usage, Account, Serial string + Timeout time.Duration + }{ + Timeout: 30 * time.Second, + } + + if err := util.DecodeOther(other, &cc); err != nil { + return nil, err + } + + conn, err := zendure.NewConnection(cc.Account, cc.Serial, cc.Timeout) + if err != nil { + return nil, err + } + + c := &Zendure{ + usage: cc.Usage, + conn: conn, + } + + return c, err +} + +// CurrentPower implements the api.Meter interface +func (c *Zendure) CurrentPower() (float64, error) { + res, err := c.conn.Data() + if err != nil { + return 0, err + } + + switch c.usage { + case "pv": + return float64(res.SolarInputPower), nil + case "battery": + return float64(res.GridInputPower) - float64(res.OutputHomePower), nil + default: + return 0, fmt.Errorf("invalid usage: %s", c.usage) + } +} + +// Soc implements the api.Battery interface +func (c *Zendure) Soc() (float64, error) { + res, err := c.conn.Data() + if err != nil { + return 0, err + } + return float64(res.ElectricLevel), nil +} diff --git a/meter/zendure/connection.go b/meter/zendure/connection.go new file mode 100644 index 0000000000..758d4ad83a --- /dev/null +++ b/meter/zendure/connection.go @@ -0,0 +1,86 @@ +package zendure + +import ( + "encoding/json" + "net" + "strconv" + "sync" + "time" + + "dario.cat/mergo" + "github.com/evcc-io/evcc/provider/mqtt" + "github.com/evcc-io/evcc/util" +) + +var ( + mu sync.Mutex + connections = make(map[string]*Connection) +) + +type Connection struct { + log *util.Logger + data *util.Monitor[Data] +} + +func NewConnection(account, serial string, timeout time.Duration) (*Connection, error) { + mu.Lock() + defer mu.Unlock() + + key := account + serial + if conn, ok := connections[key]; ok { + return conn, nil + } + + res, err := MqttCredentials(account, serial) + if err != nil { + return nil, err + } + + log := util.NewLogger("zendure") + client, err := mqtt.NewClient( + log, + net.JoinHostPort(res.Data.MqttUrl, strconv.Itoa(res.Data.Port)), res.Data.AppKey, res.Data.Secret, + "", 0, false, "", "", "", + ) + if err != nil { + return nil, err + } + + conn := &Connection{ + log: log, + data: util.NewMonitor[Data](timeout), + } + + topic := res.Data.AppKey + "/#" + if err := client.Listen(topic, conn.handler); err != nil { + return nil, err + } + + connections[key] = conn + + return conn, nil +} + +func (c *Connection) handler(data string) { + var res Payload + if err := json.Unmarshal([]byte(data), &res); err != nil { + c.log.ERROR.Println(err) + return + } + + if res.Data == nil { + return + } + + c.data.SetFunc(func(v Data) Data { + if err := mergo.Merge(&v, res.Data); err != nil { + c.log.ERROR.Println(err) + } + + return v + }) +} + +func (c *Connection) Data() (Data, error) { + return c.data.Get() +} diff --git a/meter/zendure/credentials.go b/meter/zendure/credentials.go new file mode 100644 index 0000000000..a64bdccd5d --- /dev/null +++ b/meter/zendure/credentials.go @@ -0,0 +1,31 @@ +package zendure + +import ( + "errors" + "net/http" + + "github.com/evcc-io/evcc/util" + "github.com/evcc-io/evcc/util/request" +) + +const CredentialsUri = "https://app.zendure.tech/eu/developer/api/apply" + +func MqttCredentials(account, serial string) (CredentialsResponse, error) { + client := request.NewHelper(util.NewLogger("zendure")) + + data := CredentialsRequest{ + SnNumber: serial, + Account: account, + } + + req, _ := request.New(http.MethodPost, CredentialsUri, request.MarshalJSON(data), request.JSONEncoding) + + var res CredentialsResponse + err := client.DoJSON(req, &res) + + if err == nil && !res.Success { + err = errors.New(res.Msg) + } + + return res, err +} diff --git a/meter/zendure/types.go b/meter/zendure/types.go new file mode 100644 index 0000000000..bdba8ae5a4 --- /dev/null +++ b/meter/zendure/types.go @@ -0,0 +1,60 @@ +package zendure + +type CredentialsRequest struct { + SnNumber string `json:"snNumber"` + Account string `json:"account"` +} + +type CredentialsResponse struct { + Success bool `json:"success"` + Data struct { + AppKey string `json:"appKey"` + Secret string `json:"secret"` + MqttUrl string `json:"mqttUrl"` + Port int `json:"port"` + } + Msg string `json:"msg"` +} + +type Payload struct { + *Command + *Data +} + +type Command struct { + CommandTopic string `json:"command_topic"` + DeviceClass string `json:"device_class"` + Name string `json:"name"` + PayloadOff bool `json:"payload_off"` + PayloadOn bool `json:"payload_on"` + StateOff bool `json:"state_off"` + StateOn bool `json:"state_on"` + StateTopic string `json:"state_topic"` + UniqueId string `json:"unique_id"` + UnitOfMeasurement string `json:"unit_of_measurement"` + ValueTemplate string `json:"value_template"` +} + +type Data struct { + AcMode int `json:"acMode"` // 1, + BuzzerSwitch bool `json:"buzzerSwitch"` // false, + ElectricLevel int `json:"electricLevel"` // 7, + GridInputPower int `json:"gridInputPower"` // 99, + HeatState int `json:"heatState"` // 0, + HubState int `json:"hubState"` // 0, + HyperTmp int `json:"hyperTmp"` // 2981, + InputLimit int `json:"inputLimit"` // 100, + InverseMaxPower int `json:"inverseMaxPower"` // 1200, + MasterSwitch bool `json:"masterSwitch"` // true, + OutputLimit int `json:"outputLimit"` // 0, + OutputPackPower int `json:"outputPackPower"` // 70, + OutputHomePower int `json:"outputHomePower"` // 70, + PackNum int `json:"packNum"` // 1, + PackState int `json:"packState"` // 0, + RemainInputTime int `json:"remainInputTime"` // 59940, + RemainOutTime int `json:"remainOutTime"` // 59940, + Sn string `json:"sn"` // "EE1LH", + SocSet int `json:"socSet"` // 1000, + SolarInputPower int `json:"solarInputPower"` // 0, + WifiState bool `json:"wifiState"` // true +} diff --git a/templates/definition/meter/zendure.yaml b/templates/definition/meter/zendure.yaml new file mode 100644 index 0000000000..f57b901722 --- /dev/null +++ b/templates/definition/meter/zendure.yaml @@ -0,0 +1,22 @@ +template: zendure +products: + - brand: Zendure + description: + generic: Hyper V +requirements: + evcc: ["skiptest"] +params: + - name: usage + choice: ["pv", "battery"] + - name: account + - name: serial + - name: capacity + default: 2 + advanced: true + - name: timeout +render: | + type: zendure + usage: {{ .usage }} + account: {{ .account }} + serial: {{ .serial }} + timeout: {{ .timeout }} From 2a68ab6e1d1618a79de3154d90f137741cb0db80 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 9 Nov 2024 12:37:18 +0100 Subject: [PATCH 10/58] chore: fix spelling --- api/api.go | 2 +- charger/eebus.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/api.go b/api/api.go index 33860d9350..fb304d4e3b 100644 --- a/api/api.go +++ b/api/api.go @@ -120,7 +120,7 @@ type Authorizer interface { Authorize(key string) error } -// PhaseDescriber returns the number of availablephases +// PhaseDescriber returns the number of available phases type PhaseDescriber interface { Phases() int } diff --git a/charger/eebus.go b/charger/eebus.go index a6c14ade7e..e8fbe9d62b 100644 --- a/charger/eebus.go +++ b/charger/eebus.go @@ -331,7 +331,7 @@ func (c *EEBus) writeCurrentLimitData(evEntity spineapi.EntityRemoteInterface, c } // if VAS VW is available, limits are completely covered by it - // this way evcc can fully control the charging behaviour + // this way evcc can fully control the charging behavior if c.writeLoadControlLimitsVASVW(evEntity, limits) { c.mux.Lock() defer c.mux.Unlock() @@ -410,7 +410,7 @@ func (c *EEBus) hasActiveVASVW(evEntity spineapi.EntityRemoteInterface) bool { return false } -// provides support for the special VW VAS ISO15118-2 charging behaviour if supported +// provides support for the special VW VAS ISO15118-2 charging behavior if supported // will return false if it isn't supported or successful // // this functionality allows to fully control charging without the EV actually having a From fe2978d72412406b43874d292b4706d881e5f54a Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 9 Nov 2024 12:43:23 +0100 Subject: [PATCH 11/58] chore: fix spelling --- api/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/api.go b/api/api.go index fb304d4e3b..9a01f7de1c 100644 --- a/api/api.go +++ b/api/api.go @@ -68,7 +68,7 @@ type CurrentGetter interface { GetMaxCurrent() (float64, error) } -// BatteryController optionally allows to control home battery (dis)charging behaviour +// BatteryController optionally allows to control home battery (dis)charging behavior type BatteryController interface { SetBatteryMode(BatteryMode) error } From ba75820a42a62815fdb90dfd6c351bc4b35f4ddb Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 9 Nov 2024 13:04:18 +0100 Subject: [PATCH 12/58] Ocpp: reduce trace logs --- charger/ocpp/cs_log.go | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/charger/ocpp/cs_log.go b/charger/ocpp/cs_log.go index b4c6138317..adb2e81f0c 100644 --- a/charger/ocpp/cs_log.go +++ b/charger/ocpp/cs_log.go @@ -2,18 +2,33 @@ 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) + // for _, p := range []string{ + // "completed request", + // "dispatched request", + // "enqueued CALL", + // "handling incoming", + // "sent CALL", + // "started timeout", + // "timeout canceled", + // } { + // if strings.HasPrefix(s, p) { + // return + // } // } + + 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 32332fe8a265cc7f5665039fad039def47fff646 Mon Sep 17 00:00:00 2001 From: Markus Thierolf <77847348+thierolm@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:04:08 +0100 Subject: [PATCH 13/58] Add Homewizard kWh meter (#17150) --- charger/homewizard.go | 7 ++--- meter/homewizard.go | 7 ++--- meter/homewizard/connection.go | 13 ++++++++- meter/homewizard/types.go | 4 +++ meter/homewizard/types_test.go | 27 ++++++++++++++++--- .../definition/meter/homewizard-kwh.yaml | 13 +++++++++ .../{homewizard.yaml => homewizard-p1.yaml} | 3 ++- 7 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 templates/definition/meter/homewizard-kwh.yaml rename templates/definition/meter/{homewizard.yaml => homewizard-p1.yaml} (81%) diff --git a/charger/homewizard.go b/charger/homewizard.go index 3a14bf81e0..445503095c 100644 --- a/charger/homewizard.go +++ b/charger/homewizard.go @@ -27,6 +27,7 @@ func NewHomeWizardFromConfig(other map[string]interface{}) (api.Charger, error) cc := struct { embed `mapstructure:",squash"` URI string + Usage string StandbyPower float64 Cache time.Duration }{ @@ -37,12 +38,12 @@ func NewHomeWizardFromConfig(other map[string]interface{}) (api.Charger, error) return nil, err } - return NewHomeWizard(cc.embed, cc.URI, cc.StandbyPower, cc.Cache) + return NewHomeWizard(cc.embed, cc.URI, cc.Usage, cc.StandbyPower, cc.Cache) } // NewHomeWizard creates HomeWizard charger -func NewHomeWizard(embed embed, uri string, standbypower float64, cache time.Duration) (*HomeWizard, error) { - conn, err := homewizard.NewConnection(uri, cache) +func NewHomeWizard(embed embed, uri string, usage string, standbypower float64, cache time.Duration) (*HomeWizard, error) { + conn, err := homewizard.NewConnection(uri, usage, cache) if err != nil { return nil, err } diff --git a/meter/homewizard.go b/meter/homewizard.go index 52d2f1d5bc..73233b4f11 100644 --- a/meter/homewizard.go +++ b/meter/homewizard.go @@ -22,6 +22,7 @@ func init() { func NewHomeWizardFromConfig(other map[string]interface{}) (api.Meter, error) { cc := struct { URI string + Usage string Cache time.Duration }{ Cache: time.Second, @@ -31,12 +32,12 @@ func NewHomeWizardFromConfig(other map[string]interface{}) (api.Meter, error) { return nil, err } - return NewHomeWizard(cc.URI, cc.Cache) + return NewHomeWizard(cc.URI, cc.Usage, cc.Cache) } // NewHomeWizard creates HomeWizard meter -func NewHomeWizard(uri string, cache time.Duration) (*HomeWizard, error) { - conn, err := homewizard.NewConnection(uri, cache) +func NewHomeWizard(uri string, usage string, cache time.Duration) (*HomeWizard, error) { + conn, err := homewizard.NewConnection(uri, usage, cache) if err != nil { return nil, err } diff --git a/meter/homewizard/connection.go b/meter/homewizard/connection.go index 4411eca616..6aa3d3150e 100644 --- a/meter/homewizard/connection.go +++ b/meter/homewizard/connection.go @@ -17,13 +17,14 @@ import ( type Connection struct { *request.Helper uri string + usage string ProductType string dataG provider.Cacheable[DataResponse] stateG provider.Cacheable[StateResponse] } // NewConnection creates a homewizard connection -func NewConnection(uri string, cache time.Duration) (*Connection, error) { +func NewConnection(uri string, usage string, cache time.Duration) (*Connection, error) { if uri == "" { return nil, errors.New("missing uri") } @@ -32,6 +33,7 @@ func NewConnection(uri string, cache time.Duration) (*Connection, error) { c := &Connection{ Helper: request.NewHelper(log), uri: fmt.Sprintf("%s/api", util.DefaultScheme(strings.TrimRight(uri, "/"), "http")), + usage: usage, } c.Client.Transport = request.NewTripper(log, transport.Insecure()) @@ -100,18 +102,27 @@ func (c *Connection) Enabled() (bool, error) { // CurrentPower implements the api.Meter interface func (c *Connection) CurrentPower() (float64, error) { res, err := c.dataG.Get() + if c.usage == "pv" { + return -res.ActivePowerW, err + } return res.ActivePowerW, err } // TotalEnergy implements the api.MeterEnergy interface func (c *Connection) TotalEnergy() (float64, error) { res, err := c.dataG.Get() + if c.usage == "pv" { + return res.TotalPowerExportT1kWh + res.TotalPowerExportT2kWh + res.TotalPowerExportT3kWh + res.TotalPowerExportT4kWh, err + } return res.TotalPowerImportT1kWh + res.TotalPowerImportT2kWh + res.TotalPowerImportT3kWh + res.TotalPowerImportT4kWh, err } // Currents implements the api.PhaseCurrents interface func (c *Connection) Currents() (float64, float64, float64, error) { res, err := c.dataG.Get() + if c.usage == "pv" { + return -res.ActiveCurrentL1A, -res.ActiveCurrentL2A, -res.ActiveCurrentL3A, err + } return res.ActiveCurrentL1A, res.ActiveCurrentL2A, res.ActiveCurrentL3A, err } diff --git a/meter/homewizard/types.go b/meter/homewizard/types.go index 2ab9d97dc0..68a3110cfe 100644 --- a/meter/homewizard/types.go +++ b/meter/homewizard/types.go @@ -21,6 +21,10 @@ type DataResponse struct { TotalPowerImportT2kWh float64 `json:"total_power_import_t2_kwh"` TotalPowerImportT3kWh float64 `json:"total_power_import_t3_kwh"` TotalPowerImportT4kWh float64 `json:"total_power_import_t4_kwh"` + TotalPowerExportT1kWh float64 `json:"total_power_export_t1_kwh"` + TotalPowerExportT2kWh float64 `json:"total_power_export_t2_kwh"` + TotalPowerExportT3kWh float64 `json:"total_power_export_t3_kwh"` + TotalPowerExportT4kWh float64 `json:"total_power_export_t4_kwh"` ActiveCurrentL1A float64 `json:"active_current_l1_a"` ActiveCurrentL2A float64 `json:"active_current_l2_a"` ActiveCurrentL3A float64 `json:"active_current_l3_a"` diff --git a/meter/homewizard/types_test.go b/meter/homewizard/types_test.go index b05e889351..381c5844fd 100644 --- a/meter/homewizard/types_test.go +++ b/meter/homewizard/types_test.go @@ -33,15 +33,16 @@ func TestUnmarshalStateResponse(t *testing.T) { } } -// Test DataResponse -func TestUnmarshalDataResponse(t *testing.T) { +// Test homewizard kWh Meter 1-Phase response +func TestUnmarshalKwhDataResponse(t *testing.T) { { var res DataResponse - + // https://www.homewizard.com/shop/wi-fi-kwh-meter-1-phase/ jsonstr := `{"wifi_ssid": "My Wi-Fi","wifi_strength": 100,"total_power_import_t1_kwh": 30.511,"total_power_export_t1_kwh": 85.951,"active_power_w": 543,"active_power_l1_w": 28,"active_power_l2_w": 0,"active_power_l3_w": -181,"active_voltage_l1_v": 235.4,"active_voltage_l2_v": 235.8,"active_voltage_l3_v": 236.1,"active_current_l1_a": 1.19,"active_current_l2_a": 0.37,"active_current_l3_a": -0.93}` require.NoError(t, json.Unmarshal([]byte(jsonstr), &res)) assert.Equal(t, float64(30.511), res.TotalPowerImportT1kWh+res.TotalPowerImportT2kWh+res.TotalPowerImportT3kWh+res.TotalPowerImportT4kWh) + assert.Equal(t, float64(85.951), res.TotalPowerExportT1kWh+res.TotalPowerExportT2kWh+res.TotalPowerExportT3kWh+res.TotalPowerExportT4kWh) assert.Equal(t, float64(543), res.ActivePowerW) assert.Equal(t, float64(235.4), res.ActiveVoltageL1V) assert.Equal(t, float64(235.8), res.ActiveVoltageL2V) @@ -51,3 +52,23 @@ func TestUnmarshalDataResponse(t *testing.T) { assert.Equal(t, float64(-0.93), res.ActiveCurrentL3A) } } + +// Test homewizard P1 Meter response +func TestUnmarshalP1DataResponse(t *testing.T) { + { + var res DataResponse + // https://www.homewizard.com/shop/wi-fi-p1-meter-rj12-2/ + jsonstr := `{"wifi_ssid":"redacted","wifi_strength":78,"smr_version":50,"meter_model":"Landis + Gyr","unique_id":"redacted","active_tariff":2,"total_power_import_kwh":18664.997,"total_power_import_t1_kwh":10909.724,"total_power_import_t2_kwh":7755.273,"total_power_export_kwh":13823.608,"total_power_export_t1_kwh":4243.981,"total_power_export_t2_kwh":9579.627,"active_power_w":203.000,"active_power_l1_w":-21.000,"active_power_l2_w":57.000,"active_power_l3_w":168.000,"active_voltage_l1_v":228.000,"active_voltage_l2_v":226.000,"active_voltage_l3_v":225.000,"active_current_a":1.091,"active_current_l1_a":-0.092,"active_current_l2_a":0.252,"active_current_l3_a":0.747,"voltage_sag_l1_count":12.000,"voltage_sag_l2_count":12.000,"voltage_sag_l3_count":19.000,"voltage_swell_l1_count":5055.000,"voltage_swell_l2_count":1950.000,"voltage_swell_l3_count":0.000,"any_power_fail_count":12.000,"long_power_fail_count":2.000,"total_gas_m3":5175.363,"gas_timestamp":241106093006,"gas_unique_id":"redacted","external":[{"unique_id":"redacted","type":"gas_meter","timestamp":241106093006,"value":5175.363,"unit":"m3"}]}` + require.NoError(t, json.Unmarshal([]byte(jsonstr), &res)) + + assert.Equal(t, float64(18664.997), res.TotalPowerImportT1kWh+res.TotalPowerImportT2kWh+res.TotalPowerImportT3kWh+res.TotalPowerImportT4kWh) + assert.Equal(t, float64(13823.608), res.TotalPowerExportT1kWh+res.TotalPowerExportT2kWh+res.TotalPowerExportT3kWh+res.TotalPowerExportT4kWh) + assert.Equal(t, float64(203), res.ActivePowerW) + assert.Equal(t, float64(228), res.ActiveVoltageL1V) + assert.Equal(t, float64(226), res.ActiveVoltageL2V) + assert.Equal(t, float64(225), res.ActiveVoltageL3V) + assert.Equal(t, float64(-0.092), res.ActiveCurrentL1A) + assert.Equal(t, float64(0.252), res.ActiveCurrentL2A) + assert.Equal(t, float64(0.747), res.ActiveCurrentL3A) + } +} diff --git a/templates/definition/meter/homewizard-kwh.yaml b/templates/definition/meter/homewizard-kwh.yaml new file mode 100644 index 0000000000..6f8b199419 --- /dev/null +++ b/templates/definition/meter/homewizard-kwh.yaml @@ -0,0 +1,13 @@ +template: homewizard-kwh +products: + - brand: HomeWizard + description: + generic: kWh Meter +params: + - name: usage + choice: ["pv"] + - name: host +render: | + type: homewizard + uri: http://{{ .host }} + usage: {{ .usage }} diff --git a/templates/definition/meter/homewizard.yaml b/templates/definition/meter/homewizard-p1.yaml similarity index 81% rename from templates/definition/meter/homewizard.yaml rename to templates/definition/meter/homewizard-p1.yaml index 6afc3bd167..4f2b70b50b 100644 --- a/templates/definition/meter/homewizard.yaml +++ b/templates/definition/meter/homewizard-p1.yaml @@ -5,8 +5,9 @@ products: generic: Wi-Fi P1 Meter params: - name: usage - choice: ["grid", "pv"] + choice: ["grid"] - name: host render: | type: homewizard uri: http://{{ .host }} + usage: {{ .usage }} From 00715500a55129d4a5df56b5e39d167e9862d518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Sun, 10 Nov 2024 10:57:33 +0100 Subject: [PATCH 14/58] chore: fix calling Docker entrypoint with arguments (#17163) --- packaging/docker/bin/entrypoint.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packaging/docker/bin/entrypoint.sh b/packaging/docker/bin/entrypoint.sh index ed4228b662..1fea90c3ed 100755 --- a/packaging/docker/bin/entrypoint.sh +++ b/packaging/docker/bin/entrypoint.sh @@ -7,9 +7,9 @@ HASSIO_OPTIONSFILE=/data/options.json if [ -f ${HASSIO_OPTIONSFILE} ]; then CONFIG=$(grep -o '"config_file": "[^"]*' ${HASSIO_OPTIONSFILE} | grep -o '[^"]*$') echo "Using config file: ${CONFIG}" - + SQLITE_FILE=$(grep -o '"sqlite_file": "[^"]*' ${HASSIO_OPTIONSFILE} | grep -o '[^"]*$') - + if [ ! -f "${CONFIG}" ]; then echo "Config not found. Please create a config under ${CONFIG}." echo "For details see evcc documentation at https://github.com/evcc-io/evcc#readme." @@ -23,7 +23,10 @@ if [ -f ${HASSIO_OPTIONSFILE} ]; then fi fi else - if [ "$1" = '"evcc"' ] || expr "$1" : '-*' > /dev/null; then + if [ "$1" = 'evcc' ]; then + shift + exec evcc "$@" + elif expr "$1" : '-.*' > /dev/null; then exec evcc "$@" else exec "$@" From b303626ff2a545c050935581718c81636622b27f Mon Sep 17 00:00:00 2001 From: premultiply <4681172+premultiply@users.noreply.github.com> Date: Sun, 10 Nov 2024 17:46:21 +0000 Subject: [PATCH 15/58] chore: fix qcells-hybrid-cloud template --- .../meter/{qcells-hybrid-cloud => qcells-hybrid-cloud.yaml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename templates/definition/meter/{qcells-hybrid-cloud => qcells-hybrid-cloud.yaml} (98%) diff --git a/templates/definition/meter/qcells-hybrid-cloud b/templates/definition/meter/qcells-hybrid-cloud.yaml similarity index 98% rename from templates/definition/meter/qcells-hybrid-cloud rename to templates/definition/meter/qcells-hybrid-cloud.yaml index 1fce99390f..8b1f8bf0f6 100644 --- a/templates/definition/meter/qcells-hybrid-cloud +++ b/templates/definition/meter/qcells-hybrid-cloud.yaml @@ -1,6 +1,6 @@ template: qcells-hybrid-cloud products: - - brand: QCells (based on Solax) + - brand: QCells description: de: Hybrid-Wechselrichter (Cloud) en: Hybrid-Inverter (Cloud) From 7e6e9bc9c206f205479a39ae4f185dfd553a5567 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sun, 10 Nov 2024 19:20:59 +0100 Subject: [PATCH 16/58] Translations update from Hosted Weblate (#16987) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Translated using Weblate (Danish) Currently translated at 100.0% (584 of 584 strings) Translated using Weblate (Danish) Currently translated at 100.0% (585 of 585 strings) Co-authored-by: amtssp Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/da/ Translation: evcc/evcc * Translated using Weblate (Hungarian) Currently translated at 100.0% (584 of 584 strings) Translated using Weblate (Hungarian) Currently translated at 93.6% (548 of 585 strings) Co-authored-by: interstart Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/hu/ Translation: evcc/evcc * Translated using Weblate (Spanish) Currently translated at 100.0% (584 of 584 strings) Translated using Weblate (Spanish) Currently translated at 96.2% (562 of 584 strings) Translated using Weblate (Spanish) Currently translated at 96.2% (561 of 583 strings) Translated using Weblate (Spanish) Currently translated at 94.3% (550 of 583 strings) Translated using Weblate (Spanish) Currently translated at 93.8% (547 of 583 strings) Co-authored-by: gallegonovato Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/es/ Translation: evcc/evcc * Translated using Weblate (Croatian) Currently translated at 100.0% (584 of 584 strings) Translated using Weblate (Croatian) Currently translated at 100.0% (583 of 583 strings) Co-authored-by: Ante Karamatic Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/hr/ Translation: evcc/evcc * Translated using Weblate (Dutch) Currently translated at 100.0% (584 of 584 strings) Translated using Weblate (Dutch) Currently translated at 100.0% (583 of 583 strings) Co-authored-by: ChristofP Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/nl/ Translation: evcc/evcc * Translated using Weblate (Lithuanian) Currently translated at 100.0% (584 of 584 strings) Translated using Weblate (Lithuanian) Currently translated at 100.0% (583 of 583 strings) Co-authored-by: RTTTC <94727758+RTTTC@users.noreply.github.com> Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/lt/ Translation: evcc/evcc * Translated using Weblate (Swedish) Currently translated at 100.0% (583 of 583 strings) Co-authored-by: Jonas Gate Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/sv/ Translation: evcc/evcc * Translated using Weblate (French) Currently translated at 100.0% (584 of 584 strings) Co-authored-by: FraBoCH Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/fr/ Translation: evcc/evcc * Translated using Weblate (Italian) Currently translated at 100.0% (584 of 584 strings) Translated using Weblate (Italian) Currently translated at 100.0% (584 of 584 strings) Co-authored-by: MobilettoSoft Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/it/ Translation: evcc/evcc * Translated using Weblate (Swedish) Currently translated at 100.0% (584 of 584 strings) Co-authored-by: bittin1ddc447d824349b2 Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/sv/ Translation: evcc/evcc * Translated using Weblate (Estonian) Currently translated at 0.5% (3 of 584 strings) Added translation using Weblate (Estonian) Co-authored-by: Priit Jõerüüt Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/et/ Translation: evcc/evcc * Translated using Weblate (Greek) Currently translated at 99.8% (583 of 584 strings) Co-authored-by: Nick Galfas Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/el/ Translation: evcc/evcc * Translated using Weblate (Slovenian) Currently translated at 100.0% (584 of 584 strings) Co-authored-by: Žiga Deisinger Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/sl/ Translation: evcc/evcc * Translated using Weblate (Luxembourgish) Currently translated at 100.0% (584 of 584 strings) Translated using Weblate (Portuguese) Currently translated at 100.0% (584 of 584 strings) Translated using Weblate (Luxembourgish) Currently translated at 98.6% (576 of 584 strings) Translated using Weblate (Portuguese) Currently translated at 99.6% (582 of 584 strings) Co-authored-by: Filipe Lima Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/lb/ Translate-URL: https://hosted.weblate.org/projects/evcc/evcc/pt/ Translation: evcc/evcc * fix toml --------- Co-authored-by: amtssp Co-authored-by: interstart Co-authored-by: gallegonovato Co-authored-by: Ante Karamatic Co-authored-by: ChristofP Co-authored-by: RTTTC <94727758+RTTTC@users.noreply.github.com> Co-authored-by: Jonas Gate Co-authored-by: FraBoCH Co-authored-by: MobilettoSoft Co-authored-by: bittin1ddc447d824349b2 Co-authored-by: Priit Jõerüüt Co-authored-by: Nick Galfas Co-authored-by: Žiga Deisinger Co-authored-by: Filipe Lima Co-authored-by: premultiply <4681172+premultiply@users.noreply.github.com> --- i18n/da.toml | 46 +++++++++++++++++++++++++++++-- i18n/el.toml | 50 +++++++++++++++++++++++++++++++--- i18n/es.toml | 50 ++++++++++++++++++++++++++++++++-- i18n/et.toml | 4 +++ i18n/fr.toml | 24 +++++++++++++++-- i18n/hr.toml | 26 +++++++++++++++--- i18n/hu.toml | 54 +++++++++++++++++++++++++++++++++++-- i18n/it.toml | 76 +++++++++++++++++++++++++++++++++++++++++++++------- i18n/lb.toml | 28 ++++++++++++++++--- i18n/lt.toml | 32 +++++++++++++++++----- i18n/nl.toml | 32 +++++++++++++++++++--- i18n/pt.toml | 68 +++++++++++++++++++++++++++++----------------- i18n/sl.toml | 46 +++++++++++++++++++++++++++++-- i18n/sv.toml | 54 +++++++++++++++++++++++++++++++++++-- 14 files changed, 523 insertions(+), 67 deletions(-) create mode 100644 i18n/et.toml diff --git a/i18n/da.toml b/i18n/da.toml index 6fd3e52205..3911f3b51c 100644 --- a/i18n/da.toml +++ b/i18n/da.toml @@ -63,6 +63,7 @@ enabled = "Aktiveret" energy = "Energi" feedinPrice = "Indfødningstarif" gridPrice = "God pris" +hemsType = "System" no = "nej" odometer = "Kilometertæller" org = "Organisation" @@ -437,7 +438,7 @@ co2 = "⌀ CO₂" duration = "Varighed" fallbackName = "Ladepunkt" power = "Effekt" -price = "Σ Pris" +price = "Pris" remaining = "Resterende tid" remoteDisabledHard = "{source}: slukket" remoteDisabledSoft = "{source}: Adaptiv sol-opladning er slukket" @@ -640,13 +641,33 @@ downloadCsv = "Download som CSV" energy = "Opladet" loadpoint = "Ladepunkt" noData = "Ingen opladninger i denne måned." -price = "Σ pris" +price = "Pris" reallyDelete = "Er du sikker på at du vil slette denne session?" +showIndividualEntries = "Vis individuelle sessioner" solar = "solenergi" title = "Opladnings Sessioner" total = "Total" vehicle = "Køretøj" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ Pris {byGroup}" +byGroupLoadpoint = "Ved ladepunktet" +byGroupVehicle = "Ved køretøjet" +energy = "Opladet energi" +energyGrouped = "Sol vs elnet energi" +energyGroupedByGroup = "Energi {byGroup}" +energySubSolar = "{value} sol" +energySubTotal = "{value} total" +groupedCo2ByGroup = "CO₂-mængde {byGroup}" +groupedPriceByGroup = "Total pris {byGroup}" +historyCo2 = "CO₂-Emission" +historyCo2Sub = "{value} total" +historyPrice = "Opladningspris" +historyPriceSub = "{value} total" +solar = "Sol andel over året" +solarByGroup = "Solar andel {byGroup}" + [sessions.csv] chargedenergy = "Energi (kWh)" chargeduration = "Varighed" @@ -668,6 +689,27 @@ allLoadpoints = "alle ladepunkter" allVehicles = "alle køretøjer" filter = "Filter" +[sessions.group] +co2 = "Emission" +grid = "Elnet" +price = "Pris" +self = "Sol" + +[sessions.groupBy] +loadpoint = "Opladnings punkt" +none = "Total" +vehicle = "Køretøj" + +[sessions.period] +month = "Måned" +total = "Total" +year = "År" + +[sessions.type] +co2 = "CO₂" +price = "Pris" +solar = "Sol" + [settings] title = "Brugergrænseflade" diff --git a/i18n/el.toml b/i18n/el.toml index e096e3a7f2..951c4b8d3c 100644 --- a/i18n/el.toml +++ b/i18n/el.toml @@ -61,6 +61,7 @@ enabled = "Ενεργοποιημένο" energy = "Ενέργεια" feedinPrice = "Ταρίφα Feed-in" gridPrice = "Τιμή δικτύου" +hemsType = "Σύστημα" no = "όχι" odometer = "Οδόμετρο" org = "Οργανισμός" @@ -422,7 +423,7 @@ co2 = "⌀ CO₂" duration = "Διάρκεια" fallbackName = "Σημείο φόρτισης" power = "Ισχύς" -price = "Σ Τιμή" +price = "Κόστος" remaining = "Απομένει" remoteDisabledHard = "{source}: απενεργοποιημένο" remoteDisabledSoft = "{source}: απενεργοποιημένη προσαρμοζόμενη ηλιακή Φ/Β φόρτιση" @@ -473,7 +474,7 @@ minpv = "Ελαχ+Φ/Β" now = "Ταχύ" off = "Κλειστό" pv = "Φ/Β" -smart = "Έξυπνο¨" +smart = "Έξυπνο" [main.provider] login = "σύνδεση" @@ -620,13 +621,33 @@ downloadCsv = "Λήψη ως CSV" energy = "Φόρτιση" loadpoint = "Σημείο φόρτισης" noData = "Δεν υπάρχουν συνεδρίες φόρτισης αυτό το μήνα." -price = "Σ Τιμή" +price = "Κόστος" reallyDelete = "Θέλετε πραγματικά να διαγράψετε αυτή τη συνεδρία;" +showIndividualEntries = "Εμφάνιση μεμονωμένων συνεδριών" solar = "Φ/Β" title = "Συνεδρίες φόρτισης" total = "Σύνολο" vehicle = "Όχημα" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ Τιμή {byGroup}" +byGroupLoadpoint = "κατά Σημείο Φόρτισης" +byGroupVehicle = "κατά Όχημα" +energy = "Φορτισμένη Ενέργεια" +energyGrouped = "Ηλιακή Φ/Β vs. Ενέργειας Δικτύου" +energyGroupedByGroup = "Ενέργεια {byGroup}" +energySubSolar = "{value} ηλιακή" +energySubTotal = "{value} σύνολο" +groupedCo2ByGroup = "Ποσότητα CO₂ {byGroup}" +groupedPriceByGroup = "Συνολικό Κόστος {byGroup}" +historyCo2 = "Εκπομπές CO₂" +historyCo2Sub = "{value} σύνολο" +historyPrice = "Κόστη Φορτίσεων" +historyPriceSub = "{value} σύνολο" +solar = "Ηλιακό Μερίδιο σε Ετήσια βάση" +solarByGroup = "Ηλιακό Μερίδιο {byGroup}" + [sessions.csv] chargedenergy = "Ενέργεια (kWh)" chargeduration = "Διάρκεια" @@ -648,6 +669,27 @@ allLoadpoints = "όλα τα σημεία φόρτισης" allVehicles = "όλα τα οχήματα" filter = "Φίλτρο" +[sessions.group] +co2 = "Εκπομπές" +grid = "Δίκτυο" +price = "Τιμή" +self = "Φ/Β" + +[sessions.groupBy] +loadpoint = "Σημείο φόρτισης" +none = "Σύνολο" +vehicle = "Όχημα" + +[sessions.period] +month = "Μήνας" +total = "Σύνολο" +year = "Έτος" + +[sessions.type] +co2 = "CO₂" +price = "Τιμή" +solar = "Φ/Β" + [settings] title = "Διεπαφή χρήστη" @@ -690,7 +732,7 @@ applyToAll = "Εφαρμογή παντού;" batteryDescription = "Φορτίζει την οικιακή μπαταρία με ενέργεια από το δίκτυο." cheapTitle = "Φτηνή φόρτιση δικτύου" cleanTitle = "Φόρτιση δικτύου πράσινης ενέργειας" -co2Label = "εκπομπές CO2" +co2Label = "εκπομπές CO₂" co2Limit = "Όριο CO₂" loadpointDescription = "Επιτρέπει την προσωρινή γρήγορη φόρτιση σε λειτουργία ηλιακής Φ/Β ενέργειας." modalTitle = "Έξυπνη φόρτιση δικτύου" diff --git a/i18n/es.toml b/i18n/es.toml index d19cdd827a..c83b929e85 100644 --- a/i18n/es.toml +++ b/i18n/es.toml @@ -63,6 +63,7 @@ enabled = "Activado" energy = "Energía" feedinPrice = "Precio de entrada" gridPrice = "Precio de red" +hemsType = "Sistema" no = "no" odometer = "Cuentakilómetros" org = "Organización" @@ -442,7 +443,7 @@ co2 = "CO₂ ⌀ " duration = "Duración" fallbackName = "Punto de carga" power = "Potencia" -price = "Σ Precio" +price = "Precio" remaining = "Tiempo restante" remoteDisabledHard = "{source}: desactivado" remoteDisabledSoft = "{source}: Carga adaptativa desactivada" @@ -461,6 +462,9 @@ vehicle = "Vehículo" [main.loadpointSettings.batteryBoost] description = "Carga rápida desde la batería de casa" +label = "Aumento de la batería" +mode = "Solo disponible en modo solar y min+solar." +once = "Boost activo para esta sesión de carga" [main.loadpointSettings.limitSoc] description = "Límite de carga que se utiliza cuando este vehículo está conectado" @@ -563,6 +567,7 @@ vehicleLimit = "límite de vehículo: {soc}" [main.vehicleStatus] awaitingAuthorization = "Esperando autorización" +batteryBoost = "Refuerzo de batería activo" charging = "Cargando ..." cheapEnergyCharging = "Energía barata disponible." cheapEnergyNextStart = "Energía barata durante {duration}" @@ -641,13 +646,33 @@ downloadCsv = "Descargar como CSV" energy = "Cargado" loadpoint = "Punto de carga" noData = "No hay sesiones de carga este mes." -price = "Σ Precio" +price = "Precio" reallyDelete = "¿De verdad quieres eliminar esta sesión?" +showIndividualEntries = "Mostrar sesiones individuales" solar = "Solar" title = "Sesiones de carga" total = "Total" vehicle = "Vehículo" +[sessions.chartTitle] +avgCo2ByGroup = "CO₂ ⌀ {byGroup}" +avgPriceByGroup = "Precio ⌀ {byGroup}" +byGroupLoadpoint = "por punto de carga" +byGroupVehicle = "por vehículo" +energy = "Energía cargada" +energyGrouped = "“Energía solar versus energía de red”" +energyGroupedByGroup = "Energía {byGroup}" +energySubSolar = "{value} solar" +energySubTotal = "{value} total" +groupedCo2ByGroup = "CO₂-Importe {byGroup}" +groupedPriceByGroup = "Coste total {byGroup}" +historyCo2 = "Emisiones de CO₂" +historyCo2Sub = "{value} total" +historyPrice = "Precio de carga" +historyPriceSub = "{value} total" +solar = "Cuota solar anual" +solarByGroup = "Cuota Solar {byGroup}" + [sessions.csv] chargedenergy = "Energía (kWh)" chargeduration = "«Duración»" @@ -669,6 +694,27 @@ allLoadpoints = "todos los puntos de recarga" allVehicles = "todos los vehiculos" filter = "Filtrar" +[sessions.group] +co2 = "Emisiones" +grid = "Red eléctrica" +price = "Precio" +self = "Energía Solar" + +[sessions.groupBy] +loadpoint = "Punto de carga" +none = "Total" +vehicle = "Vehículo" + +[sessions.period] +month = "Mes" +total = "Total" +year = "Año" + +[sessions.type] +co2 = "CO₂" +price = "Precio" +solar = "Energía Solar" + [settings] title = "Interfaz de usuario" diff --git a/i18n/et.toml b/i18n/et.toml new file mode 100644 index 0000000000..0304ead4f6 --- /dev/null +++ b/i18n/et.toml @@ -0,0 +1,4 @@ +[batterySettings] +batteryLevel = "Akutase" +capacity = "{energy} / {total}" +control = "Akuhaldus" diff --git a/i18n/fr.toml b/i18n/fr.toml index 0b55a05fc6..7e84ad0c68 100644 --- a/i18n/fr.toml +++ b/i18n/fr.toml @@ -63,6 +63,7 @@ enabled = "Activé" energy = "Énergie" feedinPrice = "Prix de revente" gridPrice = "Prix du réseau" +hemsType = "Système" no = "non" odometer = "Kilométrage" org = "Organisation" @@ -442,7 +443,7 @@ co2 = "CO₂ ⌀" duration = "Durée" fallbackName = "Point de chargement" power = "Puissance" -price = "Σ Prix" +price = "Prix" remaining = "Temps restant" remoteDisabledHard = "{source} : désactivée" remoteDisabledSoft = "{source} : charge PV adaptative désactivée" @@ -656,7 +657,7 @@ historyPriceSubTitle = "{value} totale" historyPriceTitle = "⌀ {value} Prix de la charge" loadpoint = "Point de chargement" noData = "Pas de session de charge ce mois-ci" -price = "Σ Prix" +price = "Prix" reallyDelete = "Voulez-vous vraiment supprimer cette session?" showIndividualEntries = "Afficher les sessions individuelles" solar = "Solaire" @@ -666,6 +667,25 @@ title = "Sessions de charge" total = "Total" vehicle = "Véhicule" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ Prix {byGroup}" +byGroupLoadpoint = "par Point de charge" +byGroupVehicle = "par Véhicule" +energy = "Énergie chargée" +energyGrouped = "Énergie Solaire vs. Réseau" +energyGroupedByGroup = "Énergie {byGroup}" +energySubSolar = "{value} solaire" +energySubTotal = "{value} total" +groupedCo2ByGroup = "Quantité de CO₂ {byGroup}" +groupedPriceByGroup = "Coût total {byGroup}" +historyCo2 = "Émissions de CO₂" +historyCo2Sub = "{value} total" +historyPrice = "Coûts de recharge" +historyPriceSub = "{value} total" +solar = "Part de Solaire par An" +solarByGroup = "Part de Solaire {byGroup}" + [sessions.csv] chargedenergy = "Énergie (kWh)" chargeduration = "Durée" diff --git a/i18n/hr.toml b/i18n/hr.toml index a6b3b0e005..4aba103955 100644 --- a/i18n/hr.toml +++ b/i18n/hr.toml @@ -63,6 +63,7 @@ enabled = "Omogućeno" energy = "Energija" feedinPrice = "Cijena za nabavu" gridPrice = "Cijena mreže" +hemsType = "Sustav" no = "ne" odometer = "Odometar" org = "Organizacija" @@ -271,7 +272,7 @@ tabTitle = "Živa zajednica" co2Saved = "{value} ušteđeno" co2Title = "CO₂ emisija" configurePriceCo2 = "Nauči kako konfigurirati podatke o cijeni i CO₂." -footerLong = "{percent} solarne energije" +footerLong = "{percent} solarna energija" footerShort = "{percent} solarno" modalTitle = "Pregled energije punjenja" moneySaved = "{value} ušteđeno" @@ -434,7 +435,7 @@ co2 = "⌀ CO₂" duration = "Trajanje" fallbackName = "Mjesto punjenja" power = "Snaga" -price = "Σ cijena" +price = "Trošak" remaining = "Preostalo" remoteDisabledHard = "{source}: isključeno" remoteDisabledSoft = "{source}: adaptivno solarno punjenje isključeno" @@ -648,7 +649,7 @@ historyPriceSubTitle = "ukupno {value}" historyPriceTitle = "⌀ {value} cijena punjenja" loadpoint = "Mjesto punjenja" noData = "U ovom mjesecu nema sesija napajanja." -price = "Σ cijena" +price = "Trošak" reallyDelete = "Stvarno želiš izbrisati ovu sesiju?" showIndividualEntries = "Prikaži pojedine zapise" solar = "Solarno" @@ -658,6 +659,25 @@ title = "Postupci punjenja" total = "Ukupno" vehicle = "Vozilo" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ cijena {byGroup}" +byGroupLoadpoint = "prema mjestu punjenja" +byGroupVehicle = "po vozilu" +energy = "Isporučena energija" +energyGrouped = "Izvor el. energije" +energyGroupedByGroup = "Energija {byGroup}" +energySubSolar = "{value} solarna energija" +energySubTotal = "{value} ukupno" +groupedCo2ByGroup = "CO₂ količina {byGroup}" +groupedPriceByGroup = "Ukupna cijena {byGroup}" +historyCo2 = "CO₂ onečišćenje" +historyCo2Sub = "{value} ukupno" +historyPrice = "Cijena punjenja" +historyPriceSub = "{value} ukupno" +solar = "Udio solarne energije tokom godine" +solarByGroup = "Solarna energija {byGroup}" + [sessions.csv] chargedenergy = "Energija (kWh)" chargeduration = "Trajanje" diff --git a/i18n/hu.toml b/i18n/hu.toml index d1b9bd3450..1b02d4bd26 100644 --- a/i18n/hu.toml +++ b/i18n/hu.toml @@ -61,6 +61,7 @@ enabled = "Engedélyezve" energy = "Energia" feedinPrice = "Kötelező átvételi ár" gridPrice = "Villamosenergia ára" +hemsType = "Rendszer" no = "nem" odometer = "Óraállás" org = "Szervezet" @@ -424,13 +425,14 @@ co2 = "⌀ CO₂" duration = "Időtartam" fallbackName = "Töltőpont" power = "Teljesítmény" -price = "Σ Ár" +price = "Költség" remaining = "Hátralévő" remoteDisabledHard = "{source}: kikapcsolva" remoteDisabledSoft = "{source}: kikapcsolva, adaptív napelemes töltés" solar = "Nap" [main.loadpointSettings] +batteryUsage = "Otthoni Akkumulátor" currents = "Töltőáram" default = "alapértelmezett" disclaimerHint = "Megjegyzés:" @@ -440,6 +442,12 @@ smartCostClean = "Tiszta Hálózati Töltés" title = "Beállítások {0}" vehicle = "Jármű" +[main.loadpointSettings.batteryBoost] +description = "Gyorstöltés otthoni akkumulátorról." +label = "Akkumulátoros Rásegítés" +mode = "Csak szolár és min+szolár módban elérhető." +once = "Rásegítés aktív ehhez a töltési folyamathoz." + [main.loadpointSettings.limitSoc] description = "Töltési korlát, amikor a jármű csatlakoztatva van." label = "Alapértelmezett limit" @@ -537,6 +545,7 @@ vehicleLimit = "Jármű limit: {soc}" [main.vehicleStatus] awaitingAuthorization = "Hitelesítésre várakozás." +batteryBoost = "Akkumulátoros rásegítés aktív." charging = "Töltés…" cheapEnergyCharging = "Olcsó energia elérhető." cheapEnergyNextStart = "Olcsó energia {duration}." @@ -615,13 +624,33 @@ downloadCsv = "Letöltés mint: CSV" energy = "Töltve" loadpoint = "Töltőpont" noData = "Nincs töltési folyamat ebben a hónapban." -price = "Σ Ár" +price = "Σ Költség" reallyDelete = "Biztosan szeretné törölni ezt a folyamatot?" +showIndividualEntries = "Egyéni munkamenetek megjelenítése" solar = "Napenergia" title = "Töltési Folyamatok" total = "Összesen" vehicle = "Jármű" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ Ár {byGroup}" +byGroupLoadpoint = "töltőpont szerint" +byGroupVehicle = "jármű szerint" +energy = "Töltött Energia" +energyGrouped = "Napelem vs. Hálózati Energia" +energyGroupedByGroup = "Energia {byGroup}" +energySubSolar = "{value} nap" +energySubTotal = "{value} összesen" +groupedCo2ByGroup = "CO₂-Mennyiség {byGroup}" +groupedPriceByGroup = "Összes Költség {byGroup}" +historyCo2 = "CO₂-Emissziók" +historyCo2Sub = "{value} összesen" +historyPrice = "Töltési Költségek" +historyPriceSub = "{value} összesen" +solar = "Napelem aránya egy évre vetítve" +solarByGroup = "Napelem Aránya {byGroup}" + [sessions.csv] chargedenergy = "Energia (kWh)" chargeduration = "Időtartam" @@ -643,6 +672,27 @@ allLoadpoints = "minden töltőpont" allVehicles = "minden jármű" filter = "Szűrés" +[sessions.group] +co2 = "Emissziók" +grid = "Hálózat" +price = "Ár" +self = "Nap" + +[sessions.groupBy] +loadpoint = "Töltőpont" +none = "Összes" +vehicle = "Jármű" + +[sessions.period] +month = "Hónap" +total = "Összes" +year = "Év" + +[sessions.type] +co2 = "CO₂" +price = "Ár" +solar = "Nap" + [settings] title = "Felhasználói felület" diff --git a/i18n/it.toml b/i18n/it.toml index 57f09b3af2..a2509e2ff9 100644 --- a/i18n/it.toml +++ b/i18n/it.toml @@ -4,17 +4,17 @@ capacity = "{energy} di {total}" control = "Controllo batteria" discharge = "Prevenire la scarica della batteria in modalità veloce oppure quando è attiva una pianificazione." disclaimerHint = "Nota:" -disclaimerText = "“Queste impostazioni riguardano solamente la modalità solare. Il comportamento di ricarica è adattato di conseguenza.”" -gridChargeTab = "Carica un corso dalla rete." +disclaimerText = "Queste impostazioni riguardano solamente la modalità solare. Il comportamento di ricarica è adattato di conseguenza." +gridChargeTab = "Carica in corso dalla rete" legendBottomName = "Priorità alla carica della batteria di casa”" legendBottomSubline = "Fino al raggiungimento del {soc}." -legendMiddleName = "“Priorità alla carica del veicolo”" +legendMiddleName = "Priorità alla carica del veicolo" legendMiddleSubline = "Quando la batteria supera il {soc}." legendTitle = "“Come dovrebbe essere utilizzata l’energia solare?”" legendTopAutostart = "Parte automaticamente" legendTopName = "Ricarica del veicolo assistita dalla batteria" legendTopSubline = "quando la batteria supera il {soc}." -modalTitle = "“Batteria di casa”" +modalTitle = "Batteria di casa" usageTab = "Uso della batteria" [batterySettings.bufferStart] @@ -61,6 +61,7 @@ enabled = "Abilitato" energy = "Energia" feedinPrice = "Prezzo di vendita" gridPrice = "Prezzo d'acquisto" +hemsType = "Sistema" no = "no" odometer = "Odometro" org = "Organizzazione" @@ -92,6 +93,7 @@ experimental = "Sperimentale" off = "spento" on = "acceso" password = "Password" +readFromFile = "Importa da file" remove = "Rimuovi" save = "Salva" telemetry = "Telemetria" @@ -110,7 +112,9 @@ title = "HEMS" description = "Scrive i dati di ricarica e le altre metriche su InfluxDB. Usa Grafana o altri strumenti per visualizzare i dati." descriptionToken = "Controlla la documentazione di InfluxDB per imparare a crearne uno. https://docs.influxdata.com/influxdb/v2/admin/" labelBucket = "Bucket" +labelCheckInsecure = "Permetti certificati self-signed" labelDatabase = "Database" +labelInsecure = "Validazione certificato" labelOrg = "Società" labelPassword = "Password" labelToken = "Token API" @@ -153,8 +157,11 @@ description = "Connettiti ad un broker MQTT per permettere lo scambio di dati co descriptionClientId = "Autore del messaggio. Viene usato `evcc-[rand]` se il campo è lasciato vuoto." descriptionTopic = "Lasciare vuoto per disabilitare la pubblicazione." labelBroker = "Broker" +labelCaCert = "Certificato server (CA)" labelCheckInsecure = "Permetti certificati self-signed" +labelClientCert = "Certificato client" labelClientId = "ID Client" +labelClientKey = "Chiave client" labelInsecure = "Validazione certificato" labelPassword = "Password" labelTopic = "Argomento" @@ -260,13 +267,13 @@ powerSub2 = "in carica..." tabTitle = "Live community" [footer.savings] -co2Saved = "{value} salvato" +co2Saved = "{value} di risparmio" co2Title = "Emissioni di CO₂" configurePriceCo2 = "Scopri come configurare i dati su prezzi e CO₂." footerLong = "{percent} di energia solare" footerShort = "{percent} solare" modalTitle = "Riepilogo energia caricata" -moneySaved = "{value} salvato" +moneySaved = "{value} di risparmio" percentGrid = "{grid} kWh rete" percentSelf = "{self} kWh solare" percentTitle = "Energia solare" @@ -304,7 +311,7 @@ trial = "Sei in modalità di prova e puoi utilizzare tutte le funzionalità. Ti victron = "Stai utilizzando evcc sull'hardware Victron Energy e hai accesso a tutte le funzionalità." [footer.telemetry] -optIn = "Voglio contribuire ai miei dati." +optIn = "Voglio contribuire con i miei dati." optInMoreDetails = "Ulteriori dettagli {0}." optInMoreDetailsLink = "qui" optInSponsorship = "È necessaria una sponsorizzazione" @@ -428,13 +435,14 @@ co2 = "⌀ CO₂" duration = "Durata" fallbackName = "Punto di ricarica" power = "Potenza" -price = "Σ Prezzo" +price = "Costo" remaining = "Rimanente" remoteDisabledHard = "{source}: Disabilitato" remoteDisabledSoft = "{source}: Ricarica FV adattiva disabilitata" solar = "Solare" [main.loadpointSettings] +batteryUsage = "Batteria di casa" currents = "Corrente di carica" default = "default" disclaimerHint = "Nota:" @@ -444,8 +452,14 @@ smartCostClean = "Ricarica Pulita" title = "Impostazioni {0}" vehicle = "Veicolo" +[main.loadpointSettings.batteryBoost] +description = "Carica rapida dalla batteria di casa." +label = "Boost da batteria" +mode = "Disponibile solo in modalità solare e min+solare." +once = "Boost attivo per questa sessione di ricarica." + [main.loadpointSettings.limitSoc] -description = "Limite di carica che viene applicato quando il veicolo è connesso." +description = "Limite di carica applicato quando il veicolo è connesso." label = "Limite di default" [main.loadpointSettings.maxCurrent] @@ -542,6 +556,7 @@ vehicleLimit = "Limite veicolo: {soc}" [main.vehicleStatus] awaitingAuthorization = "Aspettando l'autorizzazione." +batteryBoost = "Boost da batteria attivo" charging = "In carica..." cheapEnergyCharging = "Corrente economica disponibile." cheapEnergyNextStart = "Corrente economica in {duration}." @@ -620,13 +635,33 @@ downloadCsv = "Scarica come CSV" energy = "Caricato" loadpoint = "Punto di ricarica" noData = "Nessuna sessione di ricarica questo mese." -price = "Σ Prezzo" +price = "Costo" reallyDelete = "Vuoi veramente eliminare questa sessione?" +showIndividualEntries = "Mostra singole sessioni" solar = "Solare" title = "Sessioni di ricarica" total = "Totale" vehicle = "Veicolo" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ Prezzo {byGroup}" +byGroupLoadpoint = "per Punto di Ricarica" +byGroupVehicle = "per Veicolo" +energy = "Energia ricaricata" +energyGrouped = "Energia Solare vs Rete" +energyGroupedByGroup = "Energia {byGroup}" +energySubSolar = "{value} solare" +energySubTotal = "{value} totale" +groupedCo2ByGroup = "Quantità CO₂ {byGroup}" +groupedPriceByGroup = "Costo Totale {byGroup}" +historyCo2 = "Emissioni CO₂" +historyCo2Sub = "{value} totale" +historyPrice = "Costi di ricarica" +historyPriceSub = "{value} totale" +solar = "Perc. Solare annua" +solarByGroup = "Perc. Solare {byGroup}" + [sessions.csv] chargedenergy = "Energia (kWh)" chargeduration = "Durata" @@ -648,6 +683,27 @@ allLoadpoints = "tutte le stazioni di ricarica" allVehicles = "tutte i veicoli" filter = "Filtra" +[sessions.group] +co2 = "Emissioni" +grid = "Rete" +price = "Prezzo" +self = "Solare" + +[sessions.groupBy] +loadpoint = "Punto di ricarica" +none = "Totale" +vehicle = "Veicolo" + +[sessions.period] +month = "Mese" +total = "Totale" +year = "Anno" + +[sessions.type] +co2 = "CO₂" +price = "Prezzo" +solar = "Solare" + [settings] title = "Interfaccia Utente" diff --git a/i18n/lb.toml b/i18n/lb.toml index b1b5675dc8..2db5f4e043 100644 --- a/i18n/lb.toml +++ b/i18n/lb.toml @@ -60,6 +60,7 @@ enabled = "Ageschalt" energy = "Energie" feedinPrice = "Präis fir anzespeisen" gridPrice = "Netz Präis" +hemsType = "System" no = "nee" odometer = "Kilometerzäler" org = "Organisatioun" @@ -319,7 +320,7 @@ availableLong = "nei Versioun verfügbar" modalCancel = "Ofbriechen" modalDownload = "Download" modalInstalledVersion = "Aktuell installéiert Versioun" -modalNoReleaseNotes = "Keng Verëffentlechungsnotizen verfügbar. Méi Informatioun iwwer déi nei Versioun:" +modalNoReleaseNotes = "Keng Versiounshiweiser verfügbar. Méi Informatioun iwwert déi nei Versioun:" modalTitle = "Aktualiséierung verfügbar" modalUpdate = "Installéieren" modalUpdateNow = "Elo installéieren" @@ -433,7 +434,7 @@ co2 = "⌀ CO₂" duration = "Dauer" fallbackName = "Luedstatioun" power = "Leeschtung" -price = "Σ Präis" +price = "Käschten" remaining = "Reschtzäit" remoteDisabledHard = "{source}: Deaktivéiert" remoteDisabledSoft = "{source}: Adaptatiivt PV-Lueden deaktivéiert" @@ -647,7 +648,7 @@ historyPriceSubTitle = "{value} insgesamt" historyPriceTitle = "⌀ {value} Luedpräis" loadpoint = "Luedstatioun" noData = "Nach keng Opluedsessiounen fir dëse Mount." -price = "Σ Präis" +price = "Käschten" reallyDelete = "Wëlls du dës Sessioun wierklech läschen?" showIndividualEntries = "Eenzel Luedsessiounen uweisen" solar = "Sonn" @@ -657,6 +658,25 @@ title = "Opluedsessiounen" total = "Total" vehicle = "Gefier" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ Präis {byGroup}" +byGroupLoadpoint = "no Opluedpunkt" +byGroupVehicle = "no Gefier" +energy = "Geluedene Stroum" +energyGrouped = "Sonne- vs. Netzstroum" +energyGroupedByGroup = "Stroum {byGroup}" +energySubSolar = "{value} Sonn" +energySubTotal = "{value} insgesamt" +groupedCo2ByGroup = "Quantitéit CO₂ {byGroup}" +groupedPriceByGroup = "Käschten {byGroup}" +historyCo2 = "CO₂-Emissiounen" +historyCo2Sub = "{value} insgesamt" +historyPrice = "Opluedkäschten" +historyPriceSub = "{value} insgesamt" +solar = "Sonnenundeel iwwer d'Joer" +solarByGroup = "Sonnenundeel {byGroup}" + [sessions.csv] chargedenergy = "Energie (kWh)" chargeduration = "Oplueddauer" @@ -745,7 +765,7 @@ co2Label = "CO₂-Emissioun" co2Limit = "CO₂-Grenz" loadpointDescription = "Aktivéiert iwwerganksméisseg Schnelloplueden am PV-Modus." modalTitle = "Smart Opluede vum Netz" -none = "keent" +none = "keng" priceLabel = "Energiepräis" priceLimit = "Präisgrenz" saved = "Gepäichert." diff --git a/i18n/lt.toml b/i18n/lt.toml index 15b435865d..6ceacc6763 100644 --- a/i18n/lt.toml +++ b/i18n/lt.toml @@ -63,6 +63,7 @@ enabled = "Aktyvuota" energy = "Energija" feedinPrice = "Tiekimo į tinklą kaina" gridPrice = "Energijos pirkimo kaina" +hemsType = "Sistema" no = "ne" odometer = "Odometras" org = "Organizacija" @@ -298,7 +299,7 @@ tabTitle = "Mano" 30d = "paskutinės 30 dienų" 365d = "paskutinės 365 dienos" thisYear = "šiais metais" -total = "Iš viso" +total = "Nuo pradžios" [footer.sponsor] becomeSponsor = "Tapkite rėmėju" @@ -442,7 +443,7 @@ co2 = "⌀ CO₂" duration = "Trukmė" fallbackName = "Įkroviklis" power = "Galia" -price = "Σ Kaina" +price = "Kaina" remaining = "Liko" remoteDisabledHard = "{source}: išjungtas" remoteDisabledSoft = "{source}: adaptyvus Saulės įkrovimas išjungtas" @@ -659,16 +660,35 @@ historyPriceSubTitle = "{value} viso" historyPriceTitle = "⌀ {value} Įkrovimo Kaina" loadpoint = "Įkroviklis" noData = "Šį mėnesį įkrovimų nebuvo." -price = "Σ Kaina" +price = "Kaina" reallyDelete = "Ar tikrai norite ištrinti šią įkrovimo sesiją?" showIndividualEntries = "Rodyti individualias sesijas" solar = "Saulės" solarTitle = "Saulės dalis per metus" solarTitleByGroup = "Saulės {byGroup}" title = "Įkrovimo Sesijos" -total = "Viso" +total = "Suma" vehicle = "Automobilis" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ Kaina {byGroup}" +byGroupLoadpoint = "pagal Įkroviklį" +byGroupVehicle = "pagal Automobilį" +energy = "Įkrauta Energija" +energyGrouped = "Saulės vs. Tinklo Energija" +energyGroupedByGroup = "Energija {byGroup}" +energySubSolar = "{value} saulės" +energySubTotal = "{value} suma" +groupedCo2ByGroup = "CO₂-Kiekis {byGroup}" +groupedPriceByGroup = "Bendra Kaina {byGroup}" +historyCo2 = "CO₂-Tarša" +historyCo2Sub = "{value} suma" +historyPrice = "Įkrovimo išlaidos" +historyPriceSub = "{value} suma" +solar = "Saulės energijos dalis per metus" +solarByGroup = "Saulės energijos dalis {byGroup}" + [sessions.csv] chargedenergy = "Energija (kWh)" chargeduration = "Trukmė" @@ -698,12 +718,12 @@ self = "Saulės" [sessions.groupBy] loadpoint = "Įkroviklis" -none = "Viso" +none = "Suma" vehicle = "Automobilis" [sessions.period] month = "Mėnesis" -total = "Viso" +total = "Suma" year = "Metai" [sessions.type] diff --git a/i18n/nl.toml b/i18n/nl.toml index b521bb68cd..7941bf1f9a 100644 --- a/i18n/nl.toml +++ b/i18n/nl.toml @@ -31,10 +31,13 @@ titleAdd = "Voeg accu toe" titleEdit = "Accu aanpassen" [config.circuits] +description = "Zorgt ervoor dat de som van alle laadpunten die zijn aangesloten op een circuit de ingestelde vermogens- en stroomlimieten niet overschrijdt. Circuits kunnen genest worden om een hiërarchie op te bouwen." title = "Belastingbeheer" [config.control] description = "Normaalgesproken zijn de standaardwaardes in orde. Pas deze alleen aan als je weet wat je doet." +descriptionInterval = "Updatecyclus van de regeling in seconden. Bepaalt hoe vaak evcc metergegevens uitleest, het laadvermogen aanpast en de gebruikersinterface bijwerkt. Korte intervallen (< 30s) kunnen oscillaties en ongewenst gedrag veroorzaken." +descriptionResidualPower = "Verplaatst het werkpunt van de regelkring. Als je een thuisbatterij hebt, wordt aanbevolen om een waarde van 100 W in te stellen. Op deze manier krijgt de batterij een lichte prioriteit boven het gebruik van het net." labelInterval = "Update interval" labelResidualPower = "Vermogensoverschot" title = "Regelgedrag" @@ -60,6 +63,7 @@ enabled = "Ingeschakeld" energy = "Energie" feedinPrice = "Terugleververgoeding" gridPrice = "Netprijs" +hemsType = "Systeem" no = "nee" odometer = "Kilometerstand" org = "Organisatie" @@ -110,6 +114,7 @@ title = "HEMS" description = "Schrijft laad-data en andere cijfers naar InfluxDB. Gebruik Grafana of andere tools om de data te visualiseren." descriptionToken = "Bekijk de InfluxDB documentatie om te zien hoe je er een maakt. https://docs.influxdata.com/influxdb/v2/admin/" labelBucket = "Bucket" +labelCheckInsecure = "Sta zelfondertekende certificaten toe" labelDatabase = "Database" labelInsecure = "Certificaat validatie" labelOrg = "Organisatie" @@ -274,7 +279,7 @@ configurePriceCo2 = "Meer informatie rond het configureren van prijs en CO₂ ge footerLong = "{percent} zonne-energie" footerShort = "{percent} zon" modalTitle = "Oplaadenergie-overzicht" -moneySaved = "{value} opgeslagen" +moneySaved = "{value} bespaard" percentGrid = "{grid} kWh net" percentSelf = "{self} kWh zon" percentTitle = "Zonne-energie" @@ -438,7 +443,7 @@ co2 = "⌀ CO₂" duration = "Duur" fallbackName = "Laadpunt" power = "Vermogen" -price = "Σ Prijs" +price = "Kost" remaining = "Resterend" remoteDisabledHard = "{source}: uitgeschakeld" remoteDisabledSoft = "{source}: adaptief PV-laden uitgeschakeld" @@ -569,7 +574,7 @@ cleanEnergyNextStart = "Schone energie in {duration}." cleanEnergySet = "CO₂ limiet ingesteld." climating = "Voor-conditionering gedetecteerd." connected = "Verbonden." -disconnectRequired = "Sessie afgebroken. Verbind opnieuw." +disconnectRequired = "Sessie beëindigd. Gelieve opnieuw verbinding te maken." disconnected = "Niet verbonden." finished = "Geëindigd." minCharge = "Minimaal opladen naar {soc}." @@ -652,7 +657,7 @@ historyPriceSubTitle = "{value} totaal" historyPriceTitle = "⌀ {value} Laadprijs" loadpoint = "Oplaadpunt" noData = "Geen oplaadsessies deze maand" -price = "Σ Prijs" +price = "Kost" reallyDelete = "Wilt u deze sessie echt verwijderen?" showIndividualEntries = "Toon individuele sessies" solar = "Zon" @@ -662,6 +667,25 @@ title = "Oplaadsessies" total = "Totaal" vehicle = "Voertuig" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ Prijs {byGroup}" +byGroupLoadpoint = "per Oplaadpunt" +byGroupVehicle = "per Voertuig" +energy = "Geladen Energie" +energyGrouped = "Zon vs. Net Energie" +energyGroupedByGroup = "Energie {byGroup}" +energySubSolar = "{value} zon" +energySubTotal = "{value} totaal" +groupedCo2ByGroup = "CO₂-Hoeveelheid {byGroup}" +groupedPriceByGroup = "Totale Kost {byGroup}" +historyCo2 = "CO₂-Uitstoot" +historyCo2Sub = "{value} totaal" +historyPrice = "Oplaadkosten" +historyPriceSub = "{value} totaal" +solar = "Zonne-aandeel per jaar" +solarByGroup = "Zonne-aandeel {byGroup}" + [sessions.csv] chargedenergy = "Energie (kWh)" chargeduration = "Duur" diff --git a/i18n/pt.toml b/i18n/pt.toml index f38d3b8af6..31dd1f2b1f 100644 --- a/i18n/pt.toml +++ b/i18n/pt.toml @@ -2,7 +2,7 @@ batteryLevel = "Nível da bateria" capacity = "{energy} de {total}" control = "Controle de bateria" -discharge = "Prevenir a descarga no modo rápido e o carregamento planejado." +discharge = "Prevenir a descarga no modo rápido e a recarga planeada." disclaimerHint = "Nota:" disclaimerText = "Estas configurações só afetam o modo solar. O comportamento de carregamento é ajustado de acordo." gridChargeTab = "Carregamento de rede" @@ -31,8 +31,8 @@ titleAdd = "Adicionar bateria" titleEdit = "Editar bateria" [config.circuits] -description = "Assegura que a soma de todos os pontos de carga conectados a um circuito não exceda os limites de potência e corrente configurados. Circuitos podem ser aninhados para construir uma hierarquia." -title = "Gerenciamento de carga" +description = "Assegura que a soma de todos os pontos de recarga conectados a um circuito não exceda os limites de potência e corrente configurados. Circuitos podem ser combinados para construir uma hierarquia." +title = "Gerir a recarga" [config.control] description = "No geral, os valores padrão estão bem. Apenas mude-os se você sabe o que está fazendo." @@ -63,6 +63,7 @@ enabled = "Ativado" energy = "Energia" feedinPrice = "Preço de alimentação" gridPrice = "Preço da rede" +hemsType = "Sistema" no = "não" odometer = "Odómetro" org = "Organização" @@ -126,7 +127,7 @@ v1Support = "Apoio necessário para o InfluxDB 1.x?" v2Support = "Voltar ao InfluxDB 2.x" [config.main] -addLoadpoint = "Adicionar ponto de carga" +addLoadpoint = "Adicionar ponto de recarga" addPvBattery = "Adicionar solar ou bateria" addVehicle = "Adicionar veículo" configured = "configurado" @@ -262,7 +263,7 @@ greenEnergySub2 = "desde outubro de 2022" greenShare = "Parte solar" greenShareSub1 = "energia fornecida por" greenShareSub2 = "solar e bateria doméstica" -power = "Poder de carga" +power = "Energia de recarga" powerSub1 = "{activeClients} de {totalClients} utilizadores" powerSub2 = "carregando..." tabTitle = "Comunidade ao vivo" @@ -338,7 +339,7 @@ login = "Registo de veículo" logout = "sair do sistema" nativeSettings = "Alterar servidor" needHelp = "Precisa ajuda?" -sessions = "Sessões de carga" +sessions = "Sessões de recarga" settings = "Configuração" [header.theme] @@ -436,9 +437,9 @@ avgPrice = "Preço ⌀" charged = "Carregado" co2 = "CO₂ ⌀" duration = "Duração" -fallbackName = "Ponto de carga" +fallbackName = "Ponto de recarga" power = "Desempenho" -price = "Preço Σ" +price = "Custo" remaining = "Tempo restante" remoteDisabledHard = "{source}: desativado" remoteDisabledSoft = "{source}:carregamento PV adaptável desativado" @@ -446,7 +447,7 @@ solar = "Sol" [main.loadpointSettings] batteryUsage = "Bateria de casa" -currents = "Corrente de carga" +currents = "Corrente da recarga" default = "predefinado" disclaimerHint = "Aviso:" onlyForSocBasedCharging = "Estas opções só estão disponíveis para veículos com nível de carregamento conhecido." @@ -456,20 +457,20 @@ title = "Configurações {0}" vehicle = "Veículo" [main.loadpointSettings.batteryBoost] -description = "Carga rápida da bateria de casa." +description = "Recarga rápida da bateria de casa." label = "Boost bateria " mode = "Disponível apenas nos modos solar e min+solar." -once = "Boost ativo para esta sessão de carga." +once = "Boost ativo para esta sessão de recarga." [main.loadpointSettings.limitSoc] description = "limite de compartilhamento que é usado quando este veículo está conectado." label = "limite padrão" [main.loadpointSettings.maxCurrent] -label = "Corrente de carga máxima" +label = "Corrente de recarga máxima" [main.loadpointSettings.minCurrent] -label = "Corrente de carga mínima" +label = "Corrente de recarga mínima" [main.loadpointSettings.minSoc] description = "O veículo é carregado “rápido” até {0} no modo solar. Em seguida, continua com excedente solar. Útil para garantir um alcance mínimo mesmo em dias mais escuros." @@ -507,7 +508,7 @@ modalTitle = "Definir hora-alvo" notReachableInTime = "O objetivo será alcançado {overrun} mais tarde." onlyInPvMode = "O plano de carregamento só funciona no modo solar." planDescription = "Entrar um tempo de partida, e evcc irá carregar o veículo o mais rentável ou ambientalmente amigável possível." -planDuration = "Tempo de carga" +planDuration = "Tempo de recarga" planPeriodLabel = "Período" planPeriodValue = "{start} até {end}" planUnknown = "desconhecido" @@ -528,7 +529,7 @@ vehicleCapacityDocs = "Aprender a configurá-la." vehicleCapacityRequired = "A capacidade da bateria do veículo é necessária para estimar o tempo de carregamento." [main.targetChargePlan] -chargeDuration = "Tempo de carga" +chargeDuration = "Tempo de recarga" co2Label = "Emissão de CO₂ ⌀" priceLabel = "Preço da energia" timeRange = "{day} {range} h" @@ -574,9 +575,9 @@ connected = "Ligado." disconnectRequired = "Sessão terminada. Por favor, volte a ligar-se." disconnected = "Não conectado." finished = "Concluído." -minCharge = "Carga mínima até {soc}" +minCharge = "Recarga mínima até {soc}" pvDisable = "Excedente insuficiente. Pausa em breve." -pvEnable = "Excesso disponível. Carga em breve." +pvEnable = "Excesso disponível. Recarga em breve." scale1p = "Reduzindo para carregamento monofásico em breve." scale3p = "Aumentando para carregamento trifásico em breve." targetChargeActive = "Plano de carregamento ativo. Fim estimado em {duration}." @@ -586,7 +587,7 @@ unknown = "" vehicleLimit = "“Limite dos veículos.”" vehicleLimitReached = "Limite de veículo atingido." waitForVehicle = "Pronto. Esperando pelo veículo..." -welcome = "Carga inicial curta para confirmar a ligação." +welcome = "Recarga inicial curta para confirmar a ligação." [notifications] dismissAll = "Recusar tudos" @@ -626,7 +627,7 @@ meterstop = "Contagem final" odometer = "Quilometragem" price = "Preço" started = "Começado" -title = "Sessão de carga" +title = "Sessão de recarga" [sessions] avgCo2TitleByGroup = "⌀ CO₂ {byGroup}" @@ -652,19 +653,38 @@ historyCo2SubTitle = "{value} total" historyCo2Title = "⌀ {value} Emissões de CO₂" historyPriceSubTitle = "{value} total" historyPriceTitle = "⌀ {value} Preço de carregamento" -loadpoint = "Ponto de carga" +loadpoint = "Ponto de recarga" noData = "Nenhuma sessão de carregamento este mês." odometer = "Quilometragem" -price = "Preço Σ" +price = "Custo" reallyDelete = "Você realmente quer excluir esta sessão?" showIndividualEntries = "Mostrar sessões individuais" solar = "Sol" solarTitle = "“Parte de energia solar ao longo de um ano”" solarTitleByGroup = "“Parte solar {byGroup}”" -title = "Sessões de carga" +title = "Sessões de recarga" total = "Total" vehicle = "Veículo" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ Preço {byGroup}" +byGroupLoadpoint = "por ponto de recarga" +byGroupVehicle = "por veículo" +energy = "Energia carregada" +energyGrouped = "Energia Solar vs. Energia de Rede" +energyGroupedByGroup = "Energia {byGroup}" +energySubSolar = "{value} solar" +energySubTotal = "{value} total" +groupedCo2ByGroup = "Quantidade de CO₂ {byGroup}" +groupedPriceByGroup = "Custo total {byGroup}" +historyCo2 = "Emissões de CO₂" +historyCo2Sub = "{value} total" +historyPrice = "Custos da recarga" +historyPriceSub = "{value} total" +solar = "Parte solar durante todo o ano" +solarByGroup = "Parte solar {byGroup}" + [sessions.csv] chargedenergy = "Energia (kWh)" chargeduration = "Duração" @@ -672,7 +692,7 @@ co2perkwh = "CO₂/kWh" created = "Hora de início" finished = "Hora final" identifier = "Identificador" -loadpoint = "Ponto de carga" +loadpoint = "Ponto de recarga" meterstart = "Início do contador (kWh)" meterstop = "Contagem final (kWh)" odometer = "Quilometragem (km)" @@ -693,7 +713,7 @@ price = "Preço" self = "Solar" [sessions.groupBy] -loadpoint = "“Ponto de recarga”" +loadpoint = "Ponto de recarga" none = "Total" vehicle = "Veiculo" diff --git a/i18n/sl.toml b/i18n/sl.toml index 20a531083e..c9190ee014 100644 --- a/i18n/sl.toml +++ b/i18n/sl.toml @@ -63,6 +63,7 @@ enabled = "Omogočeno" energy = "Energija" feedinPrice = "Cena prejete energije iz omrežja" gridPrice = "Cena omrežja" +hemsType = "Sistem" no = "ne" odometer = "Število kilometrov" org = "Organizacija" @@ -437,7 +438,7 @@ co2 = "⌀ CO₂" duration = "Trajanje" fallbackName = "Polnilno mesto" power = "Moč" -price = "Σ Cena" +price = "Cena" remaining = "Preostalo" remoteDisabledHard = "{source}: izključeno" remoteDisabledSoft = "{source}: izklopljeno prilagodljivo solarno polnjenje" @@ -638,13 +639,33 @@ downloadCsv = "Prenesi kot CSV" energy = "Napolnjeno" loadpoint = "Polnilno mesto" noData = "Ta mesec ni bilo sej polnjenja." -price = "Σ Cena" +price = "Cena" reallyDelete = "Ali res želite izbrisati to sejo?" +showIndividualEntries = "Prikaži posamezne seje" solar = "Sončna energija" title = "Seje polnjenja" total = "Skupaj" vehicle = "Vozilo" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ Cena {byGroup}" +byGroupLoadpoint = "po polnilnem mestu" +byGroupVehicle = "po vozilu" +energy = "Napolnjena energija" +energyGrouped = "Sončna energija v primerjavi z omrežno energijo" +energyGroupedByGroup = "Energija {byGroup}" +energySubSolar = "{value} sončna energija" +energySubTotal = "{value} skupaj" +groupedCo2ByGroup = "CO₂-Količina {byGroup}" +groupedPriceByGroup = "Skupni stroški {byGroup}" +historyCo2 = "CO₂-Emisije" +historyCo2Sub = "{value} skupaj" +historyPrice = "Stroški polnjenja" +historyPriceSub = "{value} skupaj" +solar = "Solarni delež čez leto" +solarByGroup = "Solarni delež {byGroup}" + [sessions.csv] chargedenergy = "Energija (kWh)" chargeduration = "Trajanje" @@ -666,6 +687,27 @@ allLoadpoints = "vsa polnilna mesta" allVehicles = "vsa vozila" filter = "Filter" +[sessions.group] +co2 = "Emisije" +grid = "Omrežje" +price = "Cena" +self = "Sončna energija" + +[sessions.groupBy] +loadpoint = "Polnilno mesto" +none = "Skupaj" +vehicle = "Vozilo" + +[sessions.period] +month = "Mesec" +total = "Skupaj" +year = "Leto" + +[sessions.type] +co2 = "CO₂" +price = "Cena" +solar = "Sončna energija" + [settings] title = "Uporabniški vmesnik" diff --git a/i18n/sv.toml b/i18n/sv.toml index 611a3c3cec..c0957a285b 100644 --- a/i18n/sv.toml +++ b/i18n/sv.toml @@ -63,6 +63,7 @@ enabled = "Aktiverad" energy = "Energi" feedinPrice = "Inmatningspris" gridPrice = "Nätpris" +hemsType = "System" no = "nej" odometer = "Mätarställning" org = "Organisation" @@ -437,13 +438,14 @@ co2 = "⌀ CO₂" duration = "Varaktighet" fallbackName = "Laddplats" power = "Effekt" -price = "Σ pris" +price = "Kostnad" remaining = "Återstående tid" remoteDisabledHard = "{source}: avstängd" remoteDisabledSoft = "{source}: Adaptiv solladdning avstängd" solar = "Solenergi" [main.loadpointSettings] +batteryUsage = "Hembatteri" currents = "Laddström" default = "förvald" disclaimerHint = "Anmärkning:" @@ -453,6 +455,12 @@ smartCostClean = "Laddning med grön el" title = "Inställningar {0}" vehicle = "Fordon" +[main.loadpointSettings.batteryBoost] +description = "Snabbladdning från hembatteri" +label = "Batteri Boost" +mode = "Endast tillgänglig vid 'Sol' och 'Min+Sol' läge." +once = "Boost är aktiverat för denna laddning." + [main.loadpointSettings.limitSoc] description = "Laddbegränsning när detta fordon är anslutet." label = "Förvald laddgräns" @@ -554,6 +562,7 @@ vehicleLimit = "Fordonsgräns: {soc}" [main.vehicleStatus] awaitingAuthorization = "Väntar på godkännande." +batteryBoost = "Batteriboost är aktiv." charging = "Laddar..." cheapEnergyCharging = "Billig energi är tillgänglig." cheapEnergyNextStart = "Billig energi om {duration}." @@ -632,13 +641,33 @@ downloadCsv = "Ladda hem som CSV" energy = "Laddat" loadpoint = "Laddplats" noData = "Inga laddningar denna månad" -price = "Σ pris" +price = "Kostnad" reallyDelete = "Vill du verkligen radera den här sessionen?" +showIndividualEntries = "Se enskilda sessioner" solar = "Sol" title = "Laddningar" total = "Total" vehicle = "Fordon" +[sessions.chartTitle] +avgCo2ByGroup = "⌀ CO₂ {byGroup}" +avgPriceByGroup = "⌀ Pris {byGroup}" +byGroupLoadpoint = "per laddare" +byGroupVehicle = "per fordon" +energy = "Laddad energi" +energyGrouped = "Sol vs. nätenergi" +energyGroupedByGroup = "Energi {byGroup}" +energySubSolar = "{value} sol" +energySubTotal = "{value} total" +groupedCo2ByGroup = "CO₂-mängd {byGroup}" +groupedPriceByGroup = "Total kostnad {byGroup}" +historyCo2 = "CO₂-Emissioner" +historyCo2Sub = "{value} total" +historyPrice = "Laddkostnad" +historyPriceSub = "{value} total" +solar = "Solandel över året" +solarByGroup = "Solandel {byGroup}" + [sessions.csv] chargedenergy = "Energi (kWh)" chargeduration = "Varaktighet" @@ -660,6 +689,27 @@ allLoadpoints = "alla laddplatser" allVehicles = "alla fordon" filter = "Filter" +[sessions.group] +co2 = "Emissioner" +grid = "Nät" +price = "Pris" +self = "Sol" + +[sessions.groupBy] +loadpoint = "Laddare" +none = "Total" +vehicle = "Fordon" + +[sessions.period] +month = "Månad" +total = "Total" +year = "År" + +[sessions.type] +co2 = "CO₂" +price = "Pris" +solar = "Sol" + [settings] title = "Användargränssnitt" From 6c9ae85d85d95d44b85e5e9beefb61e93ec87c5f Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 10 Nov 2024 22:29:16 +0100 Subject: [PATCH 17/58] BMW: add coarsecurrent (#17170) --- templates/definition/vehicle/bmw.yaml | 10 +++++++++- util/templates/defaults.yaml | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/templates/definition/vehicle/bmw.yaml b/templates/definition/vehicle/bmw.yaml index 04442f15d1..1a1391ad0a 100644 --- a/templates/definition/vehicle/bmw.yaml +++ b/templates/definition/vehicle/bmw.yaml @@ -15,6 +15,8 @@ params: # - EU default: EU advanced: true + - name: coarsecurrent + advanced: true - name: welcomecharge advanced: true render: | @@ -24,6 +26,12 @@ render: | {{- if ne .region "EU" }} region: {{ .region }} {{- end }} + {{- if or (eq .coarsecurrent "true") (eq .welcomecharge "true") }} + features: + {{- if eq .coarsecurrent "true" }} + - coarsecurrent + {{- end }} {{- if eq .welcomecharge "true" }} - features: ["welcomecharge"] + - welcomecharge + {{- end }} {{- end }} diff --git a/util/templates/defaults.yaml b/util/templates/defaults.yaml index 881bf0d14b..cbbfeadf14 100644 --- a/util/templates/defaults.yaml +++ b/util/templates/defaults.yaml @@ -277,6 +277,14 @@ params: help: en: The AIN is printed on the type label on the back of the device. Embed it in double quotes in case of leading zeroes. de: Die AIN ist auf dem Typenschild auf der Geräterückseite aufgedruckt. Bei führenden Nullen bitte in doppelte Hochkommata setzen. + - name: coarsecurrent + type: bool + help: + en: 1A current control + de: 1A Ladestromvorgabe + description: + en: Vehicle supports 1A current steps only + de: Fahrzeug unterstützt nur 1A Schritte der Ladestromvorgabe - name: welcomecharge type: bool description: From 552cdcfa31b180eae4c1bcb1395ff8ee06496174 Mon Sep 17 00:00:00 2001 From: andig Date: Tue, 12 Nov 2024 08:20:03 +0100 Subject: [PATCH 18/58] Pun: fix logging and error handling --- tariff/pun.go | 52 ++++++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/tariff/pun.go b/tariff/pun.go index 29703bcf68..0fd135fd1b 100644 --- a/tariff/pun.go +++ b/tariff/pun.go @@ -4,7 +4,6 @@ import ( "encoding/xml" "fmt" "io" - "net/http" "net/http/cookiejar" "net/url" "slices" @@ -16,6 +15,7 @@ import ( "github.com/cenkalti/backoff/v4" "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/util" + "github.com/evcc-io/evcc/util/request" "golang.org/x/net/html" ) @@ -124,28 +124,21 @@ func (t *Pun) Type() api.TariffType { } func (t *Pun) getData(day time.Time) (api.Rates, error) { - // Initial URL - urlString := "https://www.mercatoelettrico.org/It/WebServerDataStore/MGP_Prezzi/" + day.Format("20060102") + "MGPPrezzi.xml" - // Cookie Jar zur Speicherung von Cookies zwischen den Requests - jar, _ := cookiejar.New(nil) - client := &http.Client{ - Jar: jar, - } + client := request.NewClient(t.log) + client.Jar, _ = cookiejar.New(nil) // Erster Request - resp, err := client.Get(urlString) + uri := "https://www.mercatoelettrico.org/It/WebServerDataStore/MGP_Prezzi/" + day.Format("20060102") + "MGPPrezzi.xml" + resp, err := client.Get(uri) if err != nil { - fmt.Println("Error fetching URL:", err) return nil, err } defer resp.Body.Close() - body, _ := io.ReadAll(resp.Body) - formData, err := parseFormFields(body) + formData, err := parseFormFields(resp.Body) if err != nil { - fmt.Println("Error parsing form fields:", err) - return nil, err + return nil, fmt.Errorf("form fields: %w", err) } redirectURL := resp.Request.URL.String() @@ -164,21 +157,16 @@ func (t *Pun) getData(day time.Time) (api.Rates, error) { defer resp.Body.Close() // Erneuter Request auf die ursprüngliche URL - resp, err = client.Get(urlString) + resp, err = client.Get(uri) if err != nil { - fmt.Println("Error fetching URL after form submission:", err) return nil, err } defer resp.Body.Close() // Verarbeitung der erhaltenen Daten - body, _ = io.ReadAll(resp.Body) - xmlData := []byte(string(body)) // Ersetzen Sie [Ihr XML-Datenstring hier] mit Ihrem XML-String - var dataSet NewDataSet - err = xml.Unmarshal(xmlData, &dataSet) - if err != nil { - fmt.Println("Error unmarshalling XML: ", err) + if err := xml.NewDecoder(resp.Body).Decode(&dataSet); err != nil { + return nil, err } data := make(api.Rates, 0, len(dataSet.Prezzi)) @@ -186,17 +174,17 @@ func (t *Pun) getData(day time.Time) (api.Rates, error) { for _, p := range dataSet.Prezzi { date, err := time.Parse("20060102", p.Data) if err != nil { - fmt.Println("Error parsing date: ", err) + return nil, fmt.Errorf("parse date: %w", err) } hour, err := strconv.Atoi(p.Ora) if err != nil { - fmt.Println("Error parsing hour: ", err) + return nil, fmt.Errorf("parse hour: %w", err) } location, err := time.LoadLocation("Europe/Rome") if err != nil { - fmt.Println("Error loading location: ", err) + return nil, fmt.Errorf("load location: %w", err) } start := time.Date(date.Year(), date.Month(), date.Day(), hour-1, 0, 0, 0, location) @@ -205,7 +193,7 @@ func (t *Pun) getData(day time.Time) (api.Rates, error) { priceStr := strings.Replace(p.PUN, ",", ".", -1) // Ersetzen Sie Komma durch Punkt price, err := strconv.ParseFloat(priceStr, 64) if err != nil { - fmt.Println("Error parsing price: ", err) + return nil, fmt.Errorf("parse price: %w", err) } ar := api.Rate{ @@ -220,11 +208,11 @@ func (t *Pun) getData(day time.Time) (api.Rates, error) { return data, nil } -func parseFormFields(body []byte) (url.Values, error) { - formData := url.Values{} - doc, err := html.Parse(strings.NewReader(string(body))) +func parseFormFields(body io.Reader) (url.Values, error) { + data := url.Values{} + doc, err := html.Parse(body) if err != nil { - return formData, err + return data, err } var f func(*html.Node) f = func(n *html.Node) { @@ -242,7 +230,7 @@ func parseFormFields(body []byte) (url.Values, error) { } } if inputType == "hidden" && inputName != "" { - formData.Set(inputName, inputValue) + data.Set(inputName, inputValue) } } for c := n.FirstChild; c != nil; c = c.NextSibling { @@ -250,5 +238,5 @@ func parseFormFields(body []byte) (url.Values, error) { } } f(doc) - return formData, nil + return data, nil } From 70294d1f38695eb82e7b15751e65177a4d1b9bd1 Mon Sep 17 00:00:00 2001 From: andig Date: Tue, 12 Nov 2024 08:27:36 +0100 Subject: [PATCH 19/58] chore: simplify --- tariff/pun.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tariff/pun.go b/tariff/pun.go index 0fd135fd1b..2d64e88be7 100644 --- a/tariff/pun.go +++ b/tariff/pun.go @@ -217,9 +217,7 @@ func parseFormFields(body io.Reader) (url.Values, error) { var f func(*html.Node) f = func(n *html.Node) { if n.Type == html.ElementNode && n.Data == "input" { - inputType := "" - inputName := "" - inputValue := "" + var inputType, inputName, inputValue string for _, a := range n.Attr { if a.Key == "type" { inputType = a.Val From 8766a626fe0e0ae978dabc244ff06514e9290e73 Mon Sep 17 00:00:00 2001 From: andig Date: Tue, 12 Nov 2024 08:29:13 +0100 Subject: [PATCH 20/58] chore: skip test --- templates/definition/tariff/pun.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/definition/tariff/pun.yaml b/templates/definition/tariff/pun.yaml index 91b4c826c7..5a5ec47d8d 100644 --- a/templates/definition/tariff/pun.yaml +++ b/templates/definition/tariff/pun.yaml @@ -2,6 +2,7 @@ template: pun products: - brand: PUN Orario requirements: + evcc: ["skiptest"] description: de: "Preisdaten von https://www.mercatoelettrico.org/it/. Wird oft zur Einspeisung ins Netz verwendet. Nur für Italien verfügbar." en: "Price data from https://www.mercatoelettrico.org/it/. Often used for feeding into the grid. Only available for Italy." From b0cbffe4a8811268ed284d6451394304e5cfcbc4 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Tue, 12 Nov 2024 22:35:10 +0100 Subject: [PATCH 21/58] chore: skipt energinet test --- templates/definition/tariff/energinet.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/definition/tariff/energinet.yaml b/templates/definition/tariff/energinet.yaml index c3e448ee28..3f45119e6d 100644 --- a/templates/definition/tariff/energinet.yaml +++ b/templates/definition/tariff/energinet.yaml @@ -5,6 +5,7 @@ requirements: description: de: "Nur für Dänemark verfügbar." en: "Only available for Denmark." + evcc: ["skiptest"] group: price params: - name: region From 651b155b14936afb6ecb026b260423b74d3b9139 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Tue, 12 Nov 2024 23:03:01 +0100 Subject: [PATCH 22/58] Config UI: better device currents (#17179) --- assets/js/components/Config/DeviceTags.vue | 4 ++-- i18n/cs.toml | 6 +++--- i18n/da.toml | 6 +++--- i18n/de.toml | 6 +++--- i18n/el.toml | 6 +++--- i18n/en.toml | 6 +++--- i18n/es.toml | 6 +++--- i18n/fi.toml | 6 +++--- i18n/fr.toml | 6 +++--- i18n/hr.toml | 6 +++--- i18n/hu.toml | 6 +++--- i18n/it.toml | 6 +++--- i18n/lb.toml | 6 +++--- i18n/lt.toml | 6 +++--- i18n/nl.toml | 6 +++--- i18n/pl.toml | 6 +++--- i18n/pt.toml | 6 +++--- i18n/ro.toml | 6 +++--- i18n/sl.toml | 6 +++--- i18n/sv.toml | 6 +++--- i18n/tr.toml | 6 +++--- i18n/uk.toml | 6 +++--- 22 files changed, 65 insertions(+), 65 deletions(-) diff --git a/assets/js/components/Config/DeviceTags.vue b/assets/js/components/Config/DeviceTags.vue index 00f779a503..9021b616c1 100644 --- a/assets/js/components/Config/DeviceTags.vue +++ b/assets/js/components/Config/DeviceTags.vue @@ -62,9 +62,9 @@ export default { case "range": return `${this.fmtNumber(value, 0)} km`; case "phaseCurrents": - return value.map((v) => this.fmtNumber(v, 0)).join(" ") + " A"; + return value.map((v) => this.fmtNumber(v, 1)).join(" · ") + " A"; case "phaseVoltages": - return value.map((v) => this.fmtNumber(v, 0)).join(" ") + " V"; + return value.map((v) => this.fmtNumber(v, 0)).join(" · ") + " V"; case "phasePowers": return value.map((v) => this.fmtW(v)).join(", "); case "chargeStatus": diff --git a/i18n/cs.toml b/i18n/cs.toml index e601f22d80..6aa376013f 100644 --- a/i18n/cs.toml +++ b/i18n/cs.toml @@ -38,9 +38,9 @@ current = "Proud" enabled = "Zapnuto" energy = "Energie" odometer = "Ujetých km" -phaseCurrents = "Proud L1..L3" -phasePowers = "Výkon L1..L3" -phaseVoltages = "Napětí L1..L3" +phaseCurrents = "Proud L1, L2, L3" +phasePowers = "Výkon L1, L2, L3" +phaseVoltages = "Napětí L1, L2, L3" power = "Výkon" range = "Rozsah" soc = "SoC" diff --git a/i18n/da.toml b/i18n/da.toml index 3911f3b51c..5e275c6c5f 100644 --- a/i18n/da.toml +++ b/i18n/da.toml @@ -67,9 +67,9 @@ hemsType = "System" no = "nej" odometer = "Kilometertæller" org = "Organisation" -phaseCurrents = "Strømstyrke L1..L3" -phasePowers = "Effekt L1..L3" -phaseVoltages = "Spænding L1..L3" +phaseCurrents = "Strømstyrke L1, L2, L3" +phasePowers = "Effekt L1, L2, L3" +phaseVoltages = "Spænding L1, L2, L3" power = "Effekt" powerRange = "Effekt" range = "Rækkevidde" diff --git a/i18n/de.toml b/i18n/de.toml index 6675672eb4..1ab7c08cc3 100644 --- a/i18n/de.toml +++ b/i18n/de.toml @@ -64,9 +64,9 @@ hemsType = "System" no = "Nein" odometer = "Kilometerstand" org = "Organisation" -phaseCurrents = "Strom L1..L3" -phasePowers = "Leistung L1..L3" -phaseVoltages = "Spannung L1..L3" +phaseCurrents = "Strom L1, L2, L3" +phasePowers = "Leistung L1, L2, L3" +phaseVoltages = "Spannung L1, L2, L3" power = "Leistung" powerRange = "Leistung" range = "Reichweite" diff --git a/i18n/el.toml b/i18n/el.toml index 951c4b8d3c..a2fdce6d66 100644 --- a/i18n/el.toml +++ b/i18n/el.toml @@ -65,9 +65,9 @@ hemsType = "Σύστημα" no = "όχι" odometer = "Οδόμετρο" org = "Οργανισμός" -phaseCurrents = "Ένταση L1..L3" -phasePowers = "Ισχύς L1..L3" -phaseVoltages = "Τάση L1..L3" +phaseCurrents = "Ένταση L1, L2, L3" +phasePowers = "Ισχύς L1, L2, L3" +phaseVoltages = "Τάση L1, L2, L3" power = "Ισχύς" powerRange = "Ισχύς" range = "Αυτονομία" diff --git a/i18n/en.toml b/i18n/en.toml index d8755d2792..50a42f9eee 100644 --- a/i18n/en.toml +++ b/i18n/en.toml @@ -64,9 +64,9 @@ hemsType = "System" no = "no" odometer = "Odometer" org = "Organization" -phaseCurrents = "Current L1..L3" -phasePowers = "Power L1..L3" -phaseVoltages = "Voltage L1..L3" +phaseCurrents = "Current L1, L2, L3" +phasePowers = "Power L1, L2, L3" +phaseVoltages = "Voltage L1, L2, L3" power = "Power" powerRange = "Power" range = "Range" diff --git a/i18n/es.toml b/i18n/es.toml index c83b929e85..c0d49d10e0 100644 --- a/i18n/es.toml +++ b/i18n/es.toml @@ -67,9 +67,9 @@ hemsType = "Sistema" no = "no" odometer = "Cuentakilómetros" org = "Organización" -phaseCurrents = "Actual L1..L3" -phasePowers = "Potencia L1..L3" -phaseVoltages = "Voltaje L1..L3" +phaseCurrents = "Actual L1, L2, L3" +phasePowers = "Potencia L1, L2, L3" +phaseVoltages = "Voltaje L1, L2, L3" power = "Potencia" powerRange = "Potencia" range = "Alcance" diff --git a/i18n/fi.toml b/i18n/fi.toml index b83c2783ce..96bfe233dc 100644 --- a/i18n/fi.toml +++ b/i18n/fi.toml @@ -66,9 +66,9 @@ gridPrice = "Verkosta ostonhinta" no = "ei" odometer = "Matkamittari" org = "Organisaatio" -phaseCurrents = "Virta L1..L3" -phasePowers = "Teho L1..L3" -phaseVoltages = "Jännite L1..L3" +phaseCurrents = "Virta L1, L2, L3" +phasePowers = "Teho L1, L2, L3" +phaseVoltages = "Jännite L1, L2, L3" power = "Teho" powerRange = "Teho" range = "Toimintasäde" diff --git a/i18n/fr.toml b/i18n/fr.toml index 7e84ad0c68..fbed2b85b0 100644 --- a/i18n/fr.toml +++ b/i18n/fr.toml @@ -67,9 +67,9 @@ hemsType = "Système" no = "non" odometer = "Kilométrage" org = "Organisation" -phaseCurrents = "Courant L1..L3" -phasePowers = "Puissance L1..L3" -phaseVoltages = "Voltage L1..L3" +phaseCurrents = "Courant L1, L2, L3" +phasePowers = "Puissance L1, L2, L3" +phaseVoltages = "Voltage L1, L2, L3" power = "Puissance" powerRange = "Fourchette puissance" range = "Autonomie" diff --git a/i18n/hr.toml b/i18n/hr.toml index 4aba103955..55b856e05d 100644 --- a/i18n/hr.toml +++ b/i18n/hr.toml @@ -67,9 +67,9 @@ hemsType = "Sustav" no = "ne" odometer = "Odometar" org = "Organizacija" -phaseCurrents = "Jakost struje L1..L3" -phasePowers = "Snaga L1..L3" -phaseVoltages = "Napon L1..L3" +phaseCurrents = "Jakost struje L1, L2, L3" +phasePowers = "Snaga L1, L2, L3" +phaseVoltages = "Napon L1, L2, L3" power = "Snaga" powerRange = "Snaga" range = "Doseg" diff --git a/i18n/hu.toml b/i18n/hu.toml index 1b02d4bd26..4c601d556d 100644 --- a/i18n/hu.toml +++ b/i18n/hu.toml @@ -65,9 +65,9 @@ hemsType = "Rendszer" no = "nem" odometer = "Óraállás" org = "Szervezet" -phaseCurrents = "Áram L1..L3" -phasePowers = "Teljesítmény L1..L3" -phaseVoltages = "Feszültség L1..L3" +phaseCurrents = "Áram L1, L2, L3" +phasePowers = "Teljesítmény L1, L2, L3" +phaseVoltages = "Feszültség L1, L2, L3" power = "Teljesítmény" powerRange = "Teljesítmény" range = "Hatótáv" diff --git a/i18n/it.toml b/i18n/it.toml index a2509e2ff9..a9aab24576 100644 --- a/i18n/it.toml +++ b/i18n/it.toml @@ -65,9 +65,9 @@ hemsType = "Sistema" no = "no" odometer = "Odometro" org = "Organizzazione" -phaseCurrents = "Corrente L1..L3" -phasePowers = "Potenza L1..L3" -phaseVoltages = "Voltaggio L1..L3" +phaseCurrents = "Corrente L1, L2, L3" +phasePowers = "Potenza L1, L2, L3" +phaseVoltages = "Voltaggio L1, L2, L3" power = "Potenza" powerRange = "Potenza" range = "Intervallo" diff --git a/i18n/lb.toml b/i18n/lb.toml index 2db5f4e043..f2eac1736c 100644 --- a/i18n/lb.toml +++ b/i18n/lb.toml @@ -64,9 +64,9 @@ hemsType = "System" no = "nee" odometer = "Kilometerzäler" org = "Organisatioun" -phaseCurrents = "Stroum L1..L3" -phasePowers = "Leeschtung L1..L3" -phaseVoltages = "Spannung L1..L3" +phaseCurrents = "Stroum L1, L2, L3" +phasePowers = "Leeschtung L1, L2, L3" +phaseVoltages = "Spannung L1, L2, L3" power = "Leeschtung" powerRange = "Leeschtung" range = "Autonomie" diff --git a/i18n/lt.toml b/i18n/lt.toml index 6ceacc6763..17bb4e46b8 100644 --- a/i18n/lt.toml +++ b/i18n/lt.toml @@ -67,9 +67,9 @@ hemsType = "Sistema" no = "ne" odometer = "Odometras" org = "Organizacija" -phaseCurrents = "Srovė L1..L3" -phasePowers = "Galia L1..L3" -phaseVoltages = "Įtampa L1..L3" +phaseCurrents = "Srovė L1, L2, L3" +phasePowers = "Galia L1, L2, L3" +phaseVoltages = "Įtampa L1, L2, L3" power = "Galia" powerRange = "Galia" range = "Nuvažiuojamas atstumas" diff --git a/i18n/nl.toml b/i18n/nl.toml index 7941bf1f9a..dc931a333d 100644 --- a/i18n/nl.toml +++ b/i18n/nl.toml @@ -67,9 +67,9 @@ hemsType = "Systeem" no = "nee" odometer = "Kilometerstand" org = "Organisatie" -phaseCurrents = "Stroomsterkte L1..L3" -phasePowers = "Vermogen L1..L3" -phaseVoltages = "Spanning L1..L3" +phaseCurrents = "Stroomsterkte L1, L2, L3" +phasePowers = "Vermogen L1, L2, L3" +phaseVoltages = "Spanning L1, L2, L3" power = "Vermogen" powerRange = "Vermogen" range = "Actieradius" diff --git a/i18n/pl.toml b/i18n/pl.toml index b250a3c3cd..995428dc98 100644 --- a/i18n/pl.toml +++ b/i18n/pl.toml @@ -47,9 +47,9 @@ current = "Prąd" enabled = "Włączony" energy = "Energia" odometer = "Drogomierz" -phaseCurrents = "Prąd L1..L3" -phasePowers = "Moc L1..L3" -phaseVoltages = "Napięcie L1..L3" +phaseCurrents = "Prąd L1, L2, L3" +phasePowers = "Moc L1, L2, L3" +phaseVoltages = "Napięcie L1, L2, L3" power = "Moc" range = "Zasięg" soc = "Stan naładowania" diff --git a/i18n/pt.toml b/i18n/pt.toml index 31dd1f2b1f..c196adb10c 100644 --- a/i18n/pt.toml +++ b/i18n/pt.toml @@ -67,9 +67,9 @@ hemsType = "Sistema" no = "não" odometer = "Odómetro" org = "Organização" -phaseCurrents = "Corrente L1..L3" -phasePowers = "Energia L1..L3" -phaseVoltages = "Voltagem L1..L3" +phaseCurrents = "Corrente L1, L2, L3" +phasePowers = "Energia L1, L2, L3" +phaseVoltages = "Voltagem L1, L2, L3" power = "Energia" powerRange = "Potência" range = "Distância" diff --git a/i18n/ro.toml b/i18n/ro.toml index 07153b4d3f..5fb3fdd893 100644 --- a/i18n/ro.toml +++ b/i18n/ro.toml @@ -36,9 +36,9 @@ current = "Curent" enabled = "Activat" energy = "Energie" odometer = "Kilometraj" -phaseCurrents = "Curent L1..L3" -phasePowers = "Putere L1..L3" -phaseVoltages = "Voltaj L1..L3" +phaseCurrents = "Curent L1, L2, L3" +phasePowers = "Putere L1, L2, L3" +phaseVoltages = "Voltaj L1, L2, L3" power = "Putere" range = "Autonomie" soc = "Stare de încărcare" diff --git a/i18n/sl.toml b/i18n/sl.toml index c9190ee014..5dcc548c46 100644 --- a/i18n/sl.toml +++ b/i18n/sl.toml @@ -67,9 +67,9 @@ hemsType = "Sistem" no = "ne" odometer = "Število kilometrov" org = "Organizacija" -phaseCurrents = "Tok L1..L3" -phasePowers = "Moč L1..L3" -phaseVoltages = "Napetost L1..L3" +phaseCurrents = "Tok L1, L2, L3" +phasePowers = "Moč L1, L2, L3" +phaseVoltages = "Napetost L1, L2, L3" power = "Moč" powerRange = "Moč" range = "Doseg" diff --git a/i18n/sv.toml b/i18n/sv.toml index c0957a285b..65a3f8a83e 100644 --- a/i18n/sv.toml +++ b/i18n/sv.toml @@ -67,9 +67,9 @@ hemsType = "System" no = "nej" odometer = "Mätarställning" org = "Organisation" -phaseCurrents = "Ström L1..L3" -phasePowers = "Effekt L1..L3" -phaseVoltages = "Spänning L1..L3" +phaseCurrents = "Ström L1, L2, L3" +phasePowers = "Effekt L1, L2, L3" +phaseVoltages = "Spänning L1, L2, L3" power = "Effekt" powerRange = "Kraft" range = "Räckvidd" diff --git a/i18n/tr.toml b/i18n/tr.toml index 357c76edea..d83f8df379 100644 --- a/i18n/tr.toml +++ b/i18n/tr.toml @@ -64,9 +64,9 @@ gridPrice = "Alım fiyatı" no = "hayır" odometer = "Kilometre Sayacı" org = "Organizasyon" -phaseCurrents = "Faz Akımı L1..L3" -phasePowers = "Faz Gücü L1..L3" -phaseVoltages = "Faz Voltajı L1..L3" +phaseCurrents = "Faz Akımı L1, L2, L3" +phasePowers = "Faz Gücü L1, L2, L3" +phaseVoltages = "Faz Voltajı L1, L2, L3" power = "Güç" powerRange = "“Güç”" range = "Menzil" diff --git a/i18n/uk.toml b/i18n/uk.toml index a9554c848c..eb761cdd8d 100644 --- a/i18n/uk.toml +++ b/i18n/uk.toml @@ -59,9 +59,9 @@ enabled = "Ввімкнено" energy = "Енергія" no = "ні" odometer = "Одометр" -phaseCurrents = "Cтрум L1..L3" -phasePowers = "Потужність L1..L3" -phaseVoltages = "Напруга L1..L3" +phaseCurrents = "Cтрум L1, L2, L3" +phasePowers = "Потужність L1, L2, L3" +phaseVoltages = "Напруга L1, L2, L3" power = "Потужність" range = "Дальність" soc = "SoC" From 31373f93dcaf662b57dc91fdd25f143916d8640b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=BDiga=20Deisinger?= <41201503+zigad@users.noreply.github.com> Date: Wed, 13 Nov 2024 00:19:25 +0100 Subject: [PATCH 23/58] Fix: Make Advanced Settings Text Translatable #17220 (#17221) --- assets/js/components/Config/PropertyCollapsible.vue | 4 ++-- i18n/de.toml | 2 ++ i18n/en.toml | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/assets/js/components/Config/PropertyCollapsible.vue b/assets/js/components/Config/PropertyCollapsible.vue index a01e9a5c0c..218f382f10 100644 --- a/assets/js/components/Config/PropertyCollapsible.vue +++ b/assets/js/components/Config/PropertyCollapsible.vue @@ -6,8 +6,8 @@ type="button" @click="toggle" > - Hide advanced settings - Show advanced settings + {{ $t("config.general.hideAdvancedSettings") }} + {{ $t("config.general.showAdvancedSettings") }} diff --git a/i18n/de.toml b/i18n/de.toml index 1ab7c08cc3..1ddd6c0cc0 100644 --- a/i18n/de.toml +++ b/i18n/de.toml @@ -89,12 +89,14 @@ optional = "optional" cancel = "Abbrechen" docsLink = "Siehe Dokumentation." experimental = "Experimentell" +hideAdvancedSettings = "Erweiterte einstellungen ausblenden" off = "aus" on = "an" password = "Passwort" readFromFile = "Aus Datei lesen" remove = "Entfernen" save = "Speichern" +showAdvancedSettings = "Erweiterte einstellungen anzeigen" telemetry = "Telemetrie" title = "Titel" diff --git a/i18n/en.toml b/i18n/en.toml index 50a42f9eee..ac2d171869 100644 --- a/i18n/en.toml +++ b/i18n/en.toml @@ -89,12 +89,14 @@ optional = "optional" cancel = "Cancel" docsLink = "See documentation." experimental = "Experimental" +hideAdvancedSettings = "Hide advanced settings" off = "off" on = "on" password = "Password" readFromFile = "Read from file" remove = "Remove" save = "Save" +showAdvancedSettings = "Show advanced settings" telemetry = "Telemetry" title = "Title" From 3685c2121d00de69982d01d7e87de2af040d052e Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Wed, 13 Nov 2024 07:30:42 +0100 Subject: [PATCH 24/58] Config UI: better duration fields (#17222) --- assets/js/components/Config/PropertyField.vue | 15 +++++++++++++++ assets/js/mixins/formatter.js | 9 +++++++++ 2 files changed, 24 insertions(+) diff --git a/assets/js/components/Config/PropertyField.vue b/assets/js/components/Config/PropertyField.vue index 325aeb6d4c..929bb99bb9 100644 --- a/assets/js/components/Config/PropertyField.vue +++ b/assets/js/components/Config/PropertyField.vue @@ -93,10 +93,14 @@ import "@h2d2/shopicons/es/regular/minus"; import VehicleIcon from "../VehicleIcon"; import SelectGroup from "../SelectGroup.vue"; +import formatter from "../../mixins/formatter"; + +const NS_PER_SECOND = 1000000000; export default { name: "PropertyField", components: { VehicleIcon, SelectGroup }, + mixins: [formatter], props: { id: String, property: String, @@ -149,6 +153,9 @@ export default { if (this.property === "capacity") { return "kWh"; } + if (this.type === "Duration") { + return this.fmtSecondUnit(this.value); + } return null; }, icons() { @@ -203,6 +210,10 @@ export default { return Array.isArray(this.modelValue) ? this.modelValue.join("\n") : ""; } + if (this.type === "Duration" && typeof this.modelValue === "number") { + return this.modelValue / NS_PER_SECOND; + } + return this.modelValue; }, set(value) { @@ -216,6 +227,10 @@ export default { newValue = value ? value.split("\n") : []; } + if (this.type === "Duration" && typeof newValue === "number") { + newValue = newValue * NS_PER_SECOND; + } + this.$emit("update:modelValue", newValue); }, }, diff --git a/assets/js/mixins/formatter.js b/assets/js/mixins/formatter.js index ca15885225..86396f49e4 100644 --- a/assets/js/mixins/formatter.js +++ b/assets/js/mixins/formatter.js @@ -246,6 +246,15 @@ export default { day: "numeric", }).format(date); }, + fmtSecondUnit: function (seconds) { + return new Intl.NumberFormat(this.$i18n?.locale, { + style: "unit", + unit: "second", + unitDisplay: "long", + }) + .formatToParts(seconds) + .find((part) => part.type === "unit").value; + }, fmtMoney: function (amout = 0, currency = "EUR", decimals = true, withSymbol = false) { const currencyDisplay = withSymbol ? "narrowSymbol" : "code"; const result = new Intl.NumberFormat(this.$i18n?.locale, { From 00a3d4021868e2dee6beb6149366dda7302e7e44 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Wed, 13 Nov 2024 10:39:23 +0100 Subject: [PATCH 25/58] Sessions UI: improve solar year color pallette (#17218) --- assets/js/colors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/js/colors.js b/assets/js/colors.js index 2ba6fde98c..2e536a66f8 100644 --- a/assets/js/colors.js +++ b/assets/js/colors.js @@ -18,7 +18,7 @@ const colors = reactive({ price: "#FF912FFF", co2: "#00916EFF", background: null, - selfPalette: ["#0fde41ff", "#0ba631ff", "#076f20ff", "#054e18ff", "#043611ff", "#02230bff"], + selfPalette: ["#0FDE41FF", "#FFBD2FFF", "#FD6158FF", "#03C1EFFF", "#0F662DFF", "#FF922EFF"], palette: [ "#03C1EFFF", "#FD6158FF", From 83d3b64520b998f47e2449ff9558c4351cb221ff Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 13 Nov 2024 10:39:50 +0100 Subject: [PATCH 26/58] Zendure: add global region (#17224) --- meter/zendure.go | 9 ++++++--- meter/zendure/connection.go | 4 ++-- meter/zendure/credentials.go | 14 +++++++++++--- templates/definition/meter/zendure.yaml | 6 +++++- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/meter/zendure.go b/meter/zendure.go index e3fb541b25..fd7476effd 100644 --- a/meter/zendure.go +++ b/meter/zendure.go @@ -2,6 +2,7 @@ package meter import ( "fmt" + "strings" "time" "github.com/evcc-io/evcc/api" @@ -21,9 +22,10 @@ type Zendure struct { // NewZendureFromConfig creates a Zendure meter from generic config func NewZendureFromConfig(other map[string]interface{}) (api.Meter, error) { cc := struct { - Usage, Account, Serial string - Timeout time.Duration + Usage, Account, Serial, Region string + Timeout time.Duration }{ + Region: "EU", Timeout: 30 * time.Second, } @@ -31,7 +33,8 @@ func NewZendureFromConfig(other map[string]interface{}) (api.Meter, error) { return nil, err } - conn, err := zendure.NewConnection(cc.Account, cc.Serial, cc.Timeout) + global := strings.ToUpper(cc.Region) != "EU" + conn, err := zendure.NewConnection(cc.Account, cc.Serial, global, cc.Timeout) if err != nil { return nil, err } diff --git a/meter/zendure/connection.go b/meter/zendure/connection.go index 758d4ad83a..47c447a080 100644 --- a/meter/zendure/connection.go +++ b/meter/zendure/connection.go @@ -22,7 +22,7 @@ type Connection struct { data *util.Monitor[Data] } -func NewConnection(account, serial string, timeout time.Duration) (*Connection, error) { +func NewConnection(account, serial string, global bool, timeout time.Duration) (*Connection, error) { mu.Lock() defer mu.Unlock() @@ -31,7 +31,7 @@ func NewConnection(account, serial string, timeout time.Duration) (*Connection, return conn, nil } - res, err := MqttCredentials(account, serial) + res, err := MqttCredentials(account, serial, global) if err != nil { return nil, err } diff --git a/meter/zendure/credentials.go b/meter/zendure/credentials.go index a64bdccd5d..5c1ff21dd0 100644 --- a/meter/zendure/credentials.go +++ b/meter/zendure/credentials.go @@ -8,9 +8,12 @@ import ( "github.com/evcc-io/evcc/util/request" ) -const CredentialsUri = "https://app.zendure.tech/eu/developer/api/apply" +const ( + EUCredentialsUri = "https://app.zendure.tech/eu/developer/api/apply" + GlobalCredentialsUri = "https://app.zendure.tech/v2/developer/api/apply" +) -func MqttCredentials(account, serial string) (CredentialsResponse, error) { +func MqttCredentials(account, serial string, global bool) (CredentialsResponse, error) { client := request.NewHelper(util.NewLogger("zendure")) data := CredentialsRequest{ @@ -18,7 +21,12 @@ func MqttCredentials(account, serial string) (CredentialsResponse, error) { Account: account, } - req, _ := request.New(http.MethodPost, CredentialsUri, request.MarshalJSON(data), request.JSONEncoding) + uri := EUCredentialsUri + if global { + uri = GlobalCredentialsUri + } + + req, _ := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding) var res CredentialsResponse err := client.DoJSON(req, &res) diff --git a/templates/definition/meter/zendure.yaml b/templates/definition/meter/zendure.yaml index f57b901722..ee930115fb 100644 --- a/templates/definition/meter/zendure.yaml +++ b/templates/definition/meter/zendure.yaml @@ -2,7 +2,7 @@ template: zendure products: - brand: Zendure description: - generic: Hyper V + generic: Hyper 2000 requirements: evcc: ["skiptest"] params: @@ -10,6 +10,10 @@ params: choice: ["pv", "battery"] - name: account - name: serial + - name: region + type: choice + default: EU + validvalues: ["EU", "Global"] - name: capacity default: 2 advanced: true From d6f9e7a0c8fe16fd42162e301ddb8eff42a5d114 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Wed, 13 Nov 2024 10:40:11 +0100 Subject: [PATCH 27/58] chore: npm dependency upgrade (#17217) --- package-lock.json | 1396 ++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 691 insertions(+), 707 deletions(-) diff --git a/package-lock.json b/package-lock.json index feb20ed3c1..f2bed5d7e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "@vue/eslint-config-prettier": "^10.1.0", "@vue/eslint-config-typescript": "^14.1.3", "@vue/test-utils": "^2.2.7", - "@vue/tsconfig": "^0.5.1", + "@vue/tsconfig": "^0.6.0", "axios": "^1.7.4", "body-parser": "^1.20.2", "bootstrap": "^5.2.2", @@ -84,9 +84,9 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.0.tgz", - "integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", @@ -98,9 +98,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.0.tgz", - "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", + "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -136,22 +136,13 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/generator": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.0.tgz", - "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.0", + "@babel/parser": "^7.26.2", "@babel/types": "^7.26.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", @@ -202,15 +193,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", @@ -232,15 +214,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", @@ -258,19 +231,10 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", - "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", + "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", @@ -462,9 +426,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.1.tgz", - "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", "license": "MIT", "dependencies": { "@babel/types": "^7.26.0" @@ -1494,15 +1458,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", @@ -1649,9 +1604,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.34.1", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.1.tgz", - "integrity": "sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==", + "version": "6.34.2", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.2.tgz", + "integrity": "sha512-d6n0WFvL970A9Z+l9N2dO+Hk9ev4hDYQzIx+B9tCyBP0W5wPEszi1rhuyFesNSkLZzXbQE5FPH7F/z/TMJfoPA==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.4.0", @@ -2046,9 +2001,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.2.tgz", - "integrity": "sha512-2WwyTYNVaMNUWPZTOJdkax9iqTdirrApgTbk+Qoq5EPX6myqZvG8QGFRgdKmkjKVG6/G/a565vpPauHk0+hpBA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -2068,28 +2023,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@eslint/core": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", @@ -2122,45 +2055,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/espree": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", - "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -2173,22 +2067,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@eslint/js": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", - "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", + "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2204,9 +2086,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.1.tgz", - "integrity": "sha512-HFZ4Mp26nbWk9d/BpvP0YNL6W4UoZF0VFcTw/aPPA8RpOxeFQgK+ClABGgAUXs9Y/RGX/l1vOmrqz1MQt9MNuw==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.2.tgz", + "integrity": "sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==", "license": "Apache-2.0", "dependencies": { "levn": "^0.4.1" @@ -2356,27 +2238,40 @@ "license": "MIT" }, "node_modules/@humanfs/core": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", - "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "license": "Apache-2.0", "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.5", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", - "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.0", + "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" }, "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -2391,9 +2286,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -2464,33 +2359,6 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "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" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -2732,9 +2600,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", - "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.25.0.tgz", + "integrity": "sha512-CC/ZqFZwlAIbU1wUPisHyV/XRc5RydFrNLtgl3dGYskdwPZdt4HERtKm50a/+DtTlKeCq9IXFEWR+P6blwjqBA==", "cpu": [ "arm" ], @@ -2745,9 +2613,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", - "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.25.0.tgz", + "integrity": "sha512-/Y76tmLGUJqVBXXCfVS8Q8FJqYGhgH4wl4qTA24E9v/IJM0XvJCGQVSW1QZ4J+VURO9h8YCa28sTFacZXwK7Rg==", "cpu": [ "arm64" ], @@ -2758,9 +2626,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", - "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.25.0.tgz", + "integrity": "sha512-YVT6L3UrKTlC0FpCZd0MGA7NVdp7YNaEqkENbWQ7AOVOqd/7VzyHpgIpc1mIaxRAo1ZsJRH45fq8j4N63I/vvg==", "cpu": [ "arm64" ], @@ -2771,9 +2639,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", - "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.25.0.tgz", + "integrity": "sha512-ZRL+gexs3+ZmmWmGKEU43Bdn67kWnMeWXLFhcVv5Un8FQcx38yulHBA7XR2+KQdYIOtD0yZDWBCudmfj6lQJoA==", "cpu": [ "x64" ], @@ -2783,10 +2651,36 @@ "darwin" ] }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.25.0.tgz", + "integrity": "sha512-xpEIXhiP27EAylEpreCozozsxWQ2TJbOLSivGfXhU4G1TBVEYtUPi2pOZBnvGXHyOdLAUUhPnJzH3ah5cqF01g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.25.0.tgz", + "integrity": "sha512-sC5FsmZGlJv5dOcURrsnIK7ngc3Kirnx3as2XU9uER+zjfyqIjdcMVgzy4cOawhsssqzoAX19qmxgJ8a14Qrqw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", - "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.25.0.tgz", + "integrity": "sha512-uD/dbLSs1BEPzg564TpRAQ/YvTnCds2XxyOndAO8nJhaQcqQGFgv/DAVko/ZHap3boCvxnzYMa3mTkV/B/3SWA==", "cpu": [ "arm" ], @@ -2797,9 +2691,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", - "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.25.0.tgz", + "integrity": "sha512-ZVt/XkrDlQWegDWrwyC3l0OfAF7yeJUF4fq5RMS07YM72BlSfn2fQQ6lPyBNjt+YbczMguPiJoCfaQC2dnflpQ==", "cpu": [ "arm" ], @@ -2810,9 +2704,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", - "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.25.0.tgz", + "integrity": "sha512-qboZ+T0gHAW2kkSDPHxu7quaFaaBlynODXpBVnPxUgvWYaE84xgCKAPEYE+fSMd3Zv5PyFZR+L0tCdYCMAtG0A==", "cpu": [ "arm64" ], @@ -2823,9 +2717,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", - "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.25.0.tgz", + "integrity": "sha512-ndWTSEmAaKr88dBuogGH2NZaxe7u2rDoArsejNslugHZ+r44NfWiwjzizVS1nUOHo+n1Z6qV3X60rqE/HlISgw==", "cpu": [ "arm64" ], @@ -2836,9 +2730,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", - "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.25.0.tgz", + "integrity": "sha512-BVSQvVa2v5hKwJSy6X7W1fjDex6yZnNKy3Kx1JGimccHft6HV0THTwNtC2zawtNXKUu+S5CjXslilYdKBAadzA==", "cpu": [ "ppc64" ], @@ -2849,9 +2743,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", - "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.25.0.tgz", + "integrity": "sha512-G4hTREQrIdeV0PE2JruzI+vXdRnaK1pg64hemHq2v5fhv8C7WjVaeXc9P5i4Q5UC06d/L+zA0mszYIKl+wY8oA==", "cpu": [ "riscv64" ], @@ -2862,9 +2756,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", - "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.25.0.tgz", + "integrity": "sha512-9T/w0kQ+upxdkFL9zPVB6zy9vWW1deA3g8IauJxojN4bnz5FwSsUAD034KpXIVX5j5p/rn6XqumBMxfRkcHapQ==", "cpu": [ "s390x" ], @@ -2875,9 +2769,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", - "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.25.0.tgz", + "integrity": "sha512-ThcnU0EcMDn+J4B9LD++OgBYxZusuA7iemIIiz5yzEcFg04VZFzdFjuwPdlURmYPZw+fgVrFzj4CA64jSTG4Ig==", "cpu": [ "x64" ], @@ -2888,9 +2782,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", - "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.25.0.tgz", + "integrity": "sha512-zx71aY2oQxGxAT1JShfhNG79PnjYhMC6voAjzpu/xmMjDnKNf6Nl/xv7YaB/9SIa9jDYf8RBPWEnjcdlhlv1rQ==", "cpu": [ "x64" ], @@ -2901,9 +2795,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", - "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.25.0.tgz", + "integrity": "sha512-JT8tcjNocMs4CylWY/CxVLnv8e1lE7ff1fi6kbGocWwxDq9pj30IJ28Peb+Y8yiPNSF28oad42ApJB8oUkwGww==", "cpu": [ "arm64" ], @@ -2914,9 +2808,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", - "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.25.0.tgz", + "integrity": "sha512-dRLjLsO3dNOfSN6tjyVlG+Msm4IiZnGkuZ7G5NmpzwF9oOc582FZG05+UdfTbz5Jd4buK/wMb6UeHFhG18+OEg==", "cpu": [ "ia32" ], @@ -2927,9 +2821,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", - "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.25.0.tgz", + "integrity": "sha512-/RqrIFtLB926frMhZD0a5oDa4eFIbyNEwLLloMTEjmqfwZWXywwVVOVmwTsuyhC9HKkVEZcOOi+KV4U9wmOdlg==", "cpu": [ "x64" ], @@ -3046,25 +2940,25 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.8.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.1.tgz", - "integrity": "sha512-k6Gi8Yyo8EtrNtkHXutUu2corfDf9su95VYVP10aGYMMROM6SAItZi0w1XszA6RtWTHSVp5OeFof37w0IEqCQg==", + "version": "22.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", + "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", "license": "MIT", "dependencies": { "undici-types": "~6.19.8" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.11.0.tgz", - "integrity": "sha512-KhGn2LjW1PJT2A/GfDpiyOfS4a8xHQv2myUagTM5+zsormOmBlYsnQ6pobJ8XxJmh6hnHwa2Mbe3fPrDJoDhbA==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz", + "integrity": "sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==", "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.11.0", - "@typescript-eslint/type-utils": "8.11.0", - "@typescript-eslint/utils": "8.11.0", - "@typescript-eslint/visitor-keys": "8.11.0", + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/type-utils": "8.14.0", + "@typescript-eslint/utils": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -3088,15 +2982,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.11.0.tgz", - "integrity": "sha512-lmt73NeHdy1Q/2ul295Qy3uninSqi6wQI18XwSpm8w0ZbQXUpjCAWP1Vlv/obudoBiIjJVjlztjQ+d/Md98Yxg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.14.0.tgz", + "integrity": "sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==", "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.11.0", - "@typescript-eslint/types": "8.11.0", - "@typescript-eslint/typescript-estree": "8.11.0", - "@typescript-eslint/visitor-keys": "8.11.0", + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/typescript-estree": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", "debug": "^4.3.4" }, "engines": { @@ -3116,13 +3010,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.11.0.tgz", - "integrity": "sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.14.0.tgz", + "integrity": "sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.11.0", - "@typescript-eslint/visitor-keys": "8.11.0" + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3133,13 +3027,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.11.0.tgz", - "integrity": "sha512-ItiMfJS6pQU0NIKAaybBKkuVzo6IdnAhPFZA/2Mba/uBjuPQPet/8+zh5GtLHwmuFRShZx+8lhIs7/QeDHflOg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.14.0.tgz", + "integrity": "sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.11.0", - "@typescript-eslint/utils": "8.11.0", + "@typescript-eslint/typescript-estree": "8.14.0", + "@typescript-eslint/utils": "8.14.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -3157,9 +3051,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.11.0.tgz", - "integrity": "sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.14.0.tgz", + "integrity": "sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3170,13 +3064,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.11.0.tgz", - "integrity": "sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.14.0.tgz", + "integrity": "sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==", "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.11.0", - "@typescript-eslint/visitor-keys": "8.11.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/visitor-keys": "8.14.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -3197,16 +3091,52 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/utils": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.11.0.tgz", - "integrity": "sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.14.0.tgz", + "integrity": "sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.11.0", - "@typescript-eslint/types": "8.11.0", - "@typescript-eslint/typescript-estree": "8.11.0" + "@typescript-eslint/scope-manager": "8.14.0", + "@typescript-eslint/types": "8.14.0", + "@typescript-eslint/typescript-estree": "8.14.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3220,12 +3150,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.11.0.tgz", - "integrity": "sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.14.0.tgz", + "integrity": "sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.11.0", + "@typescript-eslint/types": "8.14.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -3237,22 +3167,22 @@ } }, "node_modules/@unhead/dom": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.11.10.tgz", - "integrity": "sha512-nL1mdRzYVATZIYauK15zOI2YyM3YxCLfhbTqljEjDFJeiJUzTTi+a//5FHiUk84ewSucFnrwHNey/pEXFlyY1A==", + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.11.11.tgz", + "integrity": "sha512-4YwziCH5CmjvUzSGdZ4Klj6BqhLSTNZooA9kt47yDxj4Qw9uHqVnXwWWupYsVdIYPNsw1tR2AkHveg82y1Fn3A==", "license": "MIT", "dependencies": { - "@unhead/schema": "1.11.10", - "@unhead/shared": "1.11.10" + "@unhead/schema": "1.11.11", + "@unhead/shared": "1.11.11" }, "funding": { "url": "https://github.com/sponsors/harlan-zw" } }, "node_modules/@unhead/schema": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/@unhead/schema/-/schema-1.11.10.tgz", - "integrity": "sha512-lXh7cm5XtFaw3gc+ZVXTSfIHXiBpAywbjtEiOsz5TR4GxOjj2rtfOAl4C3Difk1yupP6L2otYmOZdn/i8EXSJg==", + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/@unhead/schema/-/schema-1.11.11.tgz", + "integrity": "sha512-xSGsWHPBYcMV/ckQeImbrVu6ddeRnrdDCgXUKv3xIjGBY+ob/96V80lGX8FKWh8GwdFSwhblISObKlDAt5K9ZQ==", "license": "MIT", "dependencies": { "hookable": "^5.5.3", @@ -3263,28 +3193,28 @@ } }, "node_modules/@unhead/shared": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/@unhead/shared/-/shared-1.11.10.tgz", - "integrity": "sha512-YQgZcOyo1id7drUeDPGn0R83pirvIcV+Car3/m7ZfCLL1Syab6uXmRckVRd69yVbUL4eirIm9IzzmvzM/OuGuw==", + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/@unhead/shared/-/shared-1.11.11.tgz", + "integrity": "sha512-RfdvUskPn90ipO+PmR98jKZ8Lsx1uuzscOenO5xcrMrtWGhlLWaEBIrbvFOvX5PZ/u8/VNMJChTXGDUjEtHmlg==", "license": "MIT", "dependencies": { - "@unhead/schema": "1.11.10" + "@unhead/schema": "1.11.11" }, "funding": { "url": "https://github.com/sponsors/harlan-zw" } }, "node_modules/@unhead/vue": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-1.11.10.tgz", - "integrity": "sha512-v6ddp4YEQCNILhYrx37Yt0GKRIFeTrb3VSmTbjh+URT+ua1mwgmNFTfl2ZldtTtri3tEkwSG1/5wLRq20ma70g==", + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-1.11.11.tgz", + "integrity": "sha512-AxsHHauZ+w0m2irwDHqkc3GdNChMLBtolk8CN3IAZM6vTwH0EbPXlFCFcIk4WwkH0opG+R2GlKTThr5H0HLm7g==", "license": "MIT", "dependencies": { - "@unhead/schema": "1.11.10", - "@unhead/shared": "1.11.10", + "@unhead/schema": "1.11.11", + "@unhead/shared": "1.11.11", "defu": "^6.1.4", "hookable": "^5.5.3", - "unhead": "1.11.10" + "unhead": "1.11.11" }, "funding": { "url": "https://github.com/sponsors/harlan-zw" @@ -3320,9 +3250,9 @@ } }, "node_modules/@vitejs/plugin-vue": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.4.tgz", - "integrity": "sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.5.tgz", + "integrity": "sha512-dlnib73G05CDBAUR/YpuZcQQ47fpjihnnNouAAqN62z+oqSsWJ+kh52GRzIxpkgFG3q11eXK7Di7RMmoCwISZA==", "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" @@ -3333,14 +3263,14 @@ } }, "node_modules/@vitest/expect": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.3.tgz", - "integrity": "sha512-SNBoPubeCJhZ48agjXruCI57DvxcsivVDdWz+SSsmjTT4QN/DfHk3zB/xKsJqMs26bLZ/pNRLnCf0j679i0uWQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.4.tgz", + "integrity": "sha512-DOETT0Oh1avie/D/o2sgMHGrzYUFFo3zqESB2Hn70z6QB1HrS2IQ9z5DfyTqU8sg4Bpu13zZe9V4+UTNQlUeQA==", "license": "MIT", "dependencies": { - "@vitest/spy": "2.1.3", - "@vitest/utils": "2.1.3", - "chai": "^5.1.1", + "@vitest/spy": "2.1.4", + "@vitest/utils": "2.1.4", + "chai": "^5.1.2", "tinyrainbow": "^1.2.0" }, "funding": { @@ -3348,21 +3278,20 @@ } }, "node_modules/@vitest/mocker": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.3.tgz", - "integrity": "sha512-eSpdY/eJDuOvuTA3ASzCjdithHa+GIF1L4PqtEELl6Qa3XafdMLBpBlZCIUCX2J+Q6sNmjmxtosAG62fK4BlqQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.4.tgz", + "integrity": "sha512-Ky/O1Lc0QBbutJdW0rqLeFNbuLEyS+mIPiNdlVlp2/yhJ0SbyYqObS5IHdhferJud8MbbwMnexg4jordE5cCoQ==", "license": "MIT", "dependencies": { - "@vitest/spy": "2.1.3", + "@vitest/spy": "2.1.4", "estree-walker": "^3.0.3", - "magic-string": "^0.30.11" + "magic-string": "^0.30.12" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/spy": "2.1.3", - "msw": "^2.3.5", + "msw": "^2.4.9", "vite": "^5.0.0" }, "peerDependenciesMeta": { @@ -3384,9 +3313,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.3.tgz", - "integrity": "sha512-XH1XdtoLZCpqV59KRbPrIhFCOO0hErxrQCMcvnQete3Vibb9UeIOX02uFPfVn3Z9ZXsq78etlfyhnkmIZSzIwQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.4.tgz", + "integrity": "sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==", "license": "MIT", "dependencies": { "tinyrainbow": "^1.2.0" @@ -3396,12 +3325,12 @@ } }, "node_modules/@vitest/runner": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.3.tgz", - "integrity": "sha512-JGzpWqmFJ4fq5ZKHtVO3Xuy1iF2rHGV4d/pdzgkYHm1+gOzNZtqjvyiaDGJytRyMU54qkxpNzCx+PErzJ1/JqQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.4.tgz", + "integrity": "sha512-sKRautINI9XICAMl2bjxQM8VfCMTB0EbsBc/EDFA57V6UQevEKY/TOPOF5nzcvCALltiLfXWbq4MaAwWx/YxIA==", "license": "MIT", "dependencies": { - "@vitest/utils": "2.1.3", + "@vitest/utils": "2.1.4", "pathe": "^1.1.2" }, "funding": { @@ -3409,13 +3338,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.3.tgz", - "integrity": "sha512-qWC2mWc7VAXmjAkEKxrScWHWFyCQx/cmiZtuGqMi+WwqQJ2iURsVY4ZfAK6dVo6K2smKRU6l3BPwqEBvhnpQGg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.4.tgz", + "integrity": "sha512-3Kab14fn/5QZRog5BPj6Rs8dc4B+mim27XaKWFWHWA87R56AKjHTGcBFKpvZKDzC4u5Wd0w/qKsUIio3KzWW4Q==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.3", - "magic-string": "^0.30.11", + "@vitest/pretty-format": "2.1.4", + "magic-string": "^0.30.12", "pathe": "^1.1.2" }, "funding": { @@ -3423,25 +3352,25 @@ } }, "node_modules/@vitest/spy": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.3.tgz", - "integrity": "sha512-Nb2UzbcUswzeSP7JksMDaqsI43Sj5+Kry6ry6jQJT4b5gAK+NS9NED6mDb8FlMRCX8m5guaHCDZmqYMMWRy5nQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.4.tgz", + "integrity": "sha512-4JOxa+UAizJgpZfaCPKK2smq9d8mmjZVPMt2kOsg/R8QkoRzydHH1qHxIYNvr1zlEaFj4SXiaaJWxq/LPLKaLg==", "license": "MIT", "dependencies": { - "tinyspy": "^3.0.0" + "tinyspy": "^3.0.2" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.3.tgz", - "integrity": "sha512-xpiVfDSg1RrYT0tX6czgerkpcKFmFOF/gCr30+Mve5V2kewCy4Prn1/NDMSRwaSmT7PRaOF83wu+bEtsY1wrvA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.4.tgz", + "integrity": "sha512-MXDnZn0Awl2S86PSNIim5PWXgIAx8CIkzu35mBdSApUip6RFOGXBCf3YFyeEu8n1IHk4bWD46DeYFu9mQlFIRg==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.3", - "loupe": "^3.1.1", + "@vitest/pretty-format": "2.1.4", + "loupe": "^3.1.2", "tinyrainbow": "^1.2.0" }, "funding": { @@ -3604,10 +3533,22 @@ } }, "node_modules/@vue/tsconfig": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.5.1.tgz", - "integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==", - "license": "MIT" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.6.0.tgz", + "integrity": "sha512-MHXNd6lzugsEHvuA6l1GqrF5jROqUon8sP/HInLPnthJiYvB0VvpHMywg7em1dBZfFZNBSkR68qH37zOdRHmCw==", + "license": "MIT", + "peerDependencies": { + "typescript": "5.x", + "vue": "^3.3.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vue": { + "optional": true + } + } }, "node_modules/abab": { "version": "2.0.6", @@ -3626,9 +3567,9 @@ } }, "node_modules/acorn": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", - "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3697,12 +3638,15 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { @@ -3895,28 +3839,19 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", - "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", + "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.2", + "@babel/helper-define-polyfill-provider": "^0.6.3", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.10.6", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", @@ -3931,12 +3866,12 @@ } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", - "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", + "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2" + "@babel/helper-define-polyfill-provider": "^0.6.3" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -4034,12 +3969,13 @@ } }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/braces": { @@ -4168,9 +4104,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001671", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001671.tgz", - "integrity": "sha512-jocyVaSSfXg2faluE6hrWkMgDOiULBMca4QLtDT39hw1YxaIPHWc1CcTCKkPmHgGH6tKji6ZNbMSmUAvENf2/A==", + "version": "1.0.30001680", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz", + "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==", "funding": [ { "type": "opencollective", @@ -4261,9 +4197,9 @@ } }, "node_modules/chart.js": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.5.tgz", - "integrity": "sha512-CVVjg1RYTJV9OCC8WeJPMx8gsV8K6WIyIEQUE3ui4AR9Hfgls9URri6Ja3hyMVBbTF8Q2KFa19PE815gWcWhng==", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.6.tgz", + "integrity": "sha512-8Y406zevUPbbIBA/HRk33khEmQPk5+cxeflWE/2rx1NJsjVWMPw/9mSP9rxHP5eqi6LNoPBVMfZHxbwLSgldYA==", "license": "MIT", "dependencies": { "@kurkle/color": "^0.3.0" @@ -4319,6 +4255,15 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/cliui/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -4339,6 +4284,18 @@ "node": ">=8" } }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/cliui/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -4474,9 +4431,9 @@ "license": "MIT" }, "node_modules/core-js": { - "version": "3.38.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz", - "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==", + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", + "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -4485,12 +4442,12 @@ } }, "node_modules/core-js-compat": { - "version": "3.38.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", - "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", + "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", "license": "MIT", "dependencies": { - "browserslist": "^4.23.3" + "browserslist": "^4.24.2" }, "funding": { "type": "opencollective", @@ -4510,9 +4467,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", + "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -4763,6 +4720,18 @@ "node": ">=8" } }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/domexception": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", @@ -4810,6 +4779,15 @@ "node": ">=14" } }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/editorconfig/node_modules/minimatch": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", @@ -4825,6 +4803,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/editorconfig/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4832,9 +4822,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.47", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.47.tgz", - "integrity": "sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ==", + "version": "1.5.56", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.56.tgz", + "integrity": "sha512-7lXb9dAvimCFdvUMTyucD4mnIndt/xhRKFAlky0CyFogdnNmdPQNoHI23msF/2V4mpTxMzgMdjK4+YRlFlRQZw==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -5084,21 +5074,21 @@ } }, "node_modules/eslint": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz", - "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", + "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", + "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.18.0", "@eslint/core": "^0.7.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.13.0", + "@eslint/js": "9.14.0", "@eslint/plugin-kit": "^0.2.0", - "@humanfs/node": "^0.16.5", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.1", + "@humanwhocodes/retry": "^0.4.0", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", @@ -5106,9 +5096,9 @@ "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.1.0", - "eslint-visitor-keys": "^4.1.0", - "espree": "^10.2.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -5253,16 +5243,6 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -5272,39 +5252,6 @@ "ms": "^2.1.1" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/eslint-plugin-node": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", @@ -5325,37 +5272,6 @@ "eslint": ">=5.16.0" } }, - "node_modules/eslint-plugin-node/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-node/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-node/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/eslint-plugin-prettier": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", @@ -5402,9 +5318,9 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "9.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.29.1.tgz", - "integrity": "sha512-MH/MbVae4HV/tM8gKAVWMPJbYgW04CK7SuzYRrlNERpxbO0P3+Zdsa2oAcFBW6xNu7W6lIkGOsFAMCRTYmrlWQ==", + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.31.0.tgz", + "integrity": "sha512-aYMUCgivhz1o4tLkRHj5oq9YgYPM4/EJc0M7TAKRLCUA5OYxRLAhYEVD2nLtTwLyixEFI+/QXSvKU9ESZFgqjQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", @@ -5438,17 +5354,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint-plugin-vue/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5481,63 +5409,20 @@ "node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", - "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/espree": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", - "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" - }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -5557,30 +5442,30 @@ "node": ">=10.13.0" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5647,6 +5532,15 @@ "node": ">=0.10.0" } }, + "node_modules/expect-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", + "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", @@ -6027,10 +5921,34 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", - "integrity": "sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==", + "version": "15.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz", + "integrity": "sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==", "license": "MIT", "engines": { "node": ">=18" @@ -6136,9 +6054,9 @@ } }, "node_modules/happy-dom": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.7.4.tgz", - "integrity": "sha512-r1vadDYGMtsHAAsqhDuk4IpPvr6N8MGKy5ntBo7tSdim+pWDxus2PNqOcOt8LuDZ4t3KJHE+gCuzupcx/GKnyQ==", + "version": "15.11.3", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.11.3.tgz", + "integrity": "sha512-MZFy3YpoX4jnQbgrTWv35gpKxvw8y9FRSOIO6CIYmpZjxbkobaB0sAW+EXCxwTZcMvvmrjD59/NYvyld6nABfw==", "license": "MIT", "dependencies": { "entities": "^4.5.0", @@ -7187,18 +7105,15 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/minimist": { @@ -7220,14 +7135,14 @@ } }, "node_modules/mlly": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.2.tgz", - "integrity": "sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.3.tgz", + "integrity": "sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==", "license": "MIT", "dependencies": { - "acorn": "^8.12.1", + "acorn": "^8.14.0", "pathe": "^1.1.2", - "pkg-types": "^1.2.0", + "pkg-types": "^1.2.1", "ufo": "^1.5.4" } }, @@ -7345,9 +7260,9 @@ "license": "MIT" }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -7537,9 +7452,9 @@ } }, "node_modules/parse5": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.0.tgz", - "integrity": "sha512-ZkDsAOcxsUMZ4Lz5fVciOehNcJ+Gb8gTzcA4yl3wnc273BAybYWrQ+Ks/OjCjSEpjvQkDSeZbybK9qj2VHHdGA==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "license": "MIT", "dependencies": { "entities": "^4.5.0" @@ -7730,9 +7645,9 @@ } }, "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "funding": [ { "type": "opencollective", @@ -7750,7 +7665,7 @@ "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.1.0", + "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, "engines": { @@ -7837,10 +7752,13 @@ "license": "MIT" }, "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "license": "MIT" + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.10.0.tgz", + "integrity": "sha512-KSKHEbjAnpUuAUserOq0FxGXCUrzC3WniuSJhvdbs102rL55266ZcHBqLWOsG30spQMlPdpy7icATiAQehg/iA==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + } }, "node_modules/punycode": { "version": "2.3.1", @@ -8006,9 +7924,9 @@ "license": "MIT" }, "node_modules/regjsparser": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.1.tgz", - "integrity": "sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ==", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.2.tgz", + "integrity": "sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==", "license": "BSD-2-Clause", "dependencies": { "jsesc": "~3.0.2" @@ -8069,9 +7987,9 @@ } }, "node_modules/rollup": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", - "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.25.0.tgz", + "integrity": "sha512-uVbClXmR6wvx5R1M3Od4utyLUxrmOcEm3pAtMphn73Apq19PDtHpgZoEvqH2YnnaNUuvKmg2DgRd2Sqv+odyqg==", "license": "MIT", "dependencies": { "@types/estree": "1.0.6" @@ -8084,22 +8002,24 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.24.0", - "@rollup/rollup-android-arm64": "4.24.0", - "@rollup/rollup-darwin-arm64": "4.24.0", - "@rollup/rollup-darwin-x64": "4.24.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", - "@rollup/rollup-linux-arm-musleabihf": "4.24.0", - "@rollup/rollup-linux-arm64-gnu": "4.24.0", - "@rollup/rollup-linux-arm64-musl": "4.24.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", - "@rollup/rollup-linux-riscv64-gnu": "4.24.0", - "@rollup/rollup-linux-s390x-gnu": "4.24.0", - "@rollup/rollup-linux-x64-gnu": "4.24.0", - "@rollup/rollup-linux-x64-musl": "4.24.0", - "@rollup/rollup-win32-arm64-msvc": "4.24.0", - "@rollup/rollup-win32-ia32-msvc": "4.24.0", - "@rollup/rollup-win32-x64-msvc": "4.24.0", + "@rollup/rollup-android-arm-eabi": "4.25.0", + "@rollup/rollup-android-arm64": "4.25.0", + "@rollup/rollup-darwin-arm64": "4.25.0", + "@rollup/rollup-darwin-x64": "4.25.0", + "@rollup/rollup-freebsd-arm64": "4.25.0", + "@rollup/rollup-freebsd-x64": "4.25.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.25.0", + "@rollup/rollup-linux-arm-musleabihf": "4.25.0", + "@rollup/rollup-linux-arm64-gnu": "4.25.0", + "@rollup/rollup-linux-arm64-musl": "4.25.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.25.0", + "@rollup/rollup-linux-riscv64-gnu": "4.25.0", + "@rollup/rollup-linux-s390x-gnu": "4.25.0", + "@rollup/rollup-linux-x64-gnu": "4.25.0", + "@rollup/rollup-linux-x64-musl": "4.25.0", + "@rollup/rollup-win32-arm64-msvc": "4.25.0", + "@rollup/rollup-win32-ia32-msvc": "4.25.0", + "@rollup/rollup-win32-x64-msvc": "4.25.0", "fsevents": "~2.3.2" } }, @@ -8249,15 +8169,12 @@ } }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", "bin": { "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/sentence-case": { @@ -8496,9 +8413,9 @@ } }, "node_modules/std-env": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", - "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", + "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", "license": "MIT" }, "node_modules/string-width": { @@ -8533,37 +8450,31 @@ "node": ">=8" } }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, - "node_modules/string-width/node_modules/ansi-regex": { - "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" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/string.prototype.trim": { @@ -8616,15 +8527,18 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-ansi-cjs": { @@ -8640,6 +8554,15 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -8881,9 +8804,9 @@ } }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", + "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", "license": "MIT", "engines": { "node": ">=16" @@ -8917,9 +8840,9 @@ } }, "node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/type-check": { @@ -9046,14 +8969,14 @@ } }, "node_modules/typescript-eslint": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.11.0.tgz", - "integrity": "sha512-cBRGnW3FSlxaYwU8KfAewxFK5uzeOAp0l2KebIlPDOT5olVi65KDG/yjBooPBG0kGW/HLkoz1c/iuBFehcS3IA==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.14.0.tgz", + "integrity": "sha512-K8fBJHxVL3kxMmwByvz8hNdBJ8a0YqKzKDX6jRlrjMuNXyd5T2V02HIq37+OiWXvUUOXgOOGiSSOh26Mh8pC3w==", "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.11.0", - "@typescript-eslint/parser": "8.11.0", - "@typescript-eslint/utils": "8.11.0" + "@typescript-eslint/eslint-plugin": "8.14.0", + "@typescript-eslint/parser": "8.14.0", + "@typescript-eslint/utils": "8.14.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9102,14 +9025,14 @@ "license": "MIT" }, "node_modules/unhead": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/unhead/-/unhead-1.11.10.tgz", - "integrity": "sha512-hypXrAI47wE3wIhkze0RMPGAWcoo45Q1+XzdqLD/OnTCzjFXQrpuE4zBy8JRexyrqp+Ud2+nFTUNf/mjfFSymw==", + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/unhead/-/unhead-1.11.11.tgz", + "integrity": "sha512-98tM2R8OWJhvS6uqTewkfIrsPqFU/VwnKpU2tVZ+jPXSWgWSLmM3K2Y2v5AEM4bZjmC/XH8pLVGzbqB7xzFI/Q==", "license": "MIT", "dependencies": { - "@unhead/dom": "1.11.10", - "@unhead/schema": "1.11.10", - "@unhead/shared": "1.11.10", + "@unhead/dom": "1.11.11", + "@unhead/schema": "1.11.11", + "@unhead/shared": "1.11.11", "hookable": "^5.5.3" }, "funding": { @@ -9257,9 +9180,9 @@ } }, "node_modules/vite": { - "version": "5.4.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz", - "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==", + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", "license": "MIT", "dependencies": { "esbuild": "^0.21.3", @@ -9355,29 +9278,30 @@ } }, "node_modules/vitest": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.3.tgz", - "integrity": "sha512-Zrxbg/WiIvUP2uEzelDNTXmEMJXuzJ1kCpbDvaKByFA9MNeO95V+7r/3ti0qzJzrxdyuUw5VduN7k+D3VmVOSA==", - "license": "MIT", - "dependencies": { - "@vitest/expect": "2.1.3", - "@vitest/mocker": "2.1.3", - "@vitest/pretty-format": "^2.1.3", - "@vitest/runner": "2.1.3", - "@vitest/snapshot": "2.1.3", - "@vitest/spy": "2.1.3", - "@vitest/utils": "2.1.3", - "chai": "^5.1.1", - "debug": "^4.3.6", - "magic-string": "^0.30.11", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.4.tgz", + "integrity": "sha512-eDjxbVAJw1UJJCHr5xr/xM86Zx+YxIEXGAR+bmnEID7z9qWfoxpHw0zdobz+TQAFOLT+nEXz3+gx6nUJ7RgmlQ==", + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.4", + "@vitest/mocker": "2.1.4", + "@vitest/pretty-format": "^2.1.4", + "@vitest/runner": "2.1.4", + "@vitest/snapshot": "2.1.4", + "@vitest/spy": "2.1.4", + "@vitest/utils": "2.1.4", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", "pathe": "^1.1.2", "std-env": "^3.7.0", "tinybench": "^2.9.0", - "tinyexec": "^0.3.0", - "tinypool": "^1.0.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", "tinyrainbow": "^1.2.0", "vite": "^5.0.0", - "vite-node": "2.1.3", + "vite-node": "2.1.4", "why-is-node-running": "^2.3.0" }, "bin": { @@ -9392,8 +9316,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "2.1.3", - "@vitest/ui": "2.1.3", + "@vitest/browser": "2.1.4", + "@vitest/ui": "2.1.4", "happy-dom": "*", "jsdom": "*" }, @@ -9419,13 +9343,13 @@ } }, "node_modules/vitest/node_modules/vite-node": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.3.tgz", - "integrity": "sha512-I1JadzO+xYX887S39Do+paRePCKoiDrWRRjp9kkG5he0t7RXNvPAJPCQSJqbGN4uCrFFeS3Kj3sLqY8NMYBEdA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.4.tgz", + "integrity": "sha512-kqa9v+oi4HwkG6g8ufRnb5AeplcRw8jUF6/7/Qz1qRQOXHImG8YnLbB+LLszENwFnoBl9xIf9nVdCFzNd7GQEg==", "license": "MIT", "dependencies": { "cac": "^6.7.14", - "debug": "^4.3.6", + "debug": "^4.3.7", "pathe": "^1.1.2", "vite": "^5.0.0" }, @@ -9461,9 +9385,9 @@ } }, "node_modules/vue-chartjs": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.1.tgz", - "integrity": "sha512-rZjqcHBxKiHrBl0CIvcOlVEBwRhpWAVf6rDU3vUfa7HuSRmGtCslc0Oc8m16oAVuk0erzc1FCtH1VCriHsrz+A==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.2.tgz", + "integrity": "sha512-NrkbRRoYshbXbWqJkTN6InoDVwVb90C0R7eAVgMWcB9dPikbruaOoTFjFYHE/+tNPdIe6qdLCDjfjPHQ0fw4jw==", "license": "MIT", "peerDependencies": { "chart.js": "^4.1.1", @@ -9471,9 +9395,9 @@ } }, "node_modules/vue-component-type-helpers": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.1.8.tgz", - "integrity": "sha512-ii36gDzrYAfOQIkOlo44yceDdT5269gKmNGxf07Qx6seH2U50+tQ2ol02XLhYPmxrh6YabAsOdte8WDrpaO6Tw==", + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.1.10.tgz", + "integrity": "sha512-lfgdSLQKrUmADiSV6PbBvYgQ33KF3Ztv6gP85MfGaGaSGMTXORVaHT1EHfsqCgzRNBstPKYDmvAV9Do5CmJ07A==", "license": "MIT" }, "node_modules/vue-eslint-parser": { @@ -9500,6 +9424,51 @@ "eslint": ">=6.0.0" } }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/vue-hot-reload-api": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", @@ -9743,6 +9712,15 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -9763,16 +9741,16 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "ansi-regex": "^5.0.1" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "engines": { + "node": ">=8" } }, "node_modules/wrap-ansi/node_modules/ansi-styles": { @@ -9787,21 +9765,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", @@ -9880,6 +9843,15 @@ "node": ">=12" } }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/yargs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -9900,6 +9872,18 @@ "node": ">=8" } }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 02ebafcb81..8309ca235a 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@vue/eslint-config-prettier": "^10.1.0", "@vue/eslint-config-typescript": "^14.1.3", "@vue/test-utils": "^2.2.7", - "@vue/tsconfig": "^0.5.1", + "@vue/tsconfig": "^0.6.0", "axios": "^1.7.4", "body-parser": "^1.20.2", "bootstrap": "^5.2.2", From 3398312e772c314e201691407da5cde64059ea64 Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 13 Nov 2024 10:40:28 +0100 Subject: [PATCH 28/58] Mqtt: allow nil/null/none/- as empty values (#17209) --- server/mqtt.go | 2 +- server/mqtt_setter.go | 29 ++++++++++++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/server/mqtt.go b/server/mqtt.go index 27063b0eec..d9f4f6920b 100644 --- a/server/mqtt.go +++ b/server/mqtt.go @@ -220,7 +220,7 @@ func (m *MQTT) listenLoadpointSetters(topic string, site site.API, lp loadpoint. }}, {"vehicle", func(payload string) error { // https://github.com/evcc-io/evcc/issues/11184 empty payload is swallowed by listener - if payload == "-" { + if isEmpty(payload) { lp.SetVehicle(nil) return nil } diff --git a/server/mqtt_setter.go b/server/mqtt_setter.go index ee6214d21d..8541260b6f 100644 --- a/server/mqtt_setter.go +++ b/server/mqtt_setter.go @@ -1,6 +1,7 @@ package server import ( + "slices" "strconv" "time" @@ -13,6 +14,10 @@ type setter struct { fun func(string) error } +func isEmpty(payload string) bool { + return slices.Contains([]string{"-", "nil", "null", "none"}, payload) +} + func setterFunc[T any](conv func(string) (T, error), set func(T) error) func(string) error { return func(payload string) error { val, err := conv(payload) @@ -23,20 +28,26 @@ func setterFunc[T any](conv func(string) (T, error), set func(T) error) func(str } } +// ptrSetter updates pointer api +func ptrSetter[T any](conv func(string) (T, error), set func(*T) error) func(string) error { + return func(payload string) error { + var val *T + v, err := conv(payload) + if err == nil { + val = &v + } else if !isEmpty(payload) { + return err + } + return set(val) + } +} + func floatSetter(set func(float64) error) func(string) error { return setterFunc(parseFloat, set) } func floatPtrSetter(set func(*float64) error) func(string) error { - return func(s string) error { - var val *float64 - if f, err := parseFloat(s); err == nil { - val = &f - } else if s != "" { - return err - } - return set(val) - } + return ptrSetter(parseFloat, set) } func intSetter(set func(int) error) func(string) error { From 5eea98fed23a13d835d9d5d42f8a034068ef3ed6 Mon Sep 17 00:00:00 2001 From: Vrabetz Date: Wed, 13 Nov 2024 16:52:18 +0100 Subject: [PATCH 29/58] Zendure: better template (#17177) --- templates/definition/meter/zendure.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/templates/definition/meter/zendure.yaml b/templates/definition/meter/zendure.yaml index ee930115fb..553c7381ed 100644 --- a/templates/definition/meter/zendure.yaml +++ b/templates/definition/meter/zendure.yaml @@ -9,7 +9,14 @@ params: - name: usage choice: ["pv", "battery"] - name: account + required: true + example: dev@zendure.com - name: serial + required: true + example: VU5D99F74021B04 + help: + de: "Zu finden in der Zendure App in den Einstellungen des Geräts" + en: "You can find this in the Zendure App in the settings of the device" - name: region type: choice default: EU From 964adbe7978adebf4cd459f4f6e177070e9cf47b Mon Sep 17 00:00:00 2001 From: premultiply <4681172+premultiply@users.noreply.github.com> Date: Wed, 13 Nov 2024 16:53:08 +0100 Subject: [PATCH 30/58] EM24: add pv usage & fix energy (#17173) --- templates/definition/meter/cg-em24.yaml | 102 +++++++++++++++++++----- 1 file changed, 82 insertions(+), 20 deletions(-) diff --git a/templates/definition/meter/cg-em24.yaml b/templates/definition/meter/cg-em24.yaml index 47616409ae..c5d82bcc95 100644 --- a/templates/definition/meter/cg-em24.yaml +++ b/templates/definition/meter/cg-em24.yaml @@ -8,28 +8,90 @@ products: generic: EM24 params: - name: usage - choice: ["grid", "charge"] + choice: ["grid", "charge", "pv"] - name: modbus choice: ["rs485", "tcpip"] render: | - type: mbmd - {{- include "modbus" . }} - model: cgem24 - power: Power - energy: Import + type: custom + power: + source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 0x28 + type: input + decode: int32 + scale: {{ if eq .usage "pv" }}-{{ end }}0.1 + energy: + source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: {{ if eq .usage "pv" }}0x5c{{ else }}0x3e{{ end }} + type: input + decode: int32 + scale: 0.1 currents: - - CurrentL1 - - CurrentL2 - - CurrentL3 - {{- if eq .usage "grid" }} - powers: - - PowerL1 - - PowerL2 - - PowerL3 - {{- end }} - {{- if eq .usage "charge" }} + - source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 0x0c + type: input + decode: uint32 + scale: 0.001 + - source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 0x0e + type: input + decode: uint32 + scale: 0.001 + - source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 0x10 + type: input + decode: uint32 + scale: 0.001 voltages: - - VoltageL1 - - VoltageL2 - - VoltageL3 - {{- end }} + - source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 0x0 + type: input + decode: uint32 + scale: 0.1 + - source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 0x2 + type: input + decode: uint32 + scale: 0.1 + - source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 0x4 + type: input + decode: uint32 + scale: 0.1 + powers: + - source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 0x12 + type: input + decode: int32 + scale: {{ if eq .usage "pv" }}-{{ end }}0.1 + - source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 0x14 + type: input + decode: int32 + scale: {{ if eq .usage "pv" }}-{{ end }}0.1 + - source: modbus + {{- include "modbus" . | indent 2 }} + register: + address: 0x16 + type: input + decode: int32 + scale: {{ if eq .usage "pv" }}-{{ end }}0.1 From 6836749cf577289f5dc4a0b38dabf6b9e2ed67fb Mon Sep 17 00:00:00 2001 From: Markus Thierolf <77847348+thierolm@users.noreply.github.com> Date: Wed, 13 Nov 2024 20:46:11 +0100 Subject: [PATCH 31/58] Shelly: Enable Pro 3EM in monophase mode (#17219) --- meter/shelly/connection.go | 4 +++ meter/shelly/switch.go | 34 ++++++++++++------ meter/shelly/types.go | 39 +++++++++++++++------ meter/shelly/types_test.go | 40 ++++++++++++++++++++++ templates/definition/meter/shelly-1pm.yaml | 4 +-- 5 files changed, 99 insertions(+), 22 deletions(-) diff --git a/meter/shelly/connection.go b/meter/shelly/connection.go index 9fafe41539..388b2d7add 100644 --- a/meter/shelly/connection.go +++ b/meter/shelly/connection.go @@ -19,6 +19,8 @@ type Connection struct { channel int gen int // Shelly api generation devicetype string // Shelly device type + app string // Shelly device app code + profile string // Shelly device profile } // NewConnection creates a new Shelly device connection. @@ -45,6 +47,8 @@ func NewConnection(uri, user, password string, channel int) (*Connection, error) channel: channel, gen: resp.Gen, devicetype: resp.Type, + app: resp.App, + profile: resp.Profile, } conn.Client.Transport = request.NewTripper(log, transport.Insecure()) diff --git a/meter/shelly/switch.go b/meter/shelly/switch.go index 48dad7fc84..26795a9c61 100644 --- a/meter/shelly/switch.go +++ b/meter/shelly/switch.go @@ -42,18 +42,25 @@ func (sh *Switch) CurrentPower() (float64, error) { } default: + var resem Gen2EmStatusResponse var res Gen2StatusResponse - if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil { - return 0, err + if d.app == "Pro3EM" && d.profile == "monophase" { + if err := d.execGen2Cmd("Shelly.GetStatus", false, &resem); err != nil { + return 0, err + } + } else { + if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil { + return 0, err + } } switch d.channel { case 1: - power = res.Switch1.Apower + res.Pm1.Apower + power = res.Switch1.Apower + res.Pm1.Apower + resem.Em1.ActPower case 2: - power = res.Switch2.Apower + res.Pm2.Apower + power = res.Switch2.Apower + res.Pm2.Apower + resem.Em2.ActPower default: - power = res.Switch0.Apower + res.Pm0.Apower + power = res.Switch0.Apower + res.Pm0.Apower + resem.Em0.ActPower } } @@ -123,18 +130,25 @@ func (sh *Switch) TotalEnergy() (float64, error) { energy = gen1Energy(d.devicetype, energy) default: + var resem Gen2EmStatusResponse var res Gen2StatusResponse - if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil { - return 0, err + if d.app == "Pro3EM" && d.profile == "monophase" { + if err := d.execGen2Cmd("Shelly.GetStatus", false, &resem); err != nil { + return 0, err + } + } else { + if err := d.execGen2Cmd("Shelly.GetStatus", false, &res); err != nil { + return 0, err + } } switch d.channel { case 1: - energy = res.Switch1.Aenergy.Total + res.Pm1.Aenergy.Total + energy = res.Switch1.Aenergy.Total + res.Pm1.Aenergy.Total + resem.Em1Data.TotalActEnergy - resem.Em1Data.TotalActRetEnergy case 2: - energy = res.Switch2.Aenergy.Total + res.Pm2.Aenergy.Total + energy = res.Switch2.Aenergy.Total + res.Pm2.Aenergy.Total + resem.Em2Data.TotalActEnergy - resem.Em2Data.TotalActRetEnergy default: - energy = res.Switch0.Aenergy.Total + res.Pm0.Aenergy.Total + energy = res.Switch0.Aenergy.Total + res.Pm0.Aenergy.Total + resem.Em0Data.TotalActEnergy - resem.Em0Data.TotalActRetEnergy } } diff --git a/meter/shelly/types.go b/meter/shelly/types.go index c06228c532..5824d9811a 100644 --- a/meter/shelly/types.go +++ b/meter/shelly/types.go @@ -8,9 +8,11 @@ type DeviceInfo struct { Model string `json:"model"` Type string `json:"type"` Mac string `json:"mac"` + App string `json:"app"` Auth bool `json:"auth"` AuthEn bool `json:"auth_en"` NumMeters int `json:"num_meters"` + Profile string `json:"profile"` } type Gen2RpcPost struct { @@ -40,17 +42,34 @@ type Gen2StatusResponse struct { Pm2 Gen2Switch `json:"pm3:2"` } +type Gen2Em struct { + Current float64 `json:"current"` + Voltage float64 `json:"voltage"` + ActPower float64 `json:"act_power"` +} + +type Gen2EmData struct { + TotalActEnergy float64 `json:"total_act_energy"` + TotalActRetEnergy float64 `json:"total_act_ret_energy"` +} + type Gen2EmStatusResponse struct { - TotalPower float64 `json:"total_act_power"` - CurrentA float64 `json:"a_current"` - CurrentB float64 `json:"b_current"` - CurrentC float64 `json:"c_current"` - VoltageA float64 `json:"a_voltage"` - VoltageB float64 `json:"b_voltage"` - VoltageC float64 `json:"c_voltage"` - PowerA float64 `json:"a_act_power"` - PowerB float64 `json:"b_act_power"` - PowerC float64 `json:"c_act_power"` + TotalPower float64 `json:"total_act_power"` + CurrentA float64 `json:"a_current"` + CurrentB float64 `json:"b_current"` + CurrentC float64 `json:"c_current"` + VoltageA float64 `json:"a_voltage"` + VoltageB float64 `json:"b_voltage"` + VoltageC float64 `json:"c_voltage"` + PowerA float64 `json:"a_act_power"` + PowerB float64 `json:"b_act_power"` + PowerC float64 `json:"c_act_power"` + Em0 Gen2Em `json:"em1:0"` + Em1 Gen2Em `json:"em1:1"` + Em2 Gen2Em `json:"em1:2"` + Em0Data Gen2EmData `json:"em1data:0"` + Em1Data Gen2EmData `json:"em1data:1"` + Em2Data Gen2EmData `json:"em1data:2"` } type Gen2EmDataStatusResponse struct { diff --git a/meter/shelly/types_test.go b/meter/shelly/types_test.go index ad4006749c..2e4e968e82 100644 --- a/meter/shelly/types_test.go +++ b/meter/shelly/types_test.go @@ -67,4 +67,44 @@ func TestUnmarshalGen2StatusResponse(t *testing.T) { assert.Equal(t, 3551.682, res.Pm0.Aenergy.Total) assert.Equal(t, 1780.1, res.Pm0.Apower) } + + { + // Shelly Pro 3EM + var res Gen2EmStatusResponse + + jsonstr := `{"ble":{},"bthome":{"errors":["bluetooth_disabled"]},"cloud":{"connected":true},"em1:0":{"id":0,"current":3.705,"voltage":242.8,"act_power":598.9,"aprt_power":900.6,"pf":0.66,"freq":50.0,"calibration":"factory"},"em1:1":{"id":1,"current":0.194,"voltage":242.8,"act_power":0.0,"aprt_power":47.2,"pf":0.00,"freq":50.0,"calibration":"factory"},"em1:2":{"id":2,"current":0.027,"voltage":242.8,"act_power":0.0,"aprt_power":6.6,"pf":0.00,"freq":50.0,"calibration":"factory"},"em1data:0":{"id":0,"total_act_energy":3458.24,"total_act_ret_energy":1605.24},"em1data:1":{"id":1,"total_act_energy":2768.67,"total_act_ret_energy":25.49},"em1data:2":{"id":2,"total_act_energy":3.09,"total_act_ret_energy":0.71},"eth":{"ip":null},"modbus":{},"mqtt":{"connected":false},"sys":{"mac":"FCE8C0DBA850","restart_required":false,"time":"19:46","unixtime":1731404780,"uptime":563,"ram_size":247148,"ram_free":110596,"fs_size":524288,"fs_free":176128,"cfg_rev":21,"kvs_rev":0,"schedule_rev":3,"webhook_rev":1,"available_updates":{},"reset_reason":3},"temperature:0":{"id": 0,"tC":39.0, "tF":102.2},"wifi":{"sta_ip":"192.168.40.174","status":"got ip","ssid":"IoT","rssi":-67},"ws":{"connected":false}}` + require.NoError(t, json.Unmarshal([]byte(jsonstr), &res)) + // Channel 0 (1) + assert.Equal(t, 598.9, res.Em0.ActPower) + assert.Equal(t, 3.705, res.Em0.Current) + assert.Equal(t, 242.8, res.Em0.Voltage) + assert.Equal(t, 3458.24, res.Em0Data.TotalActEnergy) + assert.Equal(t, 1605.24, res.Em0Data.TotalActRetEnergy) + // Channel 1 (2) + assert.Equal(t, 0.0, res.Em1.ActPower) + assert.Equal(t, 0.194, res.Em1.Current) + assert.Equal(t, 242.8, res.Em1.Voltage) + assert.Equal(t, 2768.67, res.Em1Data.TotalActEnergy) + assert.Equal(t, 25.49, res.Em1Data.TotalActRetEnergy) + // Channel 2 (3) + assert.Equal(t, 0.0, res.Em2.ActPower) + assert.Equal(t, 0.027, res.Em2.Current) + assert.Equal(t, 242.8, res.Em2.Voltage) + assert.Equal(t, 3.09, res.Em2Data.TotalActEnergy) + assert.Equal(t, 0.71, res.Em2Data.TotalActRetEnergy) + } +} + +// Test Shelly device info +func TestUnmarshalDeviceInfoResponse(t *testing.T) { + { + // Shelly Pro 3EM + var res DeviceInfo + + jsonstr := `{"name":null,"id":"shellypro3em-fce8c0dba900","mac":"FCE8C0DBA900","slot":1,"model":"SPEM-003CEBEU","gen":2,"fw_id":"20241011-114455/1.4.4-g6d2a586","ver":"1.4.4","app":"Pro3EM","auth_en":false,"auth_domain":null,"profile":"monophase"}` + require.NoError(t, json.Unmarshal([]byte(jsonstr), &res)) + + assert.Equal(t, "Pro3EM", res.App) + assert.Equal(t, "monophase", res.Profile) + } } diff --git a/templates/definition/meter/shelly-1pm.yaml b/templates/definition/meter/shelly-1pm.yaml index 3dd14314d6..bb6383494f 100644 --- a/templates/definition/meter/shelly-1pm.yaml +++ b/templates/definition/meter/shelly-1pm.yaml @@ -2,11 +2,11 @@ template: shelly-1pm products: - brand: Shelly description: - generic: 1PM, EM, Plug S + generic: 1PM, EM, Plug S, Pro 3EM in monophase mode group: switchsockets params: - name: usage - choice: ["pv", "charge"] + choice: ["grid", "pv", "charge"] - name: host - name: user - name: password From b6997f710defc9e480264cd40947c5c299a38a7a Mon Sep 17 00:00:00 2001 From: eckerse <45845879+eckerse@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:19:12 +0100 Subject: [PATCH 32/58] SMA Hybrid: add max charge power (#17241) Co-authored-by: Sebastian Eckert --- templates/definition/meter/sma-hybrid.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/templates/definition/meter/sma-hybrid.yaml b/templates/definition/meter/sma-hybrid.yaml index cb23c740a2..0e6aeeb34e 100644 --- a/templates/definition/meter/sma-hybrid.yaml +++ b/templates/definition/meter/sma-hybrid.yaml @@ -23,6 +23,13 @@ params: type: duration default: 30s advanced: true + - name: chargepower + default: 100000 # 100kW, inverter will use it's maximum by default + advanced: true + help: + de: Ladeleistung für Netzladen in W + en: Charging power for grid charging in W + usages: ["battery"] render: | type: custom {{- if eq .usage "grid" }} @@ -167,7 +174,7 @@ render: | source: sequence set: - source: const - value: -2147483647 # Wirkleistungsvorgabe + value: -{{ .chargepower }} # Wirkleistungsvorgabe set: source: modbus {{- include "modbus" . | indent 12 }} From 52ca2c85de949f1815f52d429d262679c3bc60ef Mon Sep 17 00:00:00 2001 From: mfuchs1984 <57141790+mfuchs1984@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:19:47 +0100 Subject: [PATCH 33/58] Mennekes: reduce heartbeat interval to 5 seconds (#17260) Ref. https://github.com/evcc-io/evcc/discussions/17087#discussioncomment-11252216 --- charger/mennekes-compact.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charger/mennekes-compact.go b/charger/mennekes-compact.go index d334ab358b..577e22e56c 100644 --- a/charger/mennekes-compact.go +++ b/charger/mennekes-compact.go @@ -58,7 +58,7 @@ const ( mennekesRegChargedEnergyTotal = 0x1000 // float32 mennekesAllowed = 1 - mennekesHeartbeatInterval = 8 * time.Second + mennekesHeartbeatInterval = 5 * time.Second mennekesHeartbeatToken = 0x55AA // 21930 ) From 1a8b412ced7b96bf98160853063c35e230544a99 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Thu, 14 Nov 2024 13:33:54 +0100 Subject: [PATCH 34/58] Tariff: better rate matching error (#17255) --- api/rates.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/api/rates.go b/api/rates.go index 578a59aa04..14ccfb1085 100644 --- a/api/rates.go +++ b/api/rates.go @@ -1,7 +1,7 @@ package api import ( - "errors" + "fmt" "slices" "time" ) @@ -36,5 +36,9 @@ func (r Rates) Current(now time.Time) (Rate, error) { } } - return Rate{}, errors.New("no matching rate") + if len(r) == 0 { + return Rate{}, fmt.Errorf("no matching rate for: %s", now.Local().Format(time.RFC3339)) + } + return Rate{}, fmt.Errorf("no matching rate for: %s, %d rates (%s to %s)", + now.Local().Format(time.RFC3339), len(r), r[0].Start.Local().Format(time.RFC3339), r[len(r)-1].End.Local().Format(time.RFC3339)) } From e71f7602aa1aa68059090a6d0f0cd1fde50e9207 Mon Sep 17 00:00:00 2001 From: andig Date: Thu, 14 Nov 2024 13:36:32 +0100 Subject: [PATCH 35/58] chore: fix template --- templates/definition/meter/sma-hybrid.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/definition/meter/sma-hybrid.yaml b/templates/definition/meter/sma-hybrid.yaml index 0e6aeeb34e..7431fbc7be 100644 --- a/templates/definition/meter/sma-hybrid.yaml +++ b/templates/definition/meter/sma-hybrid.yaml @@ -24,7 +24,7 @@ params: default: 30s advanced: true - name: chargepower - default: 100000 # 100kW, inverter will use it's maximum by default + default: 100000 # 100kW, inverter will use it's maximum by default advanced: true help: de: Ladeleistung für Netzladen in W From 576cd71a443e58cdbdb82341891069f1f3862a77 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Thu, 14 Nov 2024 13:49:30 +0100 Subject: [PATCH 36/58] Auth: disable via cli flag (#17249) --- cmd/flags.go | 3 +++ cmd/root.go | 11 ++++++++++- server/http.go | 3 +-- server/http_auth.go | 10 ++++++++++ tests/auth.spec.js | 18 +++++++++++++++++- tests/evcc.js | 24 ++++++++++++++++-------- util/auth/auth.go | 15 +++++++++++++-- 7 files changed, 70 insertions(+), 14 deletions(-) diff --git a/cmd/flags.go b/cmd/flags.go index 3e977b933a..6f5b363645 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -11,6 +11,9 @@ const ( flagIgnoreDatabase = "ignore-db" flagIgnoreDatabaseDescription = "Run command ignoring service database" + flagDisableAuth = "disable-auth" + flagDisableAuthDescription = "Disable authentication (dangerous)" + flagBatteryMode = "battery-mode" flagBatteryModeDescription = "Set battery mode (normal, hold, charge)" flagBatteryModeWait = "battery-mode-wait" diff --git a/cmd/root.go b/cmd/root.go index 4fb4ef7ea8..bd331f5c0c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -18,6 +18,7 @@ import ( "github.com/evcc-io/evcc/server" "github.com/evcc-io/evcc/server/updater" "github.com/evcc-io/evcc/util" + "github.com/evcc-io/evcc/util/auth" "github.com/evcc-io/evcc/util/config" "github.com/evcc-io/evcc/util/pipe" "github.com/evcc-io/evcc/util/sponsor" @@ -75,6 +76,8 @@ func init() { rootCmd.Flags().Bool("profile", false, "Expose pprof profiles") bind(rootCmd, "profile") + + rootCmd.Flags().Bool(flagDisableAuth, false, flagDisableAuthDescription) } // initConfig reads in config file and ENV variables if set @@ -270,7 +273,13 @@ func runRoot(cmd *cobra.Command, args []string) { // allow web access for vehicles configureAuth(conf.Network, config.Instances(config.Vehicles().Devices()), httpd.Router(), valueChan) - httpd.RegisterSystemHandler(valueChan, cache, func() { + auth := auth.New() + if ok, _ := cmd.Flags().GetBool(flagDisableAuth); ok { + log.WARN.Println("❗❗❗ Authentication is disabled. This is dangerous. Your data and credentials are not protected.") + auth.Disable() + } + + httpd.RegisterSystemHandler(valueChan, cache, auth, func() { log.INFO.Println("evcc was stopped by user. OS should restart the service. Or restart manually.") once.Do(func() { close(stopC) }) // signal loop to end }) diff --git a/server/http.go b/server/http.go index 8ade922129..68265d695b 100644 --- a/server/http.go +++ b/server/http.go @@ -190,9 +190,8 @@ func (s *HTTPd) RegisterSiteHandlers(site site.API, valueChan chan<- util.Param) } // RegisterSystemHandler provides system level handlers -func (s *HTTPd) RegisterSystemHandler(valueChan chan<- util.Param, cache *util.Cache, shutdown func()) { +func (s *HTTPd) RegisterSystemHandler(valueChan chan<- util.Param, cache *util.Cache, auth auth.Auth, shutdown func()) { router := s.Server.Handler.(*mux.Router) - auth := auth.New() // api api := router.PathPrefix("/api").Subrouter() diff --git a/server/http_auth.go b/server/http_auth.go index 160bd2ebd2..0b51e67579 100644 --- a/server/http_auth.go +++ b/server/http_auth.go @@ -73,6 +73,11 @@ func jwtFromRequest(r *http.Request) string { // authStatusHandler login status (true/false) based on jwt token. Error if admin password is not configured func authStatusHandler(auth auth.Auth) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + if auth.Disabled() { + w.Write([]byte("true")) + return + } + if !auth.IsAdminPasswordConfigured() { http.Error(w, "Not implemented", http.StatusNotImplemented) return @@ -130,6 +135,11 @@ func logoutHandler(w http.ResponseWriter, r *http.Request) { func ensureAuthHandler(auth auth.Auth) mux.MiddlewareFunc { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if auth.Disabled() { + next.ServeHTTP(w, r) + return + } + // check jwt token ok, err := auth.ValidateJwtToken(jwtFromRequest(r)) if !ok || err != nil { diff --git a/tests/auth.spec.js b/tests/auth.spec.js index 783b337b1f..d81f03b30a 100644 --- a/tests/auth.spec.js +++ b/tests/auth.spec.js @@ -89,7 +89,7 @@ test("http iframe hint", async ({ page }) => { }); test("update password", async ({ page }) => { - const instance = await start(BASIC, "password.sql"); + await start(BASIC, "password.sql"); await page.goto("/"); const oldPassword = "secret"; @@ -140,3 +140,19 @@ test("update password", async ({ page }) => { await stop(); }); + +test("disable auth", async ({ page }) => { + await start(BASIC, null, "--disable-auth"); + await page.goto("/"); + + // no password modal + const modal = page.getByTestId("password-modal"); + await expect(modal).not.toBeVisible(); + + // configuration page without login + await page.getByTestId("topnavigation-button").click(); + await page.getByRole("link", { name: "Configuration" }).click(); + await expect(page.getByRole("heading", { name: "Configuration" })).toBeVisible(); + + await stop(); +}); diff --git a/tests/evcc.js b/tests/evcc.js index a7d2c278ff..686d7169a7 100644 --- a/tests/evcc.js +++ b/tests/evcc.js @@ -42,12 +42,12 @@ function dbPath() { return path.join(os.tmpdir(), file); } -export async function start(config, sqlDumps) { +export async function start(config, sqlDumps, flags) { await _clean(); if (sqlDumps) { await _restoreDatabase(sqlDumps); } - return await _start(config); + return await _start(config, flags); } export async function stop(instance) { @@ -77,14 +77,15 @@ async function _restoreDatabase(sqlDumps) { } } -async function _start(config) { +async function _start(config, flags = []) { const configFile = config.includes("/") ? config : `tests/${config}`; const port = workerPort(); log(`wait until port ${port} is available`); // wait for port to be available await waitOn({ resources: [`tcp:${port}`], reverse: true, log: true }); - log("starting evcc", { config, port }); - const instance = spawn(BINARY, ["--config", configFile], { + const additionalFlags = typeof flags === "string" ? [flags] : flags; + log("starting evcc", { config, port, additionalFlags }); + const instance = spawn(BINARY, ["--config", configFile, additionalFlags], { env: { EVCC_NETWORK_PORT: port.toString(), EVCC_DATABASE_DSN: dbPath() }, stdio: ["pipe", "pipe", "pipe"], }); @@ -108,10 +109,17 @@ async function _stop(instance) { log("evcc is down", { port }); return; } + // check if auth is required + const res = await axios.get(`${baseUrl()}/api/auth/status`); + log("auth status", res.status, res.statusText, res.data); + let cookie; + // login required + if (!res.data) { + const res = await axios.post(`${baseUrl()}/api/auth/login`, { password: "secret" }); + log("login", res.status, res.statusText); + cookie = res.headers["set-cookie"]; + } log("shutting down evcc", { port }); - const res = await axios.post(`${baseUrl()}/api/auth/login`, { password: "secret" }); - log(res.status, res.statusText); - const cookie = res.headers["set-cookie"]; await axios.post(`${baseUrl()}/api/system/shutdown`, {}, { headers: { cookie } }); log(`wait until port ${port} is closed`); await waitOn({ resources: [`tcp:${port}`], reverse: true, log: true }); diff --git a/util/auth/auth.go b/util/auth/auth.go index 1274137efb..a6cd4f7ef0 100644 --- a/util/auth/auth.go +++ b/util/auth/auth.go @@ -22,18 +22,21 @@ type Auth interface { GenerateJwtToken(time.Duration) (string, error) ValidateJwtToken(string) (bool, error) IsAdminPasswordConfigured() bool + Disable() + Disabled() bool } type auth struct { settings settings.API + disabled bool } func New() Auth { - return &auth{settings: new(settings.Settings)} + return &auth{settings: new(settings.Settings), disabled: false} } func NewMock(settings settings.API) Auth { - return &auth{settings: settings} + return &auth{settings: settings, disabled: false} } func (a *auth) hashPassword(password string) (string, error) { @@ -140,3 +143,11 @@ func (a *auth) ValidateJwtToken(tokenString string) (bool, error) { return true, nil } + +func (a *auth) Disable() { + a.disabled = true +} + +func (a *auth) Disabled() bool { + return a.disabled +} From 9780bd3cc74d975aa60f4cdf967f429078fc14b9 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Thu, 14 Nov 2024 16:51:36 +0100 Subject: [PATCH 37/58] chore: speed up e2e tests (#17262) --- tests/auth.spec.js | 8 ++++---- tests/basics.spec.js | 2 +- tests/battery-settings.spec.js | 2 +- tests/boot.spec.js | 2 +- tests/config-battery.spec.js | 6 ++---- tests/config-grid.spec.js | 5 ++--- tests/config-messaging.spec.js | 5 ++--- tests/config-mqtt.spec.js | 5 ++--- tests/config-tariffs.spec.js | 10 +++++----- tests/config-vehicles.spec.js | 17 ++++++----------- tests/config.spec.js | 7 ++----- tests/evcc.js | 6 +++--- tests/heating.spec.js | 2 +- tests/limits.spec.js | 2 +- tests/logs.spec.js | 7 +------ tests/modals.spec.js | 11 ++--------- tests/plan.spec.js | 2 +- tests/sessions.spec.js | 2 +- tests/smart-cost-only.spec.js | 2 +- tests/smart-cost.spec.js | 2 +- tests/statistics.spec.js | 2 +- tests/utils.js | 6 ------ tests/vehicle-error.spec.js | 2 +- tests/vehicle-settings.spec.js | 2 +- 24 files changed, 43 insertions(+), 74 deletions(-) diff --git a/tests/auth.spec.js b/tests/auth.spec.js index d81f03b30a..4c7078ec69 100644 --- a/tests/auth.spec.js +++ b/tests/auth.spec.js @@ -6,7 +6,7 @@ test.use({ baseURL: baseUrl() }); const BASIC = "basics.evcc.yaml"; test("set initial password", async ({ page }) => { - await start(BASIC); + await start(BASIC, null, ""); await page.goto("/"); const modal = page.getByTestId("password-modal"); @@ -34,7 +34,7 @@ test("set initial password", async ({ page }) => { }); test("login", async ({ page }) => { - await start(BASIC, "password.sql"); + await start(BASIC, "password.sql", ""); await page.goto("/"); // go to config @@ -61,7 +61,7 @@ test("login", async ({ page }) => { }); test("http iframe hint", async ({ page }) => { - await start(BASIC, "password.sql"); + await start(BASIC, "password.sql", ""); await page.goto("/"); // go to config @@ -89,7 +89,7 @@ test("http iframe hint", async ({ page }) => { }); test("update password", async ({ page }) => { - await start(BASIC, "password.sql"); + await start(BASIC, "password.sql", ""); await page.goto("/"); const oldPassword = "secret"; diff --git a/tests/basics.spec.js b/tests/basics.spec.js index 4a85041430..a832d95626 100644 --- a/tests/basics.spec.js +++ b/tests/basics.spec.js @@ -4,7 +4,7 @@ import { start, stop, baseUrl } from "./evcc"; test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { - await start("basics.evcc.yaml", "password.sql"); + await start("basics.evcc.yaml"); }); test.afterAll(async () => { await stop(); diff --git a/tests/battery-settings.spec.js b/tests/battery-settings.spec.js index 42fe67c253..4dba33b1ae 100644 --- a/tests/battery-settings.spec.js +++ b/tests/battery-settings.spec.js @@ -4,7 +4,7 @@ import { enableExperimental } from "./utils"; test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { - await start("battery-settings.evcc.yaml", "password.sql"); + await start("battery-settings.evcc.yaml"); }); test.afterAll(async () => { await stop(); diff --git a/tests/boot.spec.js b/tests/boot.spec.js index 0b2e983a02..4df26c1246 100644 --- a/tests/boot.spec.js +++ b/tests/boot.spec.js @@ -4,7 +4,7 @@ import { enableExperimental } from "./utils"; test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { - await start("battery-settings.evcc.yaml", "password.sql"); + await start("battery-settings.evcc.yaml"); }); test.afterAll(async () => { await stop(); diff --git a/tests/config-battery.spec.js b/tests/config-battery.spec.js index 2a86c64170..9cb90ee6f4 100644 --- a/tests/config-battery.spec.js +++ b/tests/config-battery.spec.js @@ -1,7 +1,7 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; import { startSimulator, stopSimulator, simulatorUrl, simulatorHost } from "./simulator"; -import { enableExperimental, login } from "./utils"; +import { enableExperimental } from "./utils"; const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; @@ -9,7 +9,7 @@ test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { await startSimulator(); - await start(CONFIG_GRID_ONLY, "password.sql"); + await start(CONFIG_GRID_ONLY); }); test.afterAll(async () => { await stop(); @@ -25,7 +25,6 @@ test.describe("battery meter", async () => { await page.getByRole("button", { name: "Apply changes" }).click(); await page.goto("/#/config"); - await login(page); await enableExperimental(page); await expect(page.getByTestId("battery")).toHaveCount(0); @@ -73,7 +72,6 @@ test.describe("battery meter", async () => { test("advanced fields", async ({ page }) => { await page.goto("/#/config"); - await login(page); await enableExperimental(page); await page.getByRole("button", { name: "Add solar or battery" }).click(); diff --git a/tests/config-grid.spec.js b/tests/config-grid.spec.js index dac01b1a02..d10fc352b3 100644 --- a/tests/config-grid.spec.js +++ b/tests/config-grid.spec.js @@ -1,7 +1,7 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; import { startSimulator, stopSimulator, simulatorUrl, simulatorHost } from "./simulator"; -import { enableExperimental, login } from "./utils"; +import { enableExperimental } from "./utils"; const CONFIG_EMPTY = "config-empty.evcc.yaml"; @@ -9,7 +9,7 @@ test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { await startSimulator(); - await start(CONFIG_EMPTY, "password.sql"); + await start(CONFIG_EMPTY); }); test.afterAll(async () => { await stop(); @@ -32,7 +32,6 @@ test.describe("grid meter", async () => { await page.getByRole("button", { name: "Apply changes" }).click(); await page.goto("/#/config"); - await login(page); await enableExperimental(page); await expect(page.getByTestId("grid")).toHaveCount(1); diff --git a/tests/config-messaging.spec.js b/tests/config-messaging.spec.js index fa7fe88a0f..c0b55f5b65 100644 --- a/tests/config-messaging.spec.js +++ b/tests/config-messaging.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, baseUrl } from "./evcc"; -import { enableExperimental, login } from "./utils"; +import { enableExperimental } from "./utils"; const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; @@ -14,13 +14,12 @@ const SELECT_ALL = "ControlOrMeta+KeyA"; async function goToConfig(page) { await page.goto("/#/config"); - await login(page); await enableExperimental(page); } test.describe("messaging", async () => { test("save a comment", async ({ page }) => { - await start(CONFIG_GRID_ONLY, "password.sql"); + await start(CONFIG_GRID_ONLY); await goToConfig(page); await page.getByTestId("messaging").getByRole("button", { name: "edit" }).click(); diff --git a/tests/config-mqtt.spec.js b/tests/config-mqtt.spec.js index d2dacaba63..abec62f540 100644 --- a/tests/config-mqtt.spec.js +++ b/tests/config-mqtt.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; -import { enableExperimental, login } from "./utils"; +import { enableExperimental } from "./utils"; const CONFIG = "config-grid-only.evcc.yaml"; @@ -8,9 +8,8 @@ test.use({ baseURL: baseUrl() }); test.describe.configure({ mode: "parallel" }); test.beforeEach(async ({ page }) => { - await start(CONFIG, "password.sql"); + await start(CONFIG); await page.goto("/#/config"); - await login(page); await enableExperimental(page); }); diff --git a/tests/config-tariffs.spec.js b/tests/config-tariffs.spec.js index fa554a04ae..9d900497b2 100644 --- a/tests/config-tariffs.spec.js +++ b/tests/config-tariffs.spec.js @@ -1,6 +1,7 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; -import { enableExperimental, login } from "./utils"; +import { enableExperimental } from "./utils"; + const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; const CONFIG_WITH_TARIFFS = "config-with-tariffs.evcc.yaml"; @@ -15,13 +16,12 @@ const SELECT_ALL = "ControlOrMeta+KeyA"; async function goToConfig(page) { await page.goto("/#/config"); - await login(page); await enableExperimental(page); } test.describe("tariffs", async () => { test("tariffs not configured", async ({ page }) => { - await start(CONFIG_GRID_ONLY, "password.sql"); + await start(CONFIG_GRID_ONLY); await goToConfig(page); await expect(page.getByTestId("tariffs")).toBeVisible(); @@ -31,7 +31,7 @@ test.describe("tariffs", async () => { }); test("tariffs via ui", async ({ page }) => { - await start(CONFIG_GRID_ONLY, "password.sql"); + await start(CONFIG_GRID_ONLY); await goToConfig(page); await page.getByTestId("tariffs").getByRole("button", { name: "edit" }).click(); @@ -89,7 +89,7 @@ test.describe("tariffs", async () => { }); test("tariffs from evcc.yaml", async ({ page }) => { - await start(CONFIG_WITH_TARIFFS, "password.sql"); + await start(CONFIG_WITH_TARIFFS); await goToConfig(page); await expect(page.getByTestId("tariffs")).toBeVisible(); diff --git a/tests/config-vehicles.spec.js b/tests/config-vehicles.spec.js index d153f777f0..ada5c4ee43 100644 --- a/tests/config-vehicles.spec.js +++ b/tests/config-vehicles.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, restart, baseUrl } from "./evcc"; -import { enableExperimental, login } from "./utils"; +import { enableExperimental } from "./utils"; const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; const CONFIG_WITH_VEHICLE = "config-with-vehicle.evcc.yaml"; @@ -14,10 +14,9 @@ test.afterEach(async () => { test.describe("vehicles", async () => { test("create, edit and delete vehicles", async ({ page }) => { - await start(CONFIG_GRID_ONLY, "password.sql"); + await start(CONFIG_GRID_ONLY); await page.goto("/#/config"); - await login(page); await enableExperimental(page); await expect(page.getByTestId("vehicle")).toHaveCount(0); @@ -65,10 +64,9 @@ test.describe("vehicles", async () => { }); test("config should survive restart", async ({ page }) => { - await start(CONFIG_GRID_ONLY, "password.sql"); + await start(CONFIG_GRID_ONLY); await page.goto("/#/config"); - await login(page); await enableExperimental(page); await expect(page.getByTestId("vehicle")).toHaveCount(0); @@ -99,10 +97,9 @@ test.describe("vehicles", async () => { }); test("mixed config (yaml + db)", async ({ page }) => { - await start(CONFIG_WITH_VEHICLE, "password.sql"); + await start(CONFIG_WITH_VEHICLE); await page.goto("/#/config"); - await login(page); await enableExperimental(page); await expect(page.getByTestId("vehicle")).toHaveCount(1); @@ -120,10 +117,9 @@ test.describe("vehicles", async () => { }); test("advanced fields", async ({ page }) => { - await start(CONFIG_GRID_ONLY, "password.sql"); + await start(CONFIG_GRID_ONLY); await page.goto("/#/config"); - await login(page); await enableExperimental(page); await page.getByTestId("add-vehicle").click(); @@ -159,10 +155,9 @@ test.describe("vehicles", async () => { }); test("save and restore rfid identifiers", async ({ page }) => { - await start(CONFIG_GRID_ONLY, "password.sql"); + await start(CONFIG_GRID_ONLY); await page.goto("/#/config"); - await login(page); await enableExperimental(page); await page.getByTestId("add-vehicle").click(); diff --git a/tests/config.spec.js b/tests/config.spec.js index 08329a84eb..229c81edec 100644 --- a/tests/config.spec.js +++ b/tests/config.spec.js @@ -1,13 +1,13 @@ import { test, expect } from "@playwright/test"; import { start, stop, baseUrl } from "./evcc"; -import { enableExperimental, login } from "./utils"; +import { enableExperimental } from "./utils"; const CONFIG_GRID_ONLY = "config-grid-only.evcc.yaml"; test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { - await start(CONFIG_GRID_ONLY, "password.sql"); + await start(CONFIG_GRID_ONLY); }); test.afterAll(async () => { await stop(); @@ -18,12 +18,10 @@ test.describe("basics", async () => { await page.goto("/"); await page.getByTestId("topnavigation-button").click(); await page.getByRole("link", { name: "Configuration" }).click(); - await login(page); await expect(page.getByRole("heading", { name: "Configuration" })).toBeVisible(); }); test.skip("alert box should always be visible", async ({ page }) => { await page.goto("/#/config"); - await login(page); await enableExperimental(page); await expect(page.getByRole("alert")).toBeVisible(); }); @@ -37,7 +35,6 @@ test.describe("general", async () => { // change value in config await page.goto("/#/config"); - await login(page); await enableExperimental(page); await expect(page.getByTestId("generalconfig-title")).toContainText("Hello World"); diff --git a/tests/evcc.js b/tests/evcc.js index 686d7169a7..a9d4bf1cf2 100644 --- a/tests/evcc.js +++ b/tests/evcc.js @@ -42,7 +42,7 @@ function dbPath() { return path.join(os.tmpdir(), file); } -export async function start(config, sqlDumps, flags) { +export async function start(config, sqlDumps, flags = "--disable-auth") { await _clean(); if (sqlDumps) { await _restoreDatabase(sqlDumps); @@ -55,9 +55,9 @@ export async function stop(instance) { await _clean(); } -export async function restart(config) { +export async function restart(config, flags = "--disable-auth") { await _stop(); - await _start(config); + await _start(config, flags); } export async function cleanRestart(config, sqlDumps) { diff --git a/tests/heating.spec.js b/tests/heating.spec.js index d11df1968e..468b23d2e6 100644 --- a/tests/heating.spec.js +++ b/tests/heating.spec.js @@ -4,7 +4,7 @@ import { start, stop, baseUrl } from "./evcc"; test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { - await start("heating.evcc.yaml", "password.sql"); + await start("heating.evcc.yaml"); }); test.afterAll(async () => { await stop(); diff --git a/tests/limits.spec.js b/tests/limits.spec.js index 2aa058955e..6ddd512007 100644 --- a/tests/limits.spec.js +++ b/tests/limits.spec.js @@ -12,7 +12,7 @@ test.afterAll(async () => { }); test.beforeEach(async ({ page }) => { - await start(simulatorConfig(), "password.sql"); + await start(simulatorConfig()); await page.goto(simulatorUrl()); await page.getByLabel("Grid Power").fill("500"); diff --git a/tests/logs.spec.js b/tests/logs.spec.js index 3d21c0f6b2..b92af0cc6f 100644 --- a/tests/logs.spec.js +++ b/tests/logs.spec.js @@ -1,11 +1,10 @@ import { test, expect } from "@playwright/test"; import { start, stop, baseUrl } from "./evcc"; -import { login } from "./utils"; test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { - await start("basics.evcc.yaml", "password.sql"); + await start("basics.evcc.yaml"); }); test.afterAll(async () => { await stop(); @@ -16,7 +15,6 @@ test.describe("opening logs", async () => { await page.goto("/"); await page.getByTestId("topnavigation-button").click(); await page.getByRole("link", { name: "Configuration" }).click(); - await login(page); await page.getByRole("link", { name: "Logs" }).click(); await expect(page.getByRole("heading", { name: "Logs", exact: false })).toBeVisible(); }); @@ -25,7 +23,6 @@ test.describe("opening logs", async () => { await page.evaluate(() => window.app.raise({ message: "Fake Error" })); await page.getByTestId("notification-icon").click(); await page.getByRole("link", { name: "View full logs" }).click(); - await login(page); await expect(page.getByRole("heading", { name: "Logs", exact: false })).toBeVisible(); }); test("via need help", async ({ page }) => { @@ -33,7 +30,6 @@ test.describe("opening logs", async () => { await page.getByTestId("topnavigation-button").click(); await page.getByRole("button", { name: "Need Help?" }).click(); await page.getByRole("link", { name: "View logs" }).click(); - await login(page); await expect(page.getByRole("heading", { name: "Logs", exact: false })).toBeVisible(); }); }); @@ -41,7 +37,6 @@ test.describe("opening logs", async () => { test.describe("features", async () => { test("content", async ({ page }) => { await page.goto("/#/log"); - await login(page); await page.getByTestId("log-search").fill("listening at"); await expect(page.getByTestId("log-content")).toContainText("listening at"); }); diff --git a/tests/modals.spec.js b/tests/modals.spec.js index 7a7049e6e2..560a77e0e9 100644 --- a/tests/modals.spec.js +++ b/tests/modals.spec.js @@ -1,7 +1,6 @@ import { test, expect } from "@playwright/test"; import { start, stop, baseUrl } from "./evcc"; import { startSimulator, stopSimulator, simulatorConfig } from "./simulator"; -import { login } from "./utils"; const BASICS_CONFIG = "basics.evcc.yaml"; @@ -11,7 +10,7 @@ test.use({ baseURL: baseUrl() }); test.describe("Basics", async () => { test.beforeAll(async () => { - await start(BASICS_CONFIG, "password.sql"); + await start(BASICS_CONFIG); }); test.afterAll(async () => { @@ -21,9 +20,6 @@ test.describe("Basics", async () => { test("Menu options. No battery and grid.", async ({ page }) => { for (const route of UI_ROUTES) { await page.goto(route); - if (route === "/#/config") { - await login(page); - } await page.getByTestId("topnavigation-button").click(); await expect(page.getByRole("button", { name: "User Interface" })).toBeVisible(); @@ -53,7 +49,7 @@ test.describe("Basics", async () => { test.describe("Advanced", async () => { test.beforeAll(async () => { await startSimulator(); - await start(simulatorConfig(), "password.sql"); + await start(simulatorConfig()); }); test.afterAll(async () => { @@ -64,9 +60,6 @@ test.describe("Advanced", async () => { test("Menu options. All available.", async ({ page }) => { for (const route of UI_ROUTES) { await page.goto(route); - if (route === "/#/config") { - await login(page); - } await page.getByTestId("topnavigation-button").click(); await expect(page.getByRole("button", { name: "User Interface" })).toBeVisible(); diff --git a/tests/plan.spec.js b/tests/plan.spec.js index 36f8641b5c..c943c88e14 100644 --- a/tests/plan.spec.js +++ b/tests/plan.spec.js @@ -7,7 +7,7 @@ test.describe.configure({ mode: "parallel" }); const CONFIG = "plan.evcc.yaml"; test.beforeEach(async () => { - await start(CONFIG, "password.sql"); + await start(CONFIG); }); test.afterEach(async () => { diff --git a/tests/sessions.spec.js b/tests/sessions.spec.js index 12227ef69e..47daa41ec6 100644 --- a/tests/sessions.spec.js +++ b/tests/sessions.spec.js @@ -7,7 +7,7 @@ const mobile = devices["iPhone 12 Mini"].viewport; const desktop = devices["Desktop Chrome"].viewport; test.beforeAll(async () => { - await start("basics.evcc.yaml", ["password.sql", "sessions.sql"]); + await start("basics.evcc.yaml", "sessions.sql"); }); test.afterAll(async () => { await stop(); diff --git a/tests/smart-cost-only.spec.js b/tests/smart-cost-only.spec.js index bb890f70ce..06f8a5cc70 100644 --- a/tests/smart-cost-only.spec.js +++ b/tests/smart-cost-only.spec.js @@ -4,7 +4,7 @@ import { start, stop, baseUrl } from "./evcc"; test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { - await start("smart-cost-only.evcc.yaml", "password.sql"); + await start("smart-cost-only.evcc.yaml"); }); test.afterAll(async () => { await stop(); diff --git a/tests/smart-cost.spec.js b/tests/smart-cost.spec.js index d9110ef37e..264b8ef892 100644 --- a/tests/smart-cost.spec.js +++ b/tests/smart-cost.spec.js @@ -6,7 +6,7 @@ test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { await startSimulator(); - await start(simulatorConfig(), "password.sql"); + await start(simulatorConfig()); }); test.afterAll(async () => { await stop(); diff --git a/tests/statistics.spec.js b/tests/statistics.spec.js index a701e04234..a5c4400ea9 100644 --- a/tests/statistics.spec.js +++ b/tests/statistics.spec.js @@ -4,7 +4,7 @@ import { start, stop, baseUrl } from "./evcc"; test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { - await start("statistics.evcc.yaml", ["password.sql", "statistics.sql"]); + await start("statistics.evcc.yaml", "statistics.sql"); }); test.afterAll(async () => { await stop(); diff --git a/tests/utils.js b/tests/utils.js index 9a9fc2f09c..da3f4d8891 100644 --- a/tests/utils.js +++ b/tests/utils.js @@ -7,9 +7,3 @@ export async function enableExperimental(page) { await page.getByRole("button", { name: "Close" }).click(); await expect(page.locator(".modal-backdrop")).not.toBeVisible(); } - -export async function login(page) { - await page.locator("#loginPassword").fill("secret"); - await page.getByRole("button", { name: "Login" }).click(); - await expect(page.locator("#loginPassword")).not.toBeVisible(); -} diff --git a/tests/vehicle-error.spec.js b/tests/vehicle-error.spec.js index 205cdcf8bf..0db78eb00a 100644 --- a/tests/vehicle-error.spec.js +++ b/tests/vehicle-error.spec.js @@ -4,7 +4,7 @@ import { start, stop, baseUrl } from "./evcc"; test.use({ baseURL: baseUrl() }); test.beforeAll(async () => { - await start("vehicle-error.evcc.yaml", "password.sql"); + await start("vehicle-error.evcc.yaml"); }); test.afterAll(async () => { await stop(); diff --git a/tests/vehicle-settings.spec.js b/tests/vehicle-settings.spec.js index 86b8199fd8..9b514c6a1a 100644 --- a/tests/vehicle-settings.spec.js +++ b/tests/vehicle-settings.spec.js @@ -12,7 +12,7 @@ test.afterAll(async () => { }); test.beforeEach(async ({ page }) => { - await start(simulatorConfig(), "password.sql"); + await start(simulatorConfig()); await page.goto(simulatorUrl()); await page.getByLabel("Grid Power").fill("500"); From 039cbf5631bf70476e46eda8c66a557a8cb1a814 Mon Sep 17 00:00:00 2001 From: andig Date: Thu, 14 Nov 2024 17:42:57 +0100 Subject: [PATCH 38/58] MacOS Sequoia: fix network errors --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 50d1ec8d25..c744b029ad 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/evcc-io/evcc -go 1.23.0 +go 1.23.3 require ( dario.cat/mergo v1.0.1 From a9d9565e62c05842c097a983bf8901423fc4d55f Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 16 Nov 2024 13:38:59 +0100 Subject: [PATCH 39/58] Enphase: fix soc --- templates/definition/meter/enphase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/definition/meter/enphase.yaml b/templates/definition/meter/enphase.yaml index 12b497ad00..9f5730f72a 100644 --- a/templates/definition/meter/enphase.yaml +++ b/templates/definition/meter/enphase.yaml @@ -74,6 +74,6 @@ render: | password: {{ .token }} insecure: true {{- end }} - jq: .[].devices | map(.percentFull) | add / length + jq: [.[].devices[] | select(.percentFull != null) | .percentFull] | add / length capacity: {{ .capacity }} # kWh {{- end }} From 5419b521701487346fb8be69b9bffc8c88b4958c Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 16 Nov 2024 13:42:03 +0100 Subject: [PATCH 40/58] Revert "EM24: add pv usage & fix energy (#17173)" This reverts commit 964adbe7978adebf4cd459f4f6e177070e9cf47b. --- templates/definition/meter/cg-em24.yaml | 102 +++++------------------- 1 file changed, 20 insertions(+), 82 deletions(-) diff --git a/templates/definition/meter/cg-em24.yaml b/templates/definition/meter/cg-em24.yaml index c5d82bcc95..47616409ae 100644 --- a/templates/definition/meter/cg-em24.yaml +++ b/templates/definition/meter/cg-em24.yaml @@ -8,90 +8,28 @@ products: generic: EM24 params: - name: usage - choice: ["grid", "charge", "pv"] + choice: ["grid", "charge"] - name: modbus choice: ["rs485", "tcpip"] render: | - type: custom - power: - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 0x28 - type: input - decode: int32 - scale: {{ if eq .usage "pv" }}-{{ end }}0.1 - energy: - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: {{ if eq .usage "pv" }}0x5c{{ else }}0x3e{{ end }} - type: input - decode: int32 - scale: 0.1 + type: mbmd + {{- include "modbus" . }} + model: cgem24 + power: Power + energy: Import currents: - - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 0x0c - type: input - decode: uint32 - scale: 0.001 - - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 0x0e - type: input - decode: uint32 - scale: 0.001 - - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 0x10 - type: input - decode: uint32 - scale: 0.001 - voltages: - - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 0x0 - type: input - decode: uint32 - scale: 0.1 - - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 0x2 - type: input - decode: uint32 - scale: 0.1 - - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 0x4 - type: input - decode: uint32 - scale: 0.1 + - CurrentL1 + - CurrentL2 + - CurrentL3 + {{- if eq .usage "grid" }} powers: - - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 0x12 - type: input - decode: int32 - scale: {{ if eq .usage "pv" }}-{{ end }}0.1 - - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 0x14 - type: input - decode: int32 - scale: {{ if eq .usage "pv" }}-{{ end }}0.1 - - source: modbus - {{- include "modbus" . | indent 2 }} - register: - address: 0x16 - type: input - decode: int32 - scale: {{ if eq .usage "pv" }}-{{ end }}0.1 + - PowerL1 + - PowerL2 + - PowerL3 + {{- end }} + {{- if eq .usage "charge" }} + voltages: + - VoltageL1 + - VoltageL2 + - VoltageL3 + {{- end }} From 10dca60309a9752201a3c7d714e42143878f7be5 Mon Sep 17 00:00:00 2001 From: MobilettoSoft Date: Sat, 16 Nov 2024 13:46:02 +0100 Subject: [PATCH 41/58] PUN: update api endpoint (#17270) --- tariff/pun.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tariff/pun.go b/tariff/pun.go index 2d64e88be7..35edd0e55d 100644 --- a/tariff/pun.go +++ b/tariff/pun.go @@ -129,7 +129,7 @@ func (t *Pun) getData(day time.Time) (api.Rates, error) { client.Jar, _ = cookiejar.New(nil) // Erster Request - uri := "https://www.mercatoelettrico.org/It/WebServerDataStore/MGP_Prezzi/" + day.Format("20060102") + "MGPPrezzi.xml" + uri := "https://storico.mercatoelettrico.org/It/WebServerDataStore/MGP_Prezzi/" + day.Format("20060102") + "MGPPrezzi.xml" resp, err := client.Get(uri) if err != nil { return nil, err From 512aca56ed78fdeaee4e50c168dc354bcc4dad39 Mon Sep 17 00:00:00 2001 From: fanatix <43752712+djfanatix@users.noreply.github.com> Date: Sat, 16 Nov 2024 13:54:09 +0100 Subject: [PATCH 42/58] Add Tessie (#17274) --- templates/definition/vehicle/tessie.yaml | 111 +++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 templates/definition/vehicle/tessie.yaml diff --git a/templates/definition/vehicle/tessie.yaml b/templates/definition/vehicle/tessie.yaml new file mode 100644 index 0000000000..069ad5b226 --- /dev/null +++ b/templates/definition/vehicle/tessie.yaml @@ -0,0 +1,111 @@ +template: tessie +products: + - description: + generic: Tessie +group: generic +requirements: + description: + de: Verbinden Sie Ihr Tesla-Fahrzeug über die Tessie-API. Dies wird das Fahrzeug niemals aufwecken; das Polling kann auf „always“ und interval „1M“ eingestellt werden. Wenn das Fahrzeug wach ist, sind die Daten normalerweise weniger als 15 Sekunden alt. Wenn das Fahrzeug schläft, stammen die Daten aus dem Zeitpunkt, zu dem es eingeschlafen ist. Holen Sie sich Ihr Token unter https://dash.tessie.com/settings/api + en: Connect your Tesla using the Tessie API. This will never wake up the car, polling can be set to "always" and interval "1M". If the vehicle is awake, the data is usually less than 15 seconds old. If the vehicle is asleep, the data is from the time the vehicle went to sleep. Get your token at https://dash.tessie.com/settings/api +params: + - name: title + - name: vin + description: + de: Fahrzeug-VIN + en: Vehicle VIN + required: true + - name: token + description: + de: Tessie API Token + en: Tessie API Token + required: true + - name: capacity + - name: phases + advanced: true + - name: icon + default: car + advanced: true + - preset: vehicle-identify + +render: | + type: custom + {{- include "vehicle-common" . }} + {{- include "vehicle-identify" . }} + + soc: # battery state of charge (%) + source: http + uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true + headers: + Authorization: Bearer {{ .token }} + jq: .charge_state.usable_battery_level + + status: + source: combined + plugged: + source: http + uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true + headers: + Authorization: Bearer {{ .token }} + jq: .charge_state.charge_port_door_open + charging: + source: http + uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true + headers: + Authorization: Bearer {{ .token }} + jq: .charge_state.charging_state == "Charging" + + range: + source: http + uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true + headers: + Authorization: Bearer {{ .token }} + jq: .charge_state.battery_range * 1.60934 + + odometer: + source: http + uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true + headers: + Authorization: Bearer {{ .token }} + jq: .vehicle_state.odometer * 1.60934 + + climater: + source: http + uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true + headers: + Authorization: Bearer {{ .token }} + jq: .climate_state.is_climate_on + + limitsoc: + source: http + uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true + headers: + Authorization: Bearer {{ .token }} + jq: .charge_state.charge_limit_soc + + getMaxCurrent: + source: http + uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true + headers: + Authorization: Bearer {{ .token }} + jq: .charge_state.charge_current_request + + chargeEnable: + source: http + uri: https://api.tessie.com/{{ .vin }}/command/start_charging?retry_duration=40&wait_for_completion=true + headers: + Authorization: Bearer {{ .token }} + method: POST + + maxcurrent: + source: http + uri: https://api.tessie.com/{{ .vin }}/command/set_charging_amps?retry_duration=40&wait_for_completion=true&s=${maxcurrent} + headers: + Authorization: Bearer {{ .token }} + method: POST + + wakeup: + source: http + uri: https://api.tessie.com/{{ .vin }}/wake + headers: + Authorization: Bearer {{ .token }} + method: POST From ecc7279ea54044fb0f854723cb82e8df563cae84 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 16 Nov 2024 14:00:53 +0100 Subject: [PATCH 43/58] chore: fix quotes --- templates/definition/meter/enphase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/definition/meter/enphase.yaml b/templates/definition/meter/enphase.yaml index 9f5730f72a..f49da8019f 100644 --- a/templates/definition/meter/enphase.yaml +++ b/templates/definition/meter/enphase.yaml @@ -74,6 +74,6 @@ render: | password: {{ .token }} insecure: true {{- end }} - jq: [.[].devices[] | select(.percentFull != null) | .percentFull] | add / length + jq: '[.[].devices[] | select(.percentFull != null) | .percentFull] | add / length' capacity: {{ .capacity }} # kWh {{- end }} From 71905e31f1583a33c1ac2bad5655293aff00d906 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 16 Nov 2024 15:55:45 +0100 Subject: [PATCH 44/58] chore: fix line breaks --- templates/definition/vehicle/tessie.yaml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/templates/definition/vehicle/tessie.yaml b/templates/definition/vehicle/tessie.yaml index 069ad5b226..2a6f3c2bc3 100644 --- a/templates/definition/vehicle/tessie.yaml +++ b/templates/definition/vehicle/tessie.yaml @@ -26,19 +26,16 @@ params: default: car advanced: true - preset: vehicle-identify - render: | type: custom {{- include "vehicle-common" . }} {{- include "vehicle-identify" . }} - soc: # battery state of charge (%) source: http uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true headers: Authorization: Bearer {{ .token }} jq: .charge_state.usable_battery_level - status: source: combined plugged: @@ -53,56 +50,48 @@ render: | headers: Authorization: Bearer {{ .token }} jq: .charge_state.charging_state == "Charging" - range: source: http uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true headers: Authorization: Bearer {{ .token }} jq: .charge_state.battery_range * 1.60934 - odometer: source: http uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true headers: Authorization: Bearer {{ .token }} jq: .vehicle_state.odometer * 1.60934 - climater: source: http uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true headers: Authorization: Bearer {{ .token }} jq: .climate_state.is_climate_on - limitsoc: source: http uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true headers: Authorization: Bearer {{ .token }} jq: .charge_state.charge_limit_soc - getMaxCurrent: source: http uri: https://api.tessie.com/{{ .vin }}/state?use_cache=true headers: Authorization: Bearer {{ .token }} jq: .charge_state.charge_current_request - chargeEnable: source: http uri: https://api.tessie.com/{{ .vin }}/command/start_charging?retry_duration=40&wait_for_completion=true headers: Authorization: Bearer {{ .token }} method: POST - maxcurrent: source: http uri: https://api.tessie.com/{{ .vin }}/command/set_charging_amps?retry_duration=40&wait_for_completion=true&s=${maxcurrent} headers: Authorization: Bearer {{ .token }} method: POST - wakeup: source: http uri: https://api.tessie.com/{{ .vin }}/wake From 47af8935fa25cfebc2f942b38f89cbbb857eb52c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20L=C3=B6b?= <39953358+loebse@users.noreply.github.com> Date: Sat, 16 Nov 2024 16:12:06 +0100 Subject: [PATCH 45/58] Polestar: fix authentication (#17276) --- vehicle/polestar/identity.go | 54 ++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/vehicle/polestar/identity.go b/vehicle/polestar/identity.go index 53e6f87c77..9fb683e267 100644 --- a/vehicle/polestar/identity.go +++ b/vehicle/polestar/identity.go @@ -84,18 +84,30 @@ func (v *Identity) login() (*oauth2.Token, error) { } uri = fmt.Sprintf("%s/as/%s/resume/as/authorization.ping?client_id=%s", OAuthURI, resume, OAuth2Config.ClientID) - v.Client.CheckRedirect, param = request.InterceptRedirect("code", true) - defer func() { v.Client.CheckRedirect = nil }() var code string - if _, err = v.Post(uri, request.FormContent, strings.NewReader(params.Encode())); err == nil { - code, err = param() + var uid string + v.Client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + code = req.URL.Query().Get("code") + uid = req.URL.Query().Get("uid") + return nil } + defer func() { v.Client.CheckRedirect = nil }() - if err != nil { + if _, err := v.Post(uri, request.FormContent, strings.NewReader(params.Encode())); err != nil { return nil, err } + // If the authorization code is empty, this indicates that user consent must be handled + // before the code can be obtained. The `confirmConsentAndGetCode` method is called as a + // workaround to guide the user through the consent process and retrieve the authorization code. + if code == "" { + code, err = v.confirmConsentAndGetCode(resume, uid) + if err != nil { + return nil, err + } + } + var res struct { Token `graphql:"getAuthToken(code: $code)"` } @@ -137,3 +149,35 @@ func (v *Identity) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) { return v.login() } + +func (v *Identity) confirmConsentAndGetCode(resume, uid string) (string, error) { + // Extract the user ID (UID) from the redirect parameters + if uid == "" { + return "", fmt.Errorf("failed to extract user ID") + } + + // Confirm user consent by submitting the consent form, which rejects cookies + data := url.Values{ + "pf.submit": []string{"true"}, + "subject": []string{uid}, + } + + // Retrieve the authorization code after consent has been confirmed + var param request.InterceptResult + v.Client.CheckRedirect, param = request.InterceptRedirect("code", true) + defer func() { v.Client.CheckRedirect = nil }() + + // Make a POST request to confirm the user consent + if _, err := v.Post(fmt.Sprintf("%s/as/%s/resume/as/authorization.ping", OAuthURI, resume), request.FormContent, strings.NewReader(data.Encode())); err != nil { + return "", fmt.Errorf("failed confirming user consent: %w", err) + } + + // Extract the authorization code from the response + code, err := param() + if err != nil || code == "" { + return "", fmt.Errorf("failed extracting authorisation code: %w", err) + } + + // Return the retrieved code + return code, nil +} From 735d75ef74af82fcab2ce456f266425e9f4dde3d Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 16 Nov 2024 16:44:11 +0100 Subject: [PATCH 46/58] Polestar: skip test --- templates/definition/vehicle/polestar.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/definition/vehicle/polestar.yaml b/templates/definition/vehicle/polestar.yaml index 1d1d2d5182..d5cda5bdac 100644 --- a/templates/definition/vehicle/polestar.yaml +++ b/templates/definition/vehicle/polestar.yaml @@ -1,6 +1,8 @@ template: polestar products: - brand: Polestar +requirements: + evcc: ["skiptest"] params: - preset: vehicle-base - preset: vehicle-identify From 5c61d10ed7d1a0012e4b71be5c1efdb1cd77762e Mon Sep 17 00:00:00 2001 From: Carsten Schlipf Date: Mon, 18 Nov 2024 09:55:14 +0100 Subject: [PATCH 47/58] Sofar: fix docs (#17324) --- templates/definition/meter/sofarsolar-g3.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/definition/meter/sofarsolar-g3.yaml b/templates/definition/meter/sofarsolar-g3.yaml index 8084b2dd7d..a86f4d19f5 100644 --- a/templates/definition/meter/sofarsolar-g3.yaml +++ b/templates/definition/meter/sofarsolar-g3.yaml @@ -15,8 +15,8 @@ products: # capabilities: ["battery-control"] requirements: description: - de: Die Verbindung über einen LSE-3 Logger Stick mittels ModBus TCP ist möglich, jedoch kann Battery Control darüber nicht genutzt werden. Der LSW-3 WLAN Stick wird nicht unterstützt. Bei seriellem Anschluss via RS485 am COM Port ist eine wechselrichterseitige Terminierung notwendig. - en: Connection via LSE-3 logger stick using ModBus TCP is possible, however does not allow Battery Control. The LSW-3 WiFi stick is not supported. For RS485 serial connection using the inverter's COM port the inverter's side must be properly terminated. + de: Die Verbindung über einen LSE-3 Logger Stick mittels LAN Anschluss und ModBus TCP über Port 8899 ist die einfachste Anbindung. Der LSW-3 WLAN Stick wird nicht unterstützt. Bei seriellem Anschluss via RS485 am COM Port ist eine wechselrichterseitige Terminierung notwendig. + en: LSE-3 logger stick using a LAN connection and ModBus TCP via the port 8899 is the easiest connection. The LSW-3 WiFi stick is not supported. For a RS485 serial connection using the inverter's COM port the inverter's side must be properly terminated. capabilities: ["battery-control"] params: - name: usage From 77bb113cfeccabf1268ee94d687396cf92445cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Mon, 18 Nov 2024 09:56:26 +0100 Subject: [PATCH 48/58] Script: add missing string setter (#17314) --- provider/script.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/provider/script.go b/provider/script.go index 7ed25cb63f..e7a30425b8 100644 --- a/provider/script.go +++ b/provider/script.go @@ -161,3 +161,20 @@ func (p *Script) BoolSetter(param string) (func(bool) error, error) { return err }, nil } + +var _ SetStringProvider = (*Script)(nil) + +// StringSetter returns a function that invokes a script with parameter by a string value +func (p *Script) StringSetter(param string) (func(string) error, error) { + return func(v string) error { + cmd, err := util.ReplaceFormatted(p.script, map[string]interface{}{ + param: v, + }) + + if err == nil { + _, err = p.exec(cmd) + } + + return err + }, nil +} From 8a6b5d74a5f4ab5084d5d690fd4f25225a05a072 Mon Sep 17 00:00:00 2001 From: andig Date: Mon, 18 Nov 2024 09:57:19 +0100 Subject: [PATCH 49/58] Push: add custom messenger (BC) (#17211) --- push/push.go | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++ push/script.go | 85 ---------------------------------------------- 2 files changed, 91 insertions(+), 85 deletions(-) create mode 100644 push/push.go delete mode 100644 push/script.go diff --git a/push/push.go b/push/push.go new file mode 100644 index 0000000000..f3dc810512 --- /dev/null +++ b/push/push.go @@ -0,0 +1,91 @@ +package push + +import ( + "bytes" + "context" + "encoding/csv" + "encoding/json" + "strings" + + "github.com/evcc-io/evcc/api" + "github.com/evcc-io/evcc/provider" + "github.com/evcc-io/evcc/util" +) + +func init() { + registry.AddCtx(api.Custom, NewConfigurableFromConfig) +} + +// NewConfigurableFromConfig creates Messenger from config +func NewConfigurableFromConfig(ctx context.Context, other map[string]interface{}) (Messenger, error) { + var cc struct { + Send provider.Config + Encoding string + } + + if err := util.DecodeOther(other, &cc); err != nil { + return nil, err + } + + send, err := provider.NewStringSetterFromConfig(ctx, "send", cc.Send) + if err != nil { + return nil, err + } + + return NewConfigurable(send, cc.Encoding) +} + +// NewConfigurable creates a new Messenger +func NewConfigurable(send func(string) error, encoding string) (*Push, error) { + m := &Push{ + log: util.NewLogger("push"), + send: send, + encoding: strings.ToLower(encoding), + } + return m, nil +} + +// Push is a configurable Messenger implementation +type Push struct { + log *util.Logger + send func(string) error + encoding string +} + +func (m *Push) csv(separator rune, title, msg string) string { + var b bytes.Buffer + ww := csv.NewWriter(&b) + ww.Comma = separator + _ = ww.Write([]string{title, msg}) + ww.Flush() + return b.String() +} + +// Send implements the Messenger interface +func (m *Push) Send(title, msg string) { + var res string + + switch m.encoding { + case "json": + b, _ := json.Marshal(struct { + Title string `json:"title,omitempty"` + Msg string `json:"msg"` + }{ + Title: title, + Msg: msg, + }) + res = string(b) + case "csv": + res = m.csv(',', title, msg) + case "tsv": + res = m.csv('\t', title, msg) + case "title": + res = title + default: + res = msg + } + + if err := m.send(res); err != nil { + m.log.ERROR.Printf("send: %v", err) + } +} diff --git a/push/script.go b/push/script.go deleted file mode 100644 index 367aafe507..0000000000 --- a/push/script.go +++ /dev/null @@ -1,85 +0,0 @@ -package push - -import ( - "context" - "errors" - "os/exec" - "strings" - "time" - - "github.com/evcc-io/evcc/util" - "github.com/evcc-io/evcc/util/request" - "github.com/kballard/go-shellquote" -) - -func init() { - registry.Add("script", NewScriptFromConfig) -} - -// Script implements shell script-based message service and setters -type Script struct { - log *util.Logger - script string - timeout time.Duration -} - -// NewScriptFromConfig creates a Script messenger. Script execution is aborted after given timeout. -func NewScriptFromConfig(other map[string]interface{}) (Messenger, error) { - cc := struct { - CmdLine string - Timeout time.Duration - }{ - Timeout: request.Timeout, - } - - if err := util.DecodeOther(other, &cc); err != nil { - return nil, err - } - - s := &Script{ - log: util.NewLogger("script"), - script: cc.CmdLine, - timeout: cc.Timeout, - } - - return s, nil -} - -// Send calls the script -func (m *Script) Send(title, msg string) { - _, err := m.exec(m.script, title, msg) - if err != nil { - m.log.ERROR.Printf("exec: %v", err) - } -} - -func (m *Script) exec(script, title, msg string) (string, error) { - args, err := shellquote.Split(script) - if err != nil { - return "", err - } - - ctx, cancel := context.WithTimeout(context.Background(), m.timeout) - defer cancel() - - args = append(args, title, msg) - cmd := exec.CommandContext(ctx, args[0], args[1:]...) - b, err := cmd.Output() - - s := strings.TrimSpace(string(b)) - - if err != nil { - // use STDOUT if available - var ee *exec.ExitError - if errors.As(err, &ee) { - s = strings.TrimSpace(string(ee.Stderr)) - } - - m.log.ERROR.Printf("%s: %s", strings.Join(args, " "), s) - return "", err - } - - m.log.DEBUG.Printf("%s: %s", strings.Join(args, " "), s) - - return s, nil -} From 1b61e2730406e25abe2779a4fd14c4e61d2da685 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Mon, 18 Nov 2024 09:57:44 +0100 Subject: [PATCH 50/58] Tariffs: formula, charges, tax > advanced fields (#17301) --- util/templates/defaults.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/templates/defaults.yaml b/util/templates/defaults.yaml index cbbfeadf14..b3a6177981 100644 --- a/util/templates/defaults.yaml +++ b/util/templates/defaults.yaml @@ -333,16 +333,19 @@ presets: params: - name: charges type: number + advanced: true help: de: Zusätzlicher fester Aufschlag pro kWh (z.B. 0.05 für 5 Cent) en: Additional fixed charge per kWh (e.g. 0.05 for 5 cents) - name: tax type: number + advanced: true help: de: Zusätzlicher prozentualer Aufschlag (z.B. 0.2 für 20%) en: Additional percentage charge (e.g. 0.2 for 20%) - name: formula type: string + advanced: true help: de: Individuelle Formel zur Berechnung des Preises en: Individual formula for calculating the price From 695f49af4f706f77bb2c21d56efa8967b6bf6241 Mon Sep 17 00:00:00 2001 From: andig Date: Mon, 18 Nov 2024 18:26:36 +0100 Subject: [PATCH 51/58] Script: simplify setters --- provider/script.go | 42 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/provider/script.go b/provider/script.go index e7a30425b8..0a9f8355b3 100644 --- a/provider/script.go +++ b/provider/script.go @@ -126,14 +126,10 @@ func (p *Script) StringGetter() (func() (string, error), error) { }, nil } -var _ SetIntProvider = (*Script)(nil) - -// IntSetter invokes script with parameter replaced by int value -func (p *Script) IntSetter(param string) (func(int64) error, error) { - // return func to access cached value - return func(i int64) error { +func scriptSetter[T any](p *Script, param string) (func(T) error, error) { + return func(val T) error { cmd, err := util.ReplaceFormatted(p.script, map[string]interface{}{ - param: i, + param: val, }) if err == nil { @@ -144,37 +140,23 @@ func (p *Script) IntSetter(param string) (func(int64) error, error) { }, nil } +var _ SetIntProvider = (*Script)(nil) + +// IntSetter invokes script with parameter replaced by int value +func (p *Script) IntSetter(param string) (func(int64) error, error) { + return scriptSetter[int64](p, param) +} + var _ SetBoolProvider = (*Script)(nil) // BoolSetter invokes script with parameter replaced by bool value func (p *Script) BoolSetter(param string) (func(bool) error, error) { - // return func to access cached value - return func(b bool) error { - cmd, err := util.ReplaceFormatted(p.script, map[string]interface{}{ - param: b, - }) - - if err == nil { - _, err = p.exec(cmd) - } - - return err - }, nil + return scriptSetter[bool](p, param) } var _ SetStringProvider = (*Script)(nil) // StringSetter returns a function that invokes a script with parameter by a string value func (p *Script) StringSetter(param string) (func(string) error, error) { - return func(v string) error { - cmd, err := util.ReplaceFormatted(p.script, map[string]interface{}{ - param: v, - }) - - if err == nil { - _, err = p.exec(cmd) - } - - return err - }, nil + return scriptSetter[string](p, param) } From b8b7135028298d03e2f267a1688b2abba8e7c3a9 Mon Sep 17 00:00:00 2001 From: andig Date: Mon, 18 Nov 2024 18:44:03 +0100 Subject: [PATCH 52/58] MacOS: add gobuildid --- .goreleaser.yml | 4 ++++ Makefile | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 3ae3440ee9..ead2f893de 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -32,6 +32,10 @@ builds: goarch: arm - goos: windows goarch: arm64 + overrides: + - goos: darwin + ldflags: + - "-B gobuildid" env: - CGO_ENABLED=0 diff --git a/Makefile b/Makefile index 28233cd953..832337dd0f 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,7 @@ build:: CGO_ENABLED=0 go build -v $(BUILD_TAGS) $(BUILD_ARGS) snapshot:: - goreleaser --snapshot --skip-publish --clean + goreleaser --snapshot --skip publish --clean release:: goreleaser --clean From 3148c4fcf21c00408b188aceea662cafc78274ce Mon Sep 17 00:00:00 2001 From: andig Date: Mon, 18 Nov 2024 18:51:53 +0100 Subject: [PATCH 53/58] chore: refactor --- meter/zendure.go | 3 +-- meter/zendure/connection.go | 6 +++--- meter/zendure/credentials.go | 10 +++++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/meter/zendure.go b/meter/zendure.go index fd7476effd..222dbdc7c5 100644 --- a/meter/zendure.go +++ b/meter/zendure.go @@ -33,8 +33,7 @@ func NewZendureFromConfig(other map[string]interface{}) (api.Meter, error) { return nil, err } - global := strings.ToUpper(cc.Region) != "EU" - conn, err := zendure.NewConnection(cc.Account, cc.Serial, global, cc.Timeout) + conn, err := zendure.NewConnection(strings.ToUpper(cc.Region), cc.Account, cc.Serial, cc.Timeout) if err != nil { return nil, err } diff --git a/meter/zendure/connection.go b/meter/zendure/connection.go index 47c447a080..8dce525d9d 100644 --- a/meter/zendure/connection.go +++ b/meter/zendure/connection.go @@ -22,7 +22,7 @@ type Connection struct { data *util.Monitor[Data] } -func NewConnection(account, serial string, global bool, timeout time.Duration) (*Connection, error) { +func NewConnection(region, account, serial string, timeout time.Duration) (*Connection, error) { mu.Lock() defer mu.Unlock() @@ -31,12 +31,12 @@ func NewConnection(account, serial string, global bool, timeout time.Duration) ( return conn, nil } - res, err := MqttCredentials(account, serial, global) + log := util.NewLogger("zendure") + res, err := MqttCredentials(log, region, account, serial) if err != nil { return nil, err } - log := util.NewLogger("zendure") client, err := mqtt.NewClient( log, net.JoinHostPort(res.Data.MqttUrl, strconv.Itoa(res.Data.Port)), res.Data.AppKey, res.Data.Secret, diff --git a/meter/zendure/credentials.go b/meter/zendure/credentials.go index 5c1ff21dd0..a02f6a882a 100644 --- a/meter/zendure/credentials.go +++ b/meter/zendure/credentials.go @@ -13,17 +13,17 @@ const ( GlobalCredentialsUri = "https://app.zendure.tech/v2/developer/api/apply" ) -func MqttCredentials(account, serial string, global bool) (CredentialsResponse, error) { - client := request.NewHelper(util.NewLogger("zendure")) +func MqttCredentials(log *util.Logger, region, account, serial string) (CredentialsResponse, error) { + client := request.NewHelper(log) data := CredentialsRequest{ SnNumber: serial, Account: account, } - uri := EUCredentialsUri - if global { - uri = GlobalCredentialsUri + uri := GlobalCredentialsUri + if region == "EU" { + uri = EUCredentialsUri } req, _ := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding) From c44c598e21c58c7eadafe1c6c6f1b81210d582b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20He=C3=9F?= Date: Tue, 19 Nov 2024 08:52:11 +0100 Subject: [PATCH 54/58] Easee: fix PhaseGetter returning used, not configured, phases (#17326) --- charger/easee.go | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/charger/easee.go b/charger/easee.go index 2d4ffb4c9f..ab5c519ba0 100644 --- a/charger/easee.go +++ b/charger/easee.go @@ -52,6 +52,7 @@ type Easee struct { lastEnergyPollMux sync.Mutex maxChargerCurrent float64 dynamicChargerCurrent float64 + dynamicCircuitCurrent [3]float64 current float64 chargerEnabled bool smartCharging bool @@ -61,7 +62,6 @@ type Easee struct { pilotMode string reasonForNoCurrent int phaseMode int - outputPhase int sessionStartEnergy *float64 currentPower, sessionEnergy, totalEnergy, currentL1, currentL2, currentL3 float64 @@ -313,8 +313,12 @@ func (c *Easee) ProductUpdate(i json.RawMessage) { c.currentL3 = value.(float64) case easee.PHASE_MODE: c.phaseMode = value.(int) - case easee.OUTPUT_PHASE: - c.outputPhase = value.(int) / 10 // API gives 0,10,30 for 0,1,3p + case easee.DYNAMIC_CIRCUIT_CURRENT_P1: + c.dynamicCircuitCurrent[0] = value.(float64) + case easee.DYNAMIC_CIRCUIT_CURRENT_P2: + c.dynamicCircuitCurrent[1] = value.(float64) + case easee.DYNAMIC_CIRCUIT_CURRENT_P3: + c.dynamicCircuitCurrent[2] = value.(float64) case easee.MAX_CHARGER_CURRENT: c.maxChargerCurrent = value.(float64) case easee.DYNAMIC_CHARGER_CURRENT: @@ -814,7 +818,22 @@ var _ api.PhaseGetter = (*Easee)(nil) func (c *Easee) GetPhases() (int, error) { c.mux.RLock() defer c.mux.RUnlock() - return c.outputPhase, nil + var phases int + if c.circuit != 0 { + // circuit level controlled charger + for _, dcc := range c.dynamicCircuitCurrent { + if dcc > 0 { + phases++ + } + } + } else { + // charger level + phases = c.phaseMode + if phases == 2 { // map automatic to 3p + phases = 3 + } + } + return phases, nil } var _ api.Identifier = (*Easee)(nil) From 1f2d2ceec3a74c39642eb199ff7767294bc2ae59 Mon Sep 17 00:00:00 2001 From: andig Date: Tue, 19 Nov 2024 09:02:56 +0100 Subject: [PATCH 55/58] chore: fix template --- templates/definition/meter/zendure.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/definition/meter/zendure.yaml b/templates/definition/meter/zendure.yaml index 553c7381ed..5f53f2dcfe 100644 --- a/templates/definition/meter/zendure.yaml +++ b/templates/definition/meter/zendure.yaml @@ -28,6 +28,7 @@ params: render: | type: zendure usage: {{ .usage }} + region: {{ .region }} account: {{ .account }} serial: {{ .serial }} timeout: {{ .timeout }} From 9083a846ac3f5761b0ff78b3b308ac2f5bbc5e9d Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Tue, 19 Nov 2024 17:47:29 +0100 Subject: [PATCH 56/58] chore: upgrade npm dependencies (#17344) --- package-lock.json | 615 ++++++++++++++++++++++++---------------------- 1 file changed, 319 insertions(+), 296 deletions(-) diff --git a/package-lock.json b/package-lock.json index f2bed5d7e8..ebbecd6300 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1604,9 +1604,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.34.2", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.2.tgz", - "integrity": "sha512-d6n0WFvL970A9Z+l9N2dO+Hk9ev4hDYQzIx+B9tCyBP0W5wPEszi1rhuyFesNSkLZzXbQE5FPH7F/z/TMJfoPA==", + "version": "6.34.3", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.34.3.tgz", + "integrity": "sha512-Ph5d+u8DxIeSgssXEakaakImkzBV4+slwIbcxl9oc9evexJhImeu/G8TK7+zp+IFK9KuJ0BdSn6kTBJeH2CHvA==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.4.0", @@ -2010,9 +2010,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.4", @@ -2024,18 +2024,18 @@ } }, "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", + "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "license": "MIT", "dependencies": { "ajv": "^6.12.4", @@ -2068,9 +2068,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", - "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", + "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2086,9 +2086,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.2.tgz", - "integrity": "sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", "license": "Apache-2.0", "dependencies": { "levn": "^0.4.1" @@ -2535,12 +2535,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.48.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.2.tgz", - "integrity": "sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw==", + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.0.tgz", + "integrity": "sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw==", "license": "Apache-2.0", "dependencies": { - "playwright": "1.48.2" + "playwright": "1.49.0" }, "bin": { "playwright": "cli.js" @@ -2600,9 +2600,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.25.0.tgz", - "integrity": "sha512-CC/ZqFZwlAIbU1wUPisHyV/XRc5RydFrNLtgl3dGYskdwPZdt4HERtKm50a/+DtTlKeCq9IXFEWR+P6blwjqBA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.3.tgz", + "integrity": "sha512-EzxVSkIvCFxUd4Mgm4xR9YXrcp976qVaHnqom/Tgm+vU79k4vV4eYTjmRvGfeoW8m9LVcsAy/lGjcgVegKEhLQ==", "cpu": [ "arm" ], @@ -2613,9 +2613,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.25.0.tgz", - "integrity": "sha512-/Y76tmLGUJqVBXXCfVS8Q8FJqYGhgH4wl4qTA24E9v/IJM0XvJCGQVSW1QZ4J+VURO9h8YCa28sTFacZXwK7Rg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.3.tgz", + "integrity": "sha512-LJc5pDf1wjlt9o/Giaw9Ofl+k/vLUaYsE2zeQGH85giX2F+wn/Cg8b3c5CDP3qmVmeO5NzwVUzQQxwZvC2eQKw==", "cpu": [ "arm64" ], @@ -2626,9 +2626,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.25.0.tgz", - "integrity": "sha512-YVT6L3UrKTlC0FpCZd0MGA7NVdp7YNaEqkENbWQ7AOVOqd/7VzyHpgIpc1mIaxRAo1ZsJRH45fq8j4N63I/vvg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.3.tgz", + "integrity": "sha512-OuRysZ1Mt7wpWJ+aYKblVbJWtVn3Cy52h8nLuNSzTqSesYw1EuN6wKp5NW/4eSre3mp12gqFRXOKTcN3AI3LqA==", "cpu": [ "arm64" ], @@ -2639,9 +2639,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.25.0.tgz", - "integrity": "sha512-ZRL+gexs3+ZmmWmGKEU43Bdn67kWnMeWXLFhcVv5Un8FQcx38yulHBA7XR2+KQdYIOtD0yZDWBCudmfj6lQJoA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.3.tgz", + "integrity": "sha512-xW//zjJMlJs2sOrCmXdB4d0uiilZsOdlGQIC/jjmMWT47lkLLoB1nsNhPUcnoqyi5YR6I4h+FjBpILxbEy8JRg==", "cpu": [ "x64" ], @@ -2652,9 +2652,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.25.0.tgz", - "integrity": "sha512-xpEIXhiP27EAylEpreCozozsxWQ2TJbOLSivGfXhU4G1TBVEYtUPi2pOZBnvGXHyOdLAUUhPnJzH3ah5cqF01g==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.3.tgz", + "integrity": "sha512-58E0tIcwZ+12nK1WiLzHOD8I0d0kdrY/+o7yFVPRHuVGY3twBwzwDdTIBGRxLmyjciMYl1B/U515GJy+yn46qw==", "cpu": [ "arm64" ], @@ -2665,9 +2665,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.25.0.tgz", - "integrity": "sha512-sC5FsmZGlJv5dOcURrsnIK7ngc3Kirnx3as2XU9uER+zjfyqIjdcMVgzy4cOawhsssqzoAX19qmxgJ8a14Qrqw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.3.tgz", + "integrity": "sha512-78fohrpcVwTLxg1ZzBMlwEimoAJmY6B+5TsyAZ3Vok7YabRBUvjYTsRXPTjGEvv/mfgVBepbW28OlMEz4w8wGA==", "cpu": [ "x64" ], @@ -2678,9 +2678,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.25.0.tgz", - "integrity": "sha512-uD/dbLSs1BEPzg564TpRAQ/YvTnCds2XxyOndAO8nJhaQcqQGFgv/DAVko/ZHap3boCvxnzYMa3mTkV/B/3SWA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.3.tgz", + "integrity": "sha512-h2Ay79YFXyQi+QZKo3ISZDyKaVD7uUvukEHTOft7kh00WF9mxAaxZsNs3o/eukbeKuH35jBvQqrT61fzKfAB/Q==", "cpu": [ "arm" ], @@ -2691,9 +2691,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.25.0.tgz", - "integrity": "sha512-ZVt/XkrDlQWegDWrwyC3l0OfAF7yeJUF4fq5RMS07YM72BlSfn2fQQ6lPyBNjt+YbczMguPiJoCfaQC2dnflpQ==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.3.tgz", + "integrity": "sha512-Sv2GWmrJfRY57urktVLQ0VKZjNZGogVtASAgosDZ1aUB+ykPxSi3X1nWORL5Jk0sTIIwQiPH7iE3BMi9zGWfkg==", "cpu": [ "arm" ], @@ -2704,9 +2704,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.25.0.tgz", - "integrity": "sha512-qboZ+T0gHAW2kkSDPHxu7quaFaaBlynODXpBVnPxUgvWYaE84xgCKAPEYE+fSMd3Zv5PyFZR+L0tCdYCMAtG0A==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.3.tgz", + "integrity": "sha512-FPoJBLsPW2bDNWjSrwNuTPUt30VnfM8GPGRoLCYKZpPx0xiIEdFip3dH6CqgoT0RnoGXptaNziM0WlKgBc+OWQ==", "cpu": [ "arm64" ], @@ -2717,9 +2717,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.25.0.tgz", - "integrity": "sha512-ndWTSEmAaKr88dBuogGH2NZaxe7u2rDoArsejNslugHZ+r44NfWiwjzizVS1nUOHo+n1Z6qV3X60rqE/HlISgw==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.3.tgz", + "integrity": "sha512-TKxiOvBorYq4sUpA0JT+Fkh+l+G9DScnG5Dqx7wiiqVMiRSkzTclP35pE6eQQYjP4Gc8yEkJGea6rz4qyWhp3g==", "cpu": [ "arm64" ], @@ -2730,9 +2730,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.25.0.tgz", - "integrity": "sha512-BVSQvVa2v5hKwJSy6X7W1fjDex6yZnNKy3Kx1JGimccHft6HV0THTwNtC2zawtNXKUu+S5CjXslilYdKBAadzA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.3.tgz", + "integrity": "sha512-v2M/mPvVUKVOKITa0oCFksnQQ/TqGrT+yD0184/cWHIu0LoIuYHwox0Pm3ccXEz8cEQDLk6FPKd1CCm+PlsISw==", "cpu": [ "ppc64" ], @@ -2743,9 +2743,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.25.0.tgz", - "integrity": "sha512-G4hTREQrIdeV0PE2JruzI+vXdRnaK1pg64hemHq2v5fhv8C7WjVaeXc9P5i4Q5UC06d/L+zA0mszYIKl+wY8oA==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.3.tgz", + "integrity": "sha512-LdrI4Yocb1a/tFVkzmOE5WyYRgEBOyEhWYJe4gsDWDiwnjYKjNs7PS6SGlTDB7maOHF4kxevsuNBl2iOcj3b4A==", "cpu": [ "riscv64" ], @@ -2756,9 +2756,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.25.0.tgz", - "integrity": "sha512-9T/w0kQ+upxdkFL9zPVB6zy9vWW1deA3g8IauJxojN4bnz5FwSsUAD034KpXIVX5j5p/rn6XqumBMxfRkcHapQ==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.3.tgz", + "integrity": "sha512-d4wVu6SXij/jyiwPvI6C4KxdGzuZOvJ6y9VfrcleHTwo68fl8vZC5ZYHsCVPUi4tndCfMlFniWgwonQ5CUpQcA==", "cpu": [ "s390x" ], @@ -2769,9 +2769,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.25.0.tgz", - "integrity": "sha512-ThcnU0EcMDn+J4B9LD++OgBYxZusuA7iemIIiz5yzEcFg04VZFzdFjuwPdlURmYPZw+fgVrFzj4CA64jSTG4Ig==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.3.tgz", + "integrity": "sha512-/6bn6pp1fsCGEY5n3yajmzZQAh+mW4QPItbiWxs69zskBzJuheb3tNynEjL+mKOsUSFK11X4LYF2BwwXnzWleA==", "cpu": [ "x64" ], @@ -2782,9 +2782,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.25.0.tgz", - "integrity": "sha512-zx71aY2oQxGxAT1JShfhNG79PnjYhMC6voAjzpu/xmMjDnKNf6Nl/xv7YaB/9SIa9jDYf8RBPWEnjcdlhlv1rQ==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.3.tgz", + "integrity": "sha512-nBXOfJds8OzUT1qUreT/en3eyOXd2EH5b0wr2bVB5999qHdGKkzGzIyKYaKj02lXk6wpN71ltLIaQpu58YFBoQ==", "cpu": [ "x64" ], @@ -2795,9 +2795,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.25.0.tgz", - "integrity": "sha512-JT8tcjNocMs4CylWY/CxVLnv8e1lE7ff1fi6kbGocWwxDq9pj30IJ28Peb+Y8yiPNSF28oad42ApJB8oUkwGww==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.3.tgz", + "integrity": "sha512-ogfbEVQgIZOz5WPWXF2HVb6En+kWzScuxJo/WdQTqEgeyGkaa2ui5sQav9Zkr7bnNCLK48uxmmK0TySm22eiuw==", "cpu": [ "arm64" ], @@ -2808,9 +2808,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.25.0.tgz", - "integrity": "sha512-dRLjLsO3dNOfSN6tjyVlG+Msm4IiZnGkuZ7G5NmpzwF9oOc582FZG05+UdfTbz5Jd4buK/wMb6UeHFhG18+OEg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.3.tgz", + "integrity": "sha512-ecE36ZBMLINqiTtSNQ1vzWc5pXLQHlf/oqGp/bSbi7iedcjcNb6QbCBNG73Euyy2C+l/fn8qKWEwxr+0SSfs3w==", "cpu": [ "ia32" ], @@ -2821,9 +2821,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.25.0.tgz", - "integrity": "sha512-/RqrIFtLB926frMhZD0a5oDa4eFIbyNEwLLloMTEjmqfwZWXywwVVOVmwTsuyhC9HKkVEZcOOi+KV4U9wmOdlg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.3.tgz", + "integrity": "sha512-vliZLrDmYKyaUoMzEbMTg2JkerfBjn03KmAw9CykO0Zzkzoyd7o3iZNam/TpyWNjNT+Cz2iO3P9Smv2wgrR+Eg==", "cpu": [ "x64" ], @@ -2949,16 +2949,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz", - "integrity": "sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz", + "integrity": "sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==", "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/type-utils": "8.14.0", - "@typescript-eslint/utils": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/type-utils": "8.15.0", + "@typescript-eslint/utils": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -2982,15 +2982,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.14.0.tgz", - "integrity": "sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz", + "integrity": "sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==", "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/typescript-estree": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/typescript-estree": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", "debug": "^4.3.4" }, "engines": { @@ -3010,13 +3010,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.14.0.tgz", - "integrity": "sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz", + "integrity": "sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0" + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3027,13 +3027,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.14.0.tgz", - "integrity": "sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz", + "integrity": "sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==", "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.14.0", - "@typescript-eslint/utils": "8.14.0", + "@typescript-eslint/typescript-estree": "8.15.0", + "@typescript-eslint/utils": "8.15.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -3044,6 +3044,9 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -3051,9 +3054,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.14.0.tgz", - "integrity": "sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.15.0.tgz", + "integrity": "sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3064,13 +3067,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.14.0.tgz", - "integrity": "sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz", + "integrity": "sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==", "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/visitor-keys": "8.14.0", + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/visitor-keys": "8.15.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -3128,15 +3131,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.14.0.tgz", - "integrity": "sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.15.0.tgz", + "integrity": "sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.14.0", - "@typescript-eslint/types": "8.14.0", - "@typescript-eslint/typescript-estree": "8.14.0" + "@typescript-eslint/scope-manager": "8.15.0", + "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/typescript-estree": "8.15.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3147,16 +3150,21 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.14.0.tgz", - "integrity": "sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz", + "integrity": "sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.14.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.15.0", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3166,6 +3174,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@unhead/dom": { "version": "1.11.11", "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.11.11.tgz", @@ -3250,9 +3270,9 @@ } }, "node_modules/@vitejs/plugin-vue": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.5.tgz", - "integrity": "sha512-dlnib73G05CDBAUR/YpuZcQQ47fpjihnnNouAAqN62z+oqSsWJ+kh52GRzIxpkgFG3q11eXK7Di7RMmoCwISZA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.0.tgz", + "integrity": "sha512-7n7KdUEtx/7Yl7I/WVAMZ1bEb0eVvXF3ummWTeLcs/9gvo9pJhuLdouSXGjdZ/MKD1acf1I272+X0RMua4/R3g==", "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" @@ -3263,13 +3283,13 @@ } }, "node_modules/@vitest/expect": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.4.tgz", - "integrity": "sha512-DOETT0Oh1avie/D/o2sgMHGrzYUFFo3zqESB2Hn70z6QB1HrS2IQ9z5DfyTqU8sg4Bpu13zZe9V4+UTNQlUeQA==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.5.tgz", + "integrity": "sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==", "license": "MIT", "dependencies": { - "@vitest/spy": "2.1.4", - "@vitest/utils": "2.1.4", + "@vitest/spy": "2.1.5", + "@vitest/utils": "2.1.5", "chai": "^5.1.2", "tinyrainbow": "^1.2.0" }, @@ -3278,12 +3298,12 @@ } }, "node_modules/@vitest/mocker": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.4.tgz", - "integrity": "sha512-Ky/O1Lc0QBbutJdW0rqLeFNbuLEyS+mIPiNdlVlp2/yhJ0SbyYqObS5IHdhferJud8MbbwMnexg4jordE5cCoQ==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.5.tgz", + "integrity": "sha512-XYW6l3UuBmitWqSUXTNXcVBUCRytDogBsWuNXQijc00dtnU/9OqpXWp4OJroVrad/gLIomAq9aW8yWDBtMthhQ==", "license": "MIT", "dependencies": { - "@vitest/spy": "2.1.4", + "@vitest/spy": "2.1.5", "estree-walker": "^3.0.3", "magic-string": "^0.30.12" }, @@ -3313,9 +3333,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.4.tgz", - "integrity": "sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.5.tgz", + "integrity": "sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==", "license": "MIT", "dependencies": { "tinyrainbow": "^1.2.0" @@ -3325,12 +3345,12 @@ } }, "node_modules/@vitest/runner": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.4.tgz", - "integrity": "sha512-sKRautINI9XICAMl2bjxQM8VfCMTB0EbsBc/EDFA57V6UQevEKY/TOPOF5nzcvCALltiLfXWbq4MaAwWx/YxIA==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.5.tgz", + "integrity": "sha512-pKHKy3uaUdh7X6p1pxOkgkVAFW7r2I818vHDthYLvUyjRfkKOU6P45PztOch4DZarWQne+VOaIMwA/erSSpB9g==", "license": "MIT", "dependencies": { - "@vitest/utils": "2.1.4", + "@vitest/utils": "2.1.5", "pathe": "^1.1.2" }, "funding": { @@ -3338,12 +3358,12 @@ } }, "node_modules/@vitest/snapshot": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.4.tgz", - "integrity": "sha512-3Kab14fn/5QZRog5BPj6Rs8dc4B+mim27XaKWFWHWA87R56AKjHTGcBFKpvZKDzC4u5Wd0w/qKsUIio3KzWW4Q==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.5.tgz", + "integrity": "sha512-zmYw47mhfdfnYbuhkQvkkzYroXUumrwWDGlMjpdUr4jBd3HZiV2w7CQHj+z7AAS4VOtWxI4Zt4bWt4/sKcoIjg==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.4", + "@vitest/pretty-format": "2.1.5", "magic-string": "^0.30.12", "pathe": "^1.1.2" }, @@ -3352,9 +3372,9 @@ } }, "node_modules/@vitest/spy": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.4.tgz", - "integrity": "sha512-4JOxa+UAizJgpZfaCPKK2smq9d8mmjZVPMt2kOsg/R8QkoRzydHH1qHxIYNvr1zlEaFj4SXiaaJWxq/LPLKaLg==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.5.tgz", + "integrity": "sha512-aWZF3P0r3w6DiYTVskOYuhBc7EMc3jvn1TkBg8ttylFFRqNN2XGD7V5a4aQdk6QiUzZQ4klNBSpCLJgWNdIiNw==", "license": "MIT", "dependencies": { "tinyspy": "^3.0.2" @@ -3364,12 +3384,12 @@ } }, "node_modules/@vitest/utils": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.4.tgz", - "integrity": "sha512-MXDnZn0Awl2S86PSNIim5PWXgIAx8CIkzu35mBdSApUip6RFOGXBCf3YFyeEu8n1IHk4bWD46DeYFu9mQlFIRg==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.5.tgz", + "integrity": "sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.4", + "@vitest/pretty-format": "2.1.5", "loupe": "^3.1.2", "tinyrainbow": "^1.2.0" }, @@ -3378,53 +3398,53 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.12.tgz", - "integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", "license": "MIT", "dependencies": { "@babel/parser": "^7.25.3", - "@vue/shared": "3.5.12", + "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz", - "integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.12", - "@vue/shared": "3.5.12" + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz", - "integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", "license": "MIT", "dependencies": { "@babel/parser": "^7.25.3", - "@vue/compiler-core": "3.5.12", - "@vue/compiler-dom": "3.5.12", - "@vue/compiler-ssr": "3.5.12", - "@vue/shared": "3.5.12", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", - "postcss": "^8.4.47", + "postcss": "^8.4.48", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz", - "integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.12", - "@vue/shared": "3.5.12" + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" } }, "node_modules/@vue/devtools-api": { @@ -3473,53 +3493,53 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.12.tgz", - "integrity": "sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.12" + "@vue/shared": "3.5.13" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.12.tgz", - "integrity": "sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.12", - "@vue/shared": "3.5.12" + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.12.tgz", - "integrity": "sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.12", - "@vue/runtime-core": "3.5.12", - "@vue/shared": "3.5.12", + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.12.tgz", - "integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.12", - "@vue/shared": "3.5.12" + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" }, "peerDependencies": { - "vue": "3.5.12" + "vue": "3.5.13" } }, "node_modules/@vue/shared": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.12.tgz", - "integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", "license": "MIT" }, "node_modules/@vue/test-utils": { @@ -4467,9 +4487,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", - "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -4822,9 +4842,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.56", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.56.tgz", - "integrity": "sha512-7lXb9dAvimCFdvUMTyucD4mnIndt/xhRKFAlky0CyFogdnNmdPQNoHI23msF/2V4mpTxMzgMdjK4+YRlFlRQZw==", + "version": "1.5.63", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.63.tgz", + "integrity": "sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -4855,9 +4875,9 @@ } }, "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "version": "1.23.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.5.tgz", + "integrity": "sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -4875,7 +4895,7 @@ "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", + "globalthis": "^1.0.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.3", @@ -4891,10 +4911,10 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", + "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.2", "safe-regex-test": "^1.0.3", "string.prototype.trim": "^1.2.9", @@ -4935,6 +4955,12 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", @@ -5074,26 +5100,26 @@ } }, "node_modules/eslint": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", - "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", + "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.14.0", - "@eslint/plugin-kit": "^0.2.0", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.15.0", + "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.0", + "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.5", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", @@ -5112,8 +5138,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -5701,9 +5726,9 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "license": "ISC" }, "node_modules/flexsearch": { @@ -6054,9 +6079,9 @@ } }, "node_modules/happy-dom": { - "version": "15.11.3", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.11.3.tgz", - "integrity": "sha512-MZFy3YpoX4jnQbgrTWv35gpKxvw8y9FRSOIO6CIYmpZjxbkobaB0sAW+EXCxwTZcMvvmrjD59/NYvyld6nABfw==", + "version": "15.11.6", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-15.11.6.tgz", + "integrity": "sha512-elX7iUTu+5+3b2+NGQc0L3eWyq9jKhuJJ4GpOMxxT/c2pg9O3L5H3ty2VECX0XXZgRmmRqXyOK8brA2hDI6LsQ==", "license": "MIT", "dependencies": { "entities": "^4.5.0", @@ -6958,9 +6983,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.12", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", - "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "version": "0.30.13", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.13.tgz", + "integrity": "sha512-8rYBO+MsWkgjDSOvLomYnzhdwEG51olQ4zL5KXnNJWV5MNmrb4rTZdrtkhxjnD/QyZUqR/Z/XDsUs/4ej2nx0g==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" @@ -7592,12 +7617,12 @@ } }, "node_modules/playwright": { - "version": "1.48.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.2.tgz", - "integrity": "sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==", + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.0.tgz", + "integrity": "sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.48.2" + "playwright-core": "1.49.0" }, "bin": { "playwright": "cli.js" @@ -7610,9 +7635,9 @@ } }, "node_modules/playwright-core": { - "version": "1.48.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.2.tgz", - "integrity": "sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==", + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.0.tgz", + "integrity": "sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -7987,9 +8012,9 @@ } }, "node_modules/rollup": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.25.0.tgz", - "integrity": "sha512-uVbClXmR6wvx5R1M3Od4utyLUxrmOcEm3pAtMphn73Apq19PDtHpgZoEvqH2YnnaNUuvKmg2DgRd2Sqv+odyqg==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.3.tgz", + "integrity": "sha512-SLsCOnlmGt9VoZ9Ek8yBK8tAdmPHeppkw+Xa7yDlCEhDTvwYei03JlWo1fdc7YTfLZ4tD8riJCUyAgTbszk1fQ==", "license": "MIT", "dependencies": { "@types/estree": "1.0.6" @@ -8002,24 +8027,24 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.25.0", - "@rollup/rollup-android-arm64": "4.25.0", - "@rollup/rollup-darwin-arm64": "4.25.0", - "@rollup/rollup-darwin-x64": "4.25.0", - "@rollup/rollup-freebsd-arm64": "4.25.0", - "@rollup/rollup-freebsd-x64": "4.25.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.25.0", - "@rollup/rollup-linux-arm-musleabihf": "4.25.0", - "@rollup/rollup-linux-arm64-gnu": "4.25.0", - "@rollup/rollup-linux-arm64-musl": "4.25.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.25.0", - "@rollup/rollup-linux-riscv64-gnu": "4.25.0", - "@rollup/rollup-linux-s390x-gnu": "4.25.0", - "@rollup/rollup-linux-x64-gnu": "4.25.0", - "@rollup/rollup-linux-x64-musl": "4.25.0", - "@rollup/rollup-win32-arm64-msvc": "4.25.0", - "@rollup/rollup-win32-ia32-msvc": "4.25.0", - "@rollup/rollup-win32-x64-msvc": "4.25.0", + "@rollup/rollup-android-arm-eabi": "4.27.3", + "@rollup/rollup-android-arm64": "4.27.3", + "@rollup/rollup-darwin-arm64": "4.27.3", + "@rollup/rollup-darwin-x64": "4.27.3", + "@rollup/rollup-freebsd-arm64": "4.27.3", + "@rollup/rollup-freebsd-x64": "4.27.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.3", + "@rollup/rollup-linux-arm-musleabihf": "4.27.3", + "@rollup/rollup-linux-arm64-gnu": "4.27.3", + "@rollup/rollup-linux-arm64-musl": "4.27.3", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.3", + "@rollup/rollup-linux-riscv64-gnu": "4.27.3", + "@rollup/rollup-linux-s390x-gnu": "4.27.3", + "@rollup/rollup-linux-x64-gnu": "4.27.3", + "@rollup/rollup-linux-x64-musl": "4.27.3", + "@rollup/rollup-win32-arm64-msvc": "4.27.3", + "@rollup/rollup-win32-ia32-msvc": "4.27.3", + "@rollup/rollup-win32-x64-msvc": "4.27.3", "fsevents": "~2.3.2" } }, @@ -8677,12 +8702,6 @@ "license": "MIT", "peer": true }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "license": "MIT" - }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -8696,9 +8715,9 @@ "license": "MIT" }, "node_modules/tinypool": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz", - "integrity": "sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", + "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" @@ -8969,14 +8988,14 @@ } }, "node_modules/typescript-eslint": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.14.0.tgz", - "integrity": "sha512-K8fBJHxVL3kxMmwByvz8hNdBJ8a0YqKzKDX6jRlrjMuNXyd5T2V02HIq37+OiWXvUUOXgOOGiSSOh26Mh8pC3w==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.15.0.tgz", + "integrity": "sha512-wY4FRGl0ZI+ZU4Jo/yjdBu0lVTSML58pu6PgGtJmCufvzfV565pUF6iACQt092uFOd49iLOTX/sEVmHtbSrS+w==", "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.14.0", - "@typescript-eslint/parser": "8.14.0", - "@typescript-eslint/utils": "8.14.0" + "@typescript-eslint/eslint-plugin": "8.15.0", + "@typescript-eslint/parser": "8.15.0", + "@typescript-eslint/utils": "8.15.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8985,6 +9004,9 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -9278,30 +9300,30 @@ } }, "node_modules/vitest": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.4.tgz", - "integrity": "sha512-eDjxbVAJw1UJJCHr5xr/xM86Zx+YxIEXGAR+bmnEID7z9qWfoxpHw0zdobz+TQAFOLT+nEXz3+gx6nUJ7RgmlQ==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.5.tgz", + "integrity": "sha512-P4ljsdpuzRTPI/kbND2sDZ4VmieerR2c9szEZpjc+98Z9ebvnXmM5+0tHEKqYZumXqlvnmfWsjeFOjXVriDG7A==", "license": "MIT", "dependencies": { - "@vitest/expect": "2.1.4", - "@vitest/mocker": "2.1.4", - "@vitest/pretty-format": "^2.1.4", - "@vitest/runner": "2.1.4", - "@vitest/snapshot": "2.1.4", - "@vitest/spy": "2.1.4", - "@vitest/utils": "2.1.4", + "@vitest/expect": "2.1.5", + "@vitest/mocker": "2.1.5", + "@vitest/pretty-format": "^2.1.5", + "@vitest/runner": "2.1.5", + "@vitest/snapshot": "2.1.5", + "@vitest/spy": "2.1.5", + "@vitest/utils": "2.1.5", "chai": "^5.1.2", "debug": "^4.3.7", "expect-type": "^1.1.0", "magic-string": "^0.30.12", "pathe": "^1.1.2", - "std-env": "^3.7.0", + "std-env": "^3.8.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.1", "tinypool": "^1.0.1", "tinyrainbow": "^1.2.0", "vite": "^5.0.0", - "vite-node": "2.1.4", + "vite-node": "2.1.5", "why-is-node-running": "^2.3.0" }, "bin": { @@ -9316,8 +9338,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "2.1.4", - "@vitest/ui": "2.1.4", + "@vitest/browser": "2.1.5", + "@vitest/ui": "2.1.5", "happy-dom": "*", "jsdom": "*" }, @@ -9343,13 +9365,14 @@ } }, "node_modules/vitest/node_modules/vite-node": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.4.tgz", - "integrity": "sha512-kqa9v+oi4HwkG6g8ufRnb5AeplcRw8jUF6/7/Qz1qRQOXHImG8YnLbB+LLszENwFnoBl9xIf9nVdCFzNd7GQEg==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.5.tgz", + "integrity": "sha512-rd0QIgx74q4S1Rd56XIiL2cYEdyWn13cunYBIuqh9mpmQr7gGS0IxXoP8R6OaZtNQQLyXSWbd4rXKYUbhFpK5w==", "license": "MIT", "dependencies": { "cac": "^6.7.14", "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", "pathe": "^1.1.2", "vite": "^5.0.0" }, @@ -9364,16 +9387,16 @@ } }, "node_modules/vue": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.12.tgz", - "integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.12", - "@vue/compiler-sfc": "3.5.12", - "@vue/runtime-dom": "3.5.12", - "@vue/server-renderer": "3.5.12", - "@vue/shared": "3.5.12" + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" }, "peerDependencies": { "typescript": "*" From 5bfa66124780de3b36ed978e07d34712607be3f4 Mon Sep 17 00:00:00 2001 From: Michael Geers Date: Wed, 20 Nov 2024 10:43:29 +0100 Subject: [PATCH 57/58] Config UI: device value formatting (#17258) --- assets/js/components/Config/DeviceTags.vue | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/assets/js/components/Config/DeviceTags.vue b/assets/js/components/Config/DeviceTags.vue index 9021b616c1..ab9d5e80c8 100644 --- a/assets/js/components/Config/DeviceTags.vue +++ b/assets/js/components/Config/DeviceTags.vue @@ -10,11 +10,13 @@ {{ $t(`config.deviceValue.${entry.name}`) }}
{{ fmtDeviceValue(entry) }} @@ -23,7 +25,9 @@
From 0dad8b82d5431d9701eee6b150b8e17975cc0af5 Mon Sep 17 00:00:00 2001 From: Mungg1818 <65672049+Mungg1818@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:31:10 +0100 Subject: [PATCH 58/58] Add Huawei EMMA (#17338) --- templates/definition/meter/huawei-emma.yaml | 108 ++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 templates/definition/meter/huawei-emma.yaml diff --git a/templates/definition/meter/huawei-emma.yaml b/templates/definition/meter/huawei-emma.yaml new file mode 100644 index 0000000000..2172e4c1f7 --- /dev/null +++ b/templates/definition/meter/huawei-emma.yaml @@ -0,0 +1,108 @@ +template: huawei-emma +products: + - brand: Huawei + description: + generic: EMMA +params: + - name: usage + choice: ["grid", "pv", "battery"] + allinone: true + - name: modbus + choice: ["tcpip"] + - name: capacity + advanced: true +render: | + type: custom + {{- if eq .usage "grid" }} + power: + source: modbus + id: 0 + uri: {{ .host }}:{{ .port }} + register: + address: 31657 # Active power of built-in electric energy sensor + type: holding + decode: int32 + energy: + source: modbus + id: 0 + uri: {{ .host }}:{{ .port }} + register: + address: 31679 # Total negative active energy of built-in electric energy sensor + type: holding + decode: int64 + scale: 0.01 + currents: + - source: modbus + id: 0 + uri: {{ .host }}:{{ .port }} + register: + address: 31651 # Huawei phase A grid current + type: holding + decode: int32 + scale: 0.1 + - source: modbus + id: 0 + uri: {{ .host }}:{{ .port }} + register: + address: 31653 # Huawei phase B grid current + type: holding + decode: int32 + scale: 0.1 + - source: modbus + id: 0 + uri: {{ .host }}:{{ .port }} + register: + address: 31655 # Huawei phase C grid current + type: holding + decode: int32 + scale: 0.1 + {{- end }} + {{- if eq .usage "pv" }} + power: + source: modbus + id: 0 + uri: {{ .host }}:{{ .port }} + register: + address: 30354 # Active power + type: holding + decode: int32 + energy: + source: modbus + id: 0 + uri: {{ .host }}:{{ .port }} + register: + address: 30344 # E-Total + type: holding + decode: uint32 + scale: 0.1 + {{- end }} + {{- if eq .usage "battery" }} + power: + source: modbus + id: 0 + uri: {{ .host }}:{{ .port }} + register: + address: 30360 + type: holding + decode: int32nan + scale: -1 + energy: + source: modbus + id: 0 + uri: {{ .host }}:{{ .port }} + register: + address: 30312 # Total discharge + type: holding + decode: uint32nan + scale: 0.01 + soc: + source: modbus + id: 0 + uri: {{ .host }}:{{ .port }} + register: + address: 30368 + type: holding + decode: uint16nan + scale: 0.01 + capacity: {{ .capacity }} # kWh + {{- end }}