From 0ee6d787e1a6b2c0139af9cc4513ee27a10fd4bc Mon Sep 17 00:00:00 2001 From: andig Date: Thu, 12 Feb 2026 15:56:06 +0100 Subject: [PATCH] chore: use Go 1.26 (#26786) --- .github/workflows/default.yml | 11 ++++++- .golangci.yml | 4 +-- charger/ocpp/helper.go | 2 +- charger/smaevcharger.go | 6 ++-- cmd/decorate/decorate.go | 49 ++++++++++---------------------- cmd/error.go | 2 +- cmd/helper.go | 13 ++++----- cmd/setup.go | 6 ++-- core/loadpoint_session.go | 5 ++-- core/meterenergy.go | 3 +- core/site.go | 6 ++-- core/site_tariffs.go | 4 +-- go.mod | 7 +++-- go.sum | 20 +++++++------ hems/eebus/eebus.go | 3 +- hems/relay/relay.go | 3 +- meter/lgpcs/lgpcs.go | 2 +- plugin/script.go | 3 +- server/influxdb_test.go | 11 ++++--- server/modbus/handler.go | 4 +-- server/mqtt.go | 3 +- server/mqtt_test.go | 5 ++-- tariff/helper.go | 2 +- util/error.go | 4 +-- util/format.go | 9 +++--- util/modbus/modbus_test.go | 3 +- util/templates/render_testing.go | 2 +- vehicle/bmw/cardata/mqtt.go | 3 +- vehicle/bmw/cardata/token.go | 8 ------ vehicle/fiat/provider.go | 2 +- vehicle/renault/provider.go | 9 ++---- vehicle/tronity.go | 2 +- vehicle/vw/api.go | 2 +- 33 files changed, 96 insertions(+), 122 deletions(-) diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml index cbd8890bd..f91a51e26 100644 --- a/.github/workflows/default.yml +++ b/.github/workflows/default.yml @@ -266,9 +266,18 @@ jobs: env: TZ: Europe/Berlin - - uses: actions/upload-artifact@v6 + - name: Upload Playwright Report + uses: actions/upload-artifact@v6 if: ${{ !cancelled() }} with: name: playwright-report path: playwright-report/ retention-days: 14 + + - name: Upload Playwright Raw Test Results + uses: actions/upload-artifact@v6 + if: failure() + with: + name: playwright-test-results + path: test-results/ + retention-days: 2 diff --git a/.golangci.yml b/.golangci.yml index d0a732c22..8c1836a1e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,6 @@ version: "2" -run: - go: "1.25" +# run: +# go: "1.26" linters: default: none enable: diff --git a/charger/ocpp/helper.go b/charger/ocpp/helper.go index b2224800a..d92f4f102 100644 --- a/charger/ocpp/helper.go +++ b/charger/ocpp/helper.go @@ -20,7 +20,7 @@ func wait(err error, rc chan error) error { close(rc) } - if oe := new(ocpp.Error); errors.As(err, &oe) && oe.Code == ocppj.GenericError { + if oe, ok := errors.AsType[*ocpp.Error](err); ok && oe.Code == ocppj.GenericError { err = api.ErrTimeout } } diff --git a/charger/smaevcharger.go b/charger/smaevcharger.go index 57083de84..15c0aff55 100644 --- a/charger/smaevcharger.go +++ b/charger/smaevcharger.go @@ -247,7 +247,7 @@ var _ api.MeterEnergy = (*Smaevcharger)(nil) // TotalEnergy implements the api.MeterEnergy interface func (wb *Smaevcharger) TotalEnergy() (float64, error) { res, err := wb.getMeasurement("Measurement.Metering.GridMs.TotWhIn") - if se := new(smaevcharger.ErrUnknownMeasurement); errors.As(err, &se) { + if _, ok := errors.AsType[*smaevcharger.ErrUnknownMeasurement](err); ok { res, err = wb.getMeasurement("Measurement.Metering.GridMs.TotWhIn.ChaSta") } return res / 1e3, err @@ -258,7 +258,7 @@ var _ api.Meter = (*Smaevcharger)(nil) // CurrentPower implements the api.Meter interface func (wb *Smaevcharger) CurrentPower() (float64, error) { res, err := wb.getMeasurement("Measurement.Metering.GridMs.TotWIn") - if se := new(smaevcharger.ErrUnknownMeasurement); errors.As(err, &se) { + if _, ok := errors.AsType[*smaevcharger.ErrUnknownMeasurement](err); ok { res, err = wb.getMeasurement("Measurement.Metering.GridMs.TotWIn.ChaSta") } return res, err @@ -269,7 +269,7 @@ var _ api.ChargeRater = (*Smaevcharger)(nil) // ChargedEnergy implements the api.ChargeRater interface func (wb *Smaevcharger) ChargedEnergy() (float64, error) { res, err := wb.getMeasurement("Measurement.ChaSess.WhIn") - if se := new(smaevcharger.ErrUnknownMeasurement); errors.As(err, &se) { + if _, ok := errors.AsType[*smaevcharger.ErrUnknownMeasurement](err); ok { res, err = wb.getMeasurement("Measurement.Metering.GridMs.TotWhIn.ChaSta") } return res / 1e3, err diff --git a/cmd/decorate/decorate.go b/cmd/decorate/decorate.go index 968e2106b..f1b295fa4 100644 --- a/cmd/decorate/decorate.go +++ b/cmd/decorate/decorate.go @@ -55,42 +55,23 @@ type typeStruct struct { Functions []funcStruct } -var a struct { - api.Meter - api.MeterEnergy - api.PhaseCurrents - api.PhaseVoltages - api.PhasePowers - api.MaxACPowerGetter +var dependents = make(map[string][]string) - api.PhaseSwitcher - api.PhaseGetter +func init() { + reflectTypes := map[reflect.Type][]reflect.Type{ + reflect.TypeFor[api.Meter](): {reflect.TypeFor[api.MeterEnergy](), reflect.TypeFor[api.PhaseCurrents](), reflect.TypeFor[api.PhaseVoltages](), reflect.TypeFor[api.MaxACPowerGetter]()}, + reflect.TypeFor[api.PhaseCurrents](): {reflect.TypeFor[api.PhasePowers]()}, // phase powers are only used to determine currents sign + reflect.TypeFor[api.PhaseSwitcher](): {reflect.TypeFor[api.PhaseGetter]()}, + reflect.TypeFor[api.Battery](): {reflect.TypeFor[api.BatteryCapacity](), reflect.TypeFor[api.SocLimiter](), reflect.TypeFor[api.BatteryController](), reflect.TypeFor[api.BatterySocLimiter](), reflect.TypeFor[api.BatteryPowerLimiter]()}, + reflect.TypeFor[api.ChargeState](): {reflect.TypeFor[api.ChargeController](), reflect.TypeFor[api.CurrentController]()}, + reflect.TypeFor[api.CurrentController](): {reflect.TypeFor[api.CurrentGetter]()}, + } - api.Battery - api.BatteryCapacity - api.SocLimiter // vehicles only - api.BatteryController - api.BatterySocLimiter - api.BatteryPowerLimiter - - // vehicle - api.ChargeState - api.ChargeController - api.CurrentController - api.CurrentGetter -} - -func typ(i any) string { - return reflect.TypeOf(i).Elem().String() -} - -var dependents = map[string][]string{ - typ(&a.Meter): {typ(&a.MeterEnergy), typ(&a.PhaseCurrents), typ(&a.PhaseVoltages), typ(&a.MaxACPowerGetter)}, - typ(&a.PhaseCurrents): {typ(&a.PhasePowers)}, // phase powers are only used to determine currents sign - typ(&a.PhaseSwitcher): {typ(&a.PhaseGetter)}, - typ(&a.Battery): {typ(&a.BatteryCapacity), typ(&a.SocLimiter), typ(&a.BatteryController), typ(&a.BatterySocLimiter), typ(&a.BatteryPowerLimiter)}, - typ(&a.ChargeState): {typ(&a.ChargeController), typ(&a.CurrentController)}, - typ(&a.CurrentController): {typ(&a.CurrentGetter)}, + for typ, types := range reflectTypes { + dependents[typ.String()] = lo.Map(types, func(typ reflect.Type, _ int) string { + return typ.String() + }) + } } // hasIntersection returns if the slices intersect diff --git a/cmd/error.go b/cmd/error.go index f7d403d1d..63fdeb6b2 100644 --- a/cmd/error.go +++ b/cmd/error.go @@ -82,7 +82,7 @@ func (e ClassError) MarshalJSON() ([]byte, error) { Error: e.err.Error(), } - if de := new(DeviceError); errors.As(e.err, &de) { + if de, ok := errors.AsType[*DeviceError](e.err); ok { res.Device = de.Name } diff --git a/cmd/helper.go b/cmd/helper.go index aba6556c8..fc2fe856b 100644 --- a/cmd/helper.go +++ b/cmd/helper.go @@ -81,17 +81,14 @@ func wrapFatalError(err error) error { return nil } - var opErr *net.OpError - var pathErr *os.PathError - - switch { - case errors.As(err, &opErr): - if opErr.Op == "listen" && strings.Contains(opErr.Error(), "address already in use") { + if err2, ok := errors.AsType[*net.OpError](err); ok { + if err2.Op == "listen" && strings.Contains(err2.Error(), "address already in use") { err = fmt.Errorf("could not open port- check that evcc is not already running (%w)", err) } + } - case errors.As(err, &pathErr): - if pathErr.Op == "remove" && strings.Contains(pathErr.Error(), "operation not permitted") { + if err2, ok := errors.AsType[*os.PathError](err); ok { + if err2.Op == "remove" && strings.Contains(err2.Error(), "operation not permitted") { err = fmt.Errorf("could not remove file- check that evcc is not already running (%w)", err) } } diff --git a/cmd/setup.go b/cmd/setup.go index 5953c5b5f..285edbe15 100644 --- a/cmd/setup.go +++ b/cmd/setup.go @@ -98,7 +98,7 @@ func nameValid(name string) error { func loadConfigFile(conf *globalconfig.All, checkDB bool) error { if err := viper.ReadInConfig(); err != nil { - if !errors.As(err, &vpr.ConfigFileNotFoundError{}) { + if _, ok := errors.AsType[vpr.ConfigFileNotFoundError](err); !ok { return fmt.Errorf("failed reading config file: %w", err) } } @@ -390,7 +390,7 @@ func vehicleInstance(cc config.Named) (api.Vehicle, error) { } if err != nil { - if ce := new(util.ConfigError); errors.As(err, &ce) { + if _, ok := errors.AsType[*util.ConfigError](err); ok { return nil, err } @@ -856,7 +856,7 @@ func tariffInstance(name string, conf config.Typed) (api.Tariff, error) { instance, err := tariff.NewFromConfig(ctx, conf.Type, props) if err != nil { - if ce := new(util.ConfigError); errors.As(err, &ce) { + if _, ok := errors.AsType[*util.ConfigError](err); ok { return nil, err } diff --git a/core/loadpoint_session.go b/core/loadpoint_session.go index 0f88a6399..925d35153 100644 --- a/core/loadpoint_session.go +++ b/core/loadpoint_session.go @@ -8,7 +8,6 @@ import ( "github.com/evcc-io/evcc/core/session" "github.com/evcc-io/evcc/core/wrapper" "github.com/jinzhu/now" - "github.com/samber/lo" ) func (lp *Loadpoint) chargeMeterTotal() float64 { @@ -77,12 +76,12 @@ func (lp *Loadpoint) stopSession() { s.MeterStop = &meterStop } - s.SolarPercentage = lo.ToPtr(lp.energyMetrics.SolarPercentage()) + s.SolarPercentage = new(lp.energyMetrics.SolarPercentage()) s.Price = lp.energyMetrics.Price() s.PricePerKWh = lp.energyMetrics.PricePerKWh() s.Co2PerKWh = lp.energyMetrics.Co2PerKWh() s.ChargedEnergy = lp.energyMetrics.TotalWh() / 1e3 - s.ChargeDuration = lo.ToPtr(lp.chargeDuration.Abs()) + s.ChargeDuration = new(lp.chargeDuration.Abs()) lp.db.Persist(s) } diff --git a/core/meterenergy.go b/core/meterenergy.go index c2fe98bc5..769834c37 100644 --- a/core/meterenergy.go +++ b/core/meterenergy.go @@ -6,7 +6,6 @@ import ( "time" "github.com/benbjohnson/clock" - "github.com/samber/lo" ) type meterEnergy struct { @@ -34,7 +33,7 @@ func (m *meterEnergy) AccumulatedEnergy() float64 { func (m *meterEnergy) AddMeterTotal(v float64) { defer func() { m.updated = m.clock.Now() - m.meter = lo.ToPtr(v) + m.meter = new(v) }() if m.meter == nil { diff --git a/core/site.go b/core/site.go index 3db503fb3..16cdd2758 100644 --- a/core/site.go +++ b/core/site.go @@ -614,10 +614,10 @@ func (site *Site) updateBatteryMeters() []types.Measurement { if m, ok := meter.(api.Battery); ok { batSoc, err := soc.Guard(m.Soc()) if err == nil { - mm[i].Soc = lo.ToPtr(batSoc) + mm[i].Soc = new(batSoc) if m, ok := m.(api.BatteryCapacity); ok { - mm[i].Capacity = lo.ToPtr(m.Capacity()) + mm[i].Capacity = new(m.Capacity()) } site.log.DEBUG.Printf("battery %d soc: %.0f%%", i+1, batSoc) @@ -627,7 +627,7 @@ func (site *Site) updateBatteryMeters() []types.Measurement { } _, controllable := meter.(api.BatteryController) - mm[i].Controllable = lo.ToPtr(controllable) + mm[i].Controllable = new(controllable) } batterySocAcc := lo.SumBy(mm, func(m types.Measurement) float64 { diff --git a/core/site_tariffs.go b/core/site_tariffs.go index 916b22934..28372c618 100644 --- a/core/site_tariffs.go +++ b/core/site_tariffs.go @@ -115,7 +115,7 @@ func (site *Site) publishTariffs(greenShareHome float64, greenShareLoadpoints fl // calculate adjusted solar rates if solar := tariff.Rates(site.GetTariff(api.TariffUsageSolar)); len(solar) > 0 { - fc.Solar = lo.ToPtr(site.solarDetails(solar)) + fc.Solar = new(site.solarDetails(solar)) } site.publish(keys.Forecast, util.NewSharder(keys.Forecast, fc)) @@ -169,7 +169,7 @@ func (site *Site) solarDetails(solar api.Rates) solarDetails { const minEnergy = 0.5 // kWh if produced+fcst > minEnergy { - res.Scale = lo.ToPtr(scale) + res.Scale = new(scale) } } diff --git a/go.mod b/go.mod index 1fd2c6615..52026d42c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/evcc-io/evcc -go 1.25.3 +go 1.26.0 require ( dario.cat/mergo v1.0.2 @@ -146,6 +146,7 @@ require ( github.com/clipperhouse/uax29/v2 v2.3.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/creack/goselect v0.1.2 // indirect + github.com/creack/pty v1.1.18 // indirect github.com/cronokirby/saferith v0.33.0 // indirect github.com/cstockton/go-conv v1.0.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -174,6 +175,7 @@ require ( github.com/golanguzb70/lrucache v1.2.0 // indirect github.com/google/go-querystring v1.2.0 // indirect github.com/google/jsonschema-go v0.4.2 // indirect + github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect github.com/google/renameio/v2 v2.0.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/gosimple/unidecode v1.0.1 // indirect @@ -207,7 +209,7 @@ require ( github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect github.com/olekukonko/errors v1.1.0 // indirect github.com/olekukonko/ll v0.1.4-0.20260115111900-9e59c2286df0 // indirect - github.com/onsi/ginkgo/v2 v2.13.0 // indirect + github.com/onsi/ginkgo/v2 v2.23.4 // indirect github.com/pascaldekloe/name v1.0.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect @@ -222,6 +224,7 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rickb777/date v1.21.1 // indirect github.com/rickb777/plural v1.4.2 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect diff --git a/go.sum b/go.sum index 7206fa7cc..453f90438 100644 --- a/go.sum +++ b/go.sum @@ -150,8 +150,9 @@ github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6N github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0= github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cronokirby/saferith v0.33.0 h1:TgoQlfsD4LIwx71+ChfRcIpjkw+RPOapDEVxa+LhwLo= github.com/cronokirby/saferith v0.33.0/go.mod h1:QKJhjoqUtBsXCAVEjw38mFqoi7DebT7kthcD7UzbnoA= github.com/cstockton/go-conv v1.0.0 h1:zj/q/0MpQ/97XfiC9glWiohO8lhgR4TTnHYZifLTv6I= @@ -267,7 +268,8 @@ github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 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-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-telegram/bot v1.18.0 h1:yQzv437DY42SYTPBY48RinAvwbmf1ox5QICskIYWCD8= github.com/go-telegram/bot v1.18.0/go.mod h1:i2TRs7fXWIeaceF3z7KzsMt/he0TwkVC680mvdTFYeM= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= @@ -330,8 +332,8 @@ github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8= github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= @@ -574,8 +576,8 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.38.0 h1:c/WX+w8SLAinvuKKQFh77WEucCnPk4j2OTUr7lt7BeY= github.com/onsi/gomega v1.38.0/go.mod h1:OcXcwId0b9QsE7Y49u+BTrL4IdKOBOKnD6VQNTJEB6o= @@ -666,8 +668,8 @@ github.com/robertkrimen/otto v0.5.1 h1:avDI4ToRk8k1hppLdYFTuuzND41n37vPGJU7547dG github.com/robertkrimen/otto v0.5.1/go.mod h1:bS433I4Q9p+E5pZLu7r17vP6FkE6/wLxBdmKjoqJXF8= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -799,6 +801,8 @@ go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJr go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= diff --git a/hems/eebus/eebus.go b/hems/eebus/eebus.go index 7df000920..6900675fe 100644 --- a/hems/eebus/eebus.go +++ b/hems/eebus/eebus.go @@ -15,7 +15,6 @@ import ( "github.com/evcc-io/evcc/plugin" "github.com/evcc-io/evcc/server/eebus" "github.com/evcc-io/evcc/util" - "github.com/samber/lo" ) type EEBus struct { @@ -297,7 +296,7 @@ func (c *EEBus) updateSession(id *uint, typ smartgrid.Type, limit float64) error if limit > 0 && *id == 0 { var power *float64 if p := c.root.GetChargePower(); p > 0 { - power = lo.ToPtr(p) + power = new(p) } sid, err := smartgrid.StartManage(typ, power, limit) diff --git a/hems/relay/relay.go b/hems/relay/relay.go index 435ab4b5c..312ea8b0d 100644 --- a/hems/relay/relay.go +++ b/hems/relay/relay.go @@ -13,7 +13,6 @@ import ( "github.com/evcc-io/evcc/hems/smartgrid" "github.com/evcc-io/evcc/plugin" "github.com/evcc-io/evcc/util" - "github.com/samber/lo" ) type Relay struct { @@ -129,7 +128,7 @@ func (c *Relay) updateSession(limit float64) error { if limit > 0 && c.smartgridID == 0 { var power *float64 if p := c.root.GetChargePower(); p > 0 { - power = lo.ToPtr(p) + power = new(p) } sid, err := smartgrid.StartManage(smartgrid.Dim, power, limit) diff --git a/meter/lgpcs/lgpcs.go b/meter/lgpcs/lgpcs.go index bc4da3d0e..7899ad739 100644 --- a/meter/lgpcs/lgpcs.go +++ b/meter/lgpcs/lgpcs.go @@ -201,7 +201,7 @@ func (m *Com) request(f func(any) (*http.Request, error), payload map[string]str } // re-login if request returns 405-error - if se := new(request.StatusError); errors.As(err, &se) && se.StatusCode() != http.StatusMethodNotAllowed { + if se, ok := errors.AsType[*request.StatusError](err); ok && se.StatusCode() != http.StatusMethodNotAllowed { return err } diff --git a/plugin/script.go b/plugin/script.go index a3c311ae0..5cb98c423 100644 --- a/plugin/script.go +++ b/plugin/script.go @@ -92,8 +92,7 @@ func (p *Script) exec(script string) (string, error) { if err != nil { // use STDOUT if available - var ee *exec.ExitError - if errors.As(err, &ee) { + if ee, ok := errors.AsType[*exec.ExitError](err); ok { s = strings.TrimSpace(string(ee.Stderr)) } diff --git a/server/influxdb_test.go b/server/influxdb_test.go index 2da388d1b..5e09ebbde 100644 --- a/server/influxdb_test.go +++ b/server/influxdb_test.go @@ -8,7 +8,6 @@ import ( "github.com/evcc-io/evcc/util" inf2 "github.com/influxdata/influxdb-client-go/v2" "github.com/influxdata/influxdb-client-go/v2/api/write" - "github.com/samber/lo" "github.com/stretchr/testify/suite" ) @@ -60,7 +59,7 @@ func (w *influxSuite) TestNil() { } func (w *influxSuite) TestPointer() { - w.WriteParam(util.Param{Key: "foo", Val: lo.ToPtr(1)}) + w.WriteParam(util.Param{Key: "foo", Val: new(1)}) w.Equal([]*write.Point{inf2.NewPoint("foo", nil, map[string]any{"value": 1}, w.clock.Now())}, w.p) } @@ -89,7 +88,7 @@ func (w *influxSuite) TestSlice() { } func (w *influxSuite) TestMeasurement() { - w.WriteParam(util.Param{Key: "battery", Val: types.Measurement{Power: 1, Soc: lo.ToPtr(10.0)}}) + w.WriteParam(util.Param{Key: "battery", Val: types.Measurement{Power: 1, Soc: new(10.0)}}) w.Equal([]*write.Point{ inf2.NewPoint("batteryPower", nil, map[string]any{"value": 1.0}, w.clock.Now()), inf2.NewPoint("batterySoc", nil, map[string]any{"value": 10.0}, w.clock.Now()), @@ -98,8 +97,8 @@ func (w *influxSuite) TestMeasurement() { func (w *influxSuite) TestSliceOfStruct() { w.WriteParam(util.Param{Key: "grid", Val: []types.Measurement{ - {Power: 1, Soc: lo.ToPtr(10.0)}, - {Power: 2, Soc: lo.ToPtr(20.0)}, + {Power: 1, Soc: new(10.0)}, + {Power: 2, Soc: new(20.0)}, }}) w.Equal([]*write.Point{ inf2.NewPoint("gridPower", map[string]string{"id": "1"}, map[string]any{"value": 1.0}, w.clock.Now()), @@ -115,7 +114,7 @@ func (w *influxSuite) TestBatteryState() { Soc: 20.0, Devices: []types.Measurement{{ Power: 1, - Soc: lo.ToPtr(10.0), + Soc: new(10.0), }}, }}) w.Equal([]*write.Point{ diff --git a/server/modbus/handler.go b/server/modbus/handler.go index 1d504f594..a2ffac683 100644 --- a/server/modbus/handler.go +++ b/server/modbus/handler.go @@ -44,7 +44,7 @@ func (h *handler) logResult(op string, b []byte, err error) { func (h *handler) exceptionToUint16AndError(op string, b []byte, err error) ([]uint16, error) { h.logResult(op, b, err) - if me := new(gridx.Error); errors.As(err, &me) { + if me, ok := errors.AsType[*gridx.Error](err); ok { err = mbserver.MapExceptionCodeToError(me.ExceptionCode) } @@ -74,7 +74,7 @@ func coilsToBytes(b []bool) []byte { func (h *handler) bytesToBoolResult(op string, qty uint16, b []byte, err error) ([]bool, error) { h.logResult(op, b, err) - if me := new(gridx.Error); errors.As(err, &me) { + if me, ok := errors.AsType[*gridx.Error](err); ok { err = mbserver.MapExceptionCodeToError(me.ExceptionCode) } diff --git a/server/mqtt.go b/server/mqtt.go index 940b20d92..855534c2e 100644 --- a/server/mqtt.go +++ b/server/mqtt.go @@ -14,7 +14,6 @@ import ( "github.com/evcc-io/evcc/core/vehicle" "github.com/evcc-io/evcc/plugin/mqtt" "github.com/evcc-io/evcc/util" - "github.com/samber/lo" ) // MQTT is the MQTT server. It uses the MQTT client for publishing. @@ -232,7 +231,7 @@ func (m *MQTT) listenSiteSetters(topic string, site site.API) error { {"batteryGridChargeLimit", floatPtrSetter(site.SetBatteryGridChargeLimit)}, {"batteryMode", ptrSetter(api.BatteryModeString, func(m *api.BatteryMode) error { if m == nil { - m = lo.ToPtr(api.BatteryUnknown) + m = new(api.BatteryUnknown) } return site.SetBatteryModeExternal(*m) })}, diff --git a/server/mqtt_test.go b/server/mqtt_test.go index ba79be409..d4286fc1b 100644 --- a/server/mqtt_test.go +++ b/server/mqtt_test.go @@ -8,7 +8,6 @@ import ( "time" "github.com/evcc-io/evcc/core/types" - "github.com/samber/lo" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) @@ -108,7 +107,7 @@ func (suite *mqttSuite) TestMeasurement() { suite.Equal(topics, suite.topics, "topics") suite.Equal([]string{"", "", "0", "1", "", "", "", "", "", ""}, suite.payloads, "payloads") - suite.publish("test", false, types.Measurement{Controllable: lo.ToPtr(false)}) + suite.publish("test", false, types.Measurement{Controllable: new(false)}) suite.Equal(topics, suite.topics, "topics") suite.Equal([]string{"", "", "0", "", "", "", "", "", "", "false"}, suite.payloads, "payloads") @@ -128,7 +127,7 @@ func (suite *mqttSuite) TestBatteryState() { Soc: 20.0, Devices: []types.Measurement{{ Power: 1, - Soc: lo.ToPtr(10.0), + Soc: new(10.0), }}, }) diff --git a/tariff/helper.go b/tariff/helper.go index 47281234b..7ab33a459 100644 --- a/tariff/helper.go +++ b/tariff/helper.go @@ -30,7 +30,7 @@ func bo() backoff.BackOff { // backoffPermanentError returns a permanent error in case of HTTP 400 func backoffPermanentError(err error) error { - if se := new(request.StatusError); errors.As(err, &se) { + if se, ok := errors.AsType[*request.StatusError](err); ok { if code := se.StatusCode(); code >= 400 && code <= 599 { return backoff.Permanent(se) } diff --git a/util/error.go b/util/error.go index cc432cff9..ae78b4c94 100644 --- a/util/error.go +++ b/util/error.go @@ -18,11 +18,11 @@ func ErrorAsJson(err error) any { Error: err.Error(), } - if ae := new(api.ErrLoginRequired); errors.As(err, &ae) { + if ae, ok := errors.AsType[*api.ErrLoginRequired](err); ok { res.LoginRequired = ae.ProviderAuth } - if ue := new(api.ErrUrl); errors.As(err, &ue) { + if ue, ok := errors.AsType[*api.ErrUrl](err); ok { res.URI = ue.URL().String() } diff --git a/util/format.go b/util/format.go index 35b58d5d0..e9649717d 100644 --- a/util/format.go +++ b/util/format.go @@ -11,7 +11,6 @@ import ( "time" "github.com/Masterminds/sprig/v3" - "github.com/samber/lo" ) var re = regexp.MustCompile(`(?i)\${(\w+)(:([a-zA-Z0-9%.]+))?}`) @@ -72,10 +71,10 @@ func ReplaceFormatted(s string, kv map[string]any) (string, error) { match, key, format := m[0], m[1], m[3] // find key and replacement value - var val *any + var val any for k, v := range kv { if strings.EqualFold(k, key) { - val = &v + val = v break } } @@ -83,11 +82,11 @@ func ReplaceFormatted(s string, kv map[string]any) (string, error) { if val == nil { wanted = append(wanted, key) format = "%s" - val = lo.ToPtr(any("?")) + val = "?" } // update all literal matches - new := FormatValue(format, *val) + new := FormatValue(format, val) s = strings.ReplaceAll(s, match, new) } diff --git a/util/modbus/modbus_test.go b/util/modbus/modbus_test.go index 4ee4b0434..ce2b3b614 100644 --- a/util/modbus/modbus_test.go +++ b/util/modbus/modbus_test.go @@ -3,7 +3,6 @@ package modbus import ( "testing" - "github.com/samber/lo" "github.com/stretchr/testify/require" ) @@ -31,7 +30,7 @@ func TestSettingsProtocol(t *testing.T) { res Protocol }{ {Settings{UDP: true}, Udp}, - {Settings{RTU: lo.ToPtr(true)}, Rtu}, + {Settings{RTU: new(true)}, Rtu}, {Settings{Device: "foo"}, Rtu}, {Settings{URI: "foo"}, Tcp}, {Settings{}, Tcp}, diff --git a/util/templates/render_testing.go b/util/templates/render_testing.go index 57197b645..8f49d4845 100644 --- a/util/templates/render_testing.go +++ b/util/templates/render_testing.go @@ -60,7 +60,7 @@ func testAuth(other map[string]any) error { _, err := auth.NewFromConfig(context.TODO(), cc.Type, params) // ConfigError indicates invalid parameters in mapstructure decode - if ce := new(util.ConfigError); errors.As(err, &ce) { + if _, ok := errors.AsType[*util.ConfigError](err); ok { return err } diff --git a/vehicle/bmw/cardata/mqtt.go b/vehicle/bmw/cardata/mqtt.go index f03362d8f..02eccf537 100644 --- a/vehicle/bmw/cardata/mqtt.go +++ b/vehicle/bmw/cardata/mqtt.go @@ -12,6 +12,7 @@ import ( "github.com/cenkalti/backoff/v4" mqtt "github.com/eclipse/paho.mqtt.golang" "github.com/eclipse/paho.mqtt.golang/packets" + "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/util" "golang.org/x/oauth2" ) @@ -77,7 +78,7 @@ func (v *MqttConnector) run(ctx context.Context, ts oauth2.TokenSource) { token, err := ts.Token() if err != nil { - if !tokenError(err) { + if _, ok := errors.AsType[*api.ErrLoginRequired](err); !ok { v.log.ERROR.Println(err) } diff --git a/vehicle/bmw/cardata/token.go b/vehicle/bmw/cardata/token.go index 0cec59c59..33aeafe28 100644 --- a/vehicle/bmw/cardata/token.go +++ b/vehicle/bmw/cardata/token.go @@ -1,9 +1,6 @@ package cardata import ( - "errors" - - "github.com/evcc-io/evcc/api" "golang.org/x/oauth2" ) @@ -27,8 +24,3 @@ func TokenExtra(t *oauth2.Token, key string) string { } return "" } - -func tokenError(err error) bool { - ae := new(api.ErrLoginRequired) - return errors.As(err, &ae) -} diff --git a/vehicle/fiat/provider.go b/vehicle/fiat/provider.go index e6ad7e8a5..b1c4b9929 100644 --- a/vehicle/fiat/provider.go +++ b/vehicle/fiat/provider.go @@ -52,7 +52,7 @@ func (v *Provider) deepRefresh() error { if err == nil && res.ResponseStatus != "pending" { err = fmt.Errorf("invalid response status: %s", res.ResponseStatus) } else { - if se := new(request.StatusError); errors.As(err, &se) && se.StatusCode() == http.StatusForbidden { + if se, ok := errors.AsType[*request.StatusError](err); ok && se.StatusCode() == http.StatusForbidden { err = nil } } diff --git a/vehicle/renault/provider.go b/vehicle/renault/provider.go index 527f67812..3ddb4124a 100644 --- a/vehicle/renault/provider.go +++ b/vehicle/renault/provider.go @@ -50,8 +50,7 @@ func NewProvider(api *kamereon.API, accountID, vin string, wakeupMode string, ca _, err = api.WakeUp(accountID, vin) // Check if default wakeup is unsupported - var se *request.StatusError - if errors.As(err, &se) && se.HasStatus(http.StatusForbidden, http.StatusNotFound, http.StatusBadGateway) { + if se, ok := errors.AsType[*request.StatusError](err); ok && se.HasStatus(http.StatusForbidden, http.StatusNotFound, http.StatusBadGateway) { _, err = api.WakeUpMy24(accountID, vin) } } @@ -138,8 +137,7 @@ func (v *Provider) GetLimitSoc() (int64, error) { res, err := v.socLevelsG() // Check if endpoint is unavailable - var se *request.StatusError - if errors.As(err, &se) && se.HasStatus(http.StatusForbidden, http.StatusNotFound, http.StatusBadGateway) { + if se, ok := errors.AsType[*request.StatusError](err); ok && se.HasStatus(http.StatusForbidden, http.StatusNotFound, http.StatusBadGateway) { return 0, api.ErrNotAvailable } @@ -180,8 +178,7 @@ func (v *Provider) Climater() (bool, error) { res, err := v.hvacG() // Zoe Ph2, Megane e-tech - var se *request.StatusError - if errors.As(err, &se) && se.HasStatus(http.StatusForbidden, http.StatusNotFound, http.StatusBadGateway) { + if se, ok := errors.AsType[*request.StatusError](err); ok && se.HasStatus(http.StatusForbidden, http.StatusNotFound, http.StatusBadGateway) { return false, api.ErrNotAvailable } diff --git a/vehicle/tronity.go b/vehicle/tronity.go index 2193d81ce..3defddcca 100644 --- a/vehicle/tronity.go +++ b/vehicle/tronity.go @@ -203,7 +203,7 @@ func (v *Tronity) post(uri string) error { } // ignore HTTP 405 - if se := new(request.StatusError); errors.As(err, &se) && se.StatusCode() == http.StatusMethodNotAllowed { + if se, ok := errors.AsType[*request.StatusError](err); ok && se.StatusCode() == http.StatusMethodNotAllowed { err = nil } diff --git a/vehicle/vw/api.go b/vehicle/vw/api.go index baa6a4a0e..a047b9207 100644 --- a/vehicle/vw/api.go +++ b/vehicle/vw/api.go @@ -100,7 +100,7 @@ func (v *API) Status(vin string) (StatusResponse, error) { err = v.DoJSON(req, &res) } - if se := new(request.StatusError); errors.As(err, &se) { + if _, ok := errors.AsType[*request.StatusError](err); ok { var rr RolesRights rr, err = v.RolesRights(vin)