package cmd import ( "iter" "slices" "strings" "github.com/evcc-io/evcc/api/globalconfig" "github.com/evcc-io/evcc/core" "github.com/evcc-io/evcc/core/keys" "github.com/evcc-io/evcc/server/db/settings" "github.com/evcc-io/evcc/util" "github.com/evcc-io/evcc/util/config" "github.com/evcc-io/evcc/util/templates" ) var references struct { meter, charger, vehicle, circuit, tariff, curtailer []string } func collectRefs(conf globalconfig.All) error { // site if err := collectSiteRefs(conf); err != nil { return err } // tariffs if err := collectTariffRefs(); err != nil { return err } // circuits if err := collectCircuitRefs(conf.Circuits); err != nil { return err } // loadpoints if err := collectLoadpointRefs(slices.Values(conf.Loadpoints)); err != nil { return err } // append devices from database configurable, err := config.ConfigurationsByClass(templates.Loadpoint) if err != nil { return err } return collectLoadpointRefs(func(yield func(config.Named) bool) { for _, cc := range configurable { if !yield(cc.Named()) { return } } }) } func collectSiteRefs(conf globalconfig.All) error { var refs struct { Meters core.MetersConfig `mapstructure:"meters"` // Meter references Curtailers []string `mapstructure:"curtailers"` // Curtailment device references Other map[string]any `mapstructure:",remain"` } if err := util.DecodeOther(conf.Site, &refs); err != nil { return err } references.meter = append(references.meter, refs.Meters.GridMeterRef) references.meter = append(references.meter, refs.Meters.PVMetersRef...) references.meter = append(references.meter, refs.Meters.BatteryMetersRef...) references.meter = append(references.meter, refs.Meters.ExtMetersRef...) references.meter = append(references.meter, refs.Meters.AuxMetersRef...) references.meter = append(references.meter, refs.Meters.ConsumerMetersRef...) references.curtailer = append(references.curtailer, refs.Curtailers...) // append devices from settings if v, err := settings.String(keys.GridMeter); err == nil && v != "" { references.meter = append(references.meter, v) } for _, key := range []string{keys.PvMeters, keys.BatteryMeters, keys.ExtMeters, keys.AuxMeters, keys.ConsumerMeters} { if v, err := settings.String(key); err == nil && v != "" { references.meter = append(references.meter, strings.Split(v, ",")...) } } if v, err := settings.String(keys.Curtailers); err == nil && v != "" { references.curtailer = append(references.curtailer, strings.Split(v, ",")...) } return nil } func collectTariffRefs() error { // Load tariff device references from settings if !settings.Exists(keys.TariffRefs) { return nil } var refs globalconfig.TariffRefs if err := settings.Json(keys.TariffRefs, &refs); err != nil { return err } // Collect all non-empty refs references.tariff = slices.AppendSeq(references.tariff, refs.Used()) return nil } func collectLoadpointRefs(named iter.Seq[config.Named]) error { for cc := range named { var refs struct { CircuitRef string `mapstructure:"circuit"` // Circuit reference ChargerRef string `mapstructure:"charger"` // Charger reference VehicleRef string `mapstructure:"vehicle"` // Vehicle reference MeterRef string `mapstructure:"meter"` // Charge meter reference Other map[string]any `mapstructure:",remain"` } if err := util.DecodeOther(cc.Other, &refs); err != nil { return err } references.meter = append(references.meter, refs.MeterRef) references.charger = append(references.charger, refs.ChargerRef) references.vehicle = append(references.vehicle, refs.VehicleRef) references.circuit = append(references.circuit, refs.CircuitRef) } return nil } func collectCircuitRefs(circuits []config.Named) error { for _, cc := range circuits { var refs struct { MeterRef string `mapstructure:"meter"` // Circuit meter reference Other map[string]any `mapstructure:",remain"` } if err := util.DecodeOther(cc.Other, &refs); err != nil { return err } references.meter = append(references.meter, refs.MeterRef) } return nil }