Config UI: allow repairing broken loadpoints and site (#22671)
This commit is contained in:
parent
3a80e9b3ee
commit
97189dc789
22 changed files with 412 additions and 197 deletions
|
|
@ -94,6 +94,18 @@ func shutdownDoneC() <-chan struct{} {
|
|||
return doneC
|
||||
}
|
||||
|
||||
// joinErrors is like errors.Join but does not wrap single errors (refs https://groups.google.com/g/golang-nuts/c/N0D1g5Ec_ZU)
|
||||
func joinErrors(errs ...error) error {
|
||||
switch len(errs) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return errs[0]
|
||||
default:
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
}
|
||||
|
||||
func wrapFatalError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -355,9 +355,11 @@ func runRoot(cmd *cobra.Command, args []string) {
|
|||
}
|
||||
|
||||
if err != nil {
|
||||
// improve error message
|
||||
err = wrapFatalError(err)
|
||||
valueChan <- util.Param{Key: keys.Fatal, Val: err}
|
||||
if uw, ok := err.(interface{ Unwrap() []error }); ok {
|
||||
valueChan <- util.Param{Key: keys.Fatal, Val: uw.Unwrap()}
|
||||
} else {
|
||||
valueChan <- util.Param{Key: keys.Fatal, Val: []error{wrapFatalError(err)}}
|
||||
}
|
||||
|
||||
// TODO stop reboot loop if user updates config (or show countdown in UI)
|
||||
log.FATAL.Println(err)
|
||||
|
|
|
|||
52
cmd/setup.go
52
cmd/setup.go
|
|
@ -914,20 +914,26 @@ func configureDevices(conf globalconfig.All) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// TODO: add name/identifier to error for better highlighting in UI
|
||||
// make sure all devices are configured
|
||||
var errs []error
|
||||
|
||||
if err := configureMeters(conf.Meters, references.meter...); err != nil {
|
||||
return &ClassError{ClassMeter, err}
|
||||
errs = append(errs, &ClassError{ClassMeter, err})
|
||||
}
|
||||
|
||||
if err := configureChargers(conf.Chargers, references.charger...); err != nil {
|
||||
return &ClassError{ClassCharger, err}
|
||||
errs = append(errs, &ClassError{ClassCharger, err})
|
||||
}
|
||||
|
||||
if err := configureVehicles(conf.Vehicles); err != nil {
|
||||
return &ClassError{ClassVehicle, err}
|
||||
errs = append(errs, &ClassError{ClassVehicle, err})
|
||||
}
|
||||
|
||||
if err := configureCircuits(&conf.Circuits); err != nil {
|
||||
return &ClassError{ClassCircuit, err}
|
||||
errs = append(errs, &ClassError{ClassCircuit, err})
|
||||
}
|
||||
return nil
|
||||
|
||||
return joinErrors(errs...)
|
||||
}
|
||||
|
||||
func configureModbusProxy(conf *[]globalconfig.ModbusProxy) error {
|
||||
|
|
@ -962,38 +968,39 @@ func configureSiteAndLoadpoints(conf *globalconfig.All) (*core.Site, error) {
|
|||
return nil, err
|
||||
}
|
||||
conf.Interval = time.Duration(d)
|
||||
|
||||
// TODO remove yaml file
|
||||
// } else if conf.Interval != 0 {
|
||||
// settings.SetInt(keys.Interval, int64(conf.Interval))
|
||||
}
|
||||
|
||||
var errs []error
|
||||
|
||||
if err := configureDevices(*conf); err != nil {
|
||||
return nil, err
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
if err := configureLoadpoints(*conf); err != nil {
|
||||
return nil, &ClassError{ClassLoadpoint, err}
|
||||
errs = append(errs, &ClassError{ClassLoadpoint, err})
|
||||
}
|
||||
|
||||
tariffs, err := configureTariffs(&conf.Tariffs)
|
||||
if err != nil {
|
||||
return nil, &ClassError{ClassTariff, err}
|
||||
errs = append(errs, &ClassError{ClassTariff, err})
|
||||
}
|
||||
|
||||
loadpoints := lo.Map(config.Loadpoints().Devices(), func(dev config.Device[loadpoint.API], _ int) *core.Loadpoint {
|
||||
lp := dev.Instance()
|
||||
return lp.(*core.Loadpoint)
|
||||
return dev.Instance().(*core.Loadpoint)
|
||||
})
|
||||
|
||||
site, err := configureSite(conf.Site, loadpoints, tariffs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return site, joinErrors(errs...)
|
||||
}
|
||||
|
||||
if len(config.Circuits().Devices()) > 0 {
|
||||
if err := validateCircuits(loadpoints); err != nil {
|
||||
return nil, &ClassError{ClassCircuit, err}
|
||||
return site, &ClassError{ClassCircuit, err}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1037,11 +1044,11 @@ CONTINUE:
|
|||
func configureSite(conf map[string]interface{}, loadpoints []*core.Loadpoint, tariffs *tariff.Tariffs) (*core.Site, error) {
|
||||
site, err := core.NewSiteFromConfig(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return site, err
|
||||
}
|
||||
|
||||
if err := site.Boot(log, loadpoints, tariffs); err != nil {
|
||||
return nil, fmt.Errorf("failed configuring site: %w", err)
|
||||
return site, fmt.Errorf("failed booting site: %w", err)
|
||||
}
|
||||
|
||||
return site, nil
|
||||
|
|
@ -1094,8 +1101,11 @@ func configureLoadpoints(conf globalconfig.All) error {
|
|||
err = &DeviceError{cc.Name, e}
|
||||
}
|
||||
|
||||
if e := dynamic.Apply(instance); e != nil && err == nil {
|
||||
err = &DeviceError{cc.Name, e}
|
||||
if instance != nil {
|
||||
// ignore dynamic config in case of startup errors that will leave instance empty
|
||||
if e := dynamic.Apply(instance); e != nil && err == nil {
|
||||
err = &DeviceError{cc.Name, e}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@ func (suite *circuitsTestSuite) SetupTest() {
|
|||
config.Reset()
|
||||
}
|
||||
|
||||
func (suite *circuitsTestSuite) charger() api.Charger {
|
||||
return api.NewMockCharger(gomock.NewController(suite.T()))
|
||||
}
|
||||
|
||||
func (suite *circuitsTestSuite) TestCircuitConf() {
|
||||
var conf globalconfig.All
|
||||
viper.SetConfigType("yaml")
|
||||
|
|
@ -58,7 +62,7 @@ loadpoints:
|
|||
// empty charger
|
||||
suite.Require().NoError(config.Chargers().Add(config.NewStaticDevice(config.Named{
|
||||
Name: "test",
|
||||
}, api.Charger(nil))))
|
||||
}, suite.charger())))
|
||||
|
||||
err := configureLoadpoints(conf)
|
||||
suite.Require().NoError(err)
|
||||
|
|
@ -89,7 +93,7 @@ loadpoints:
|
|||
// empty charger
|
||||
suite.Require().NoError(config.Chargers().Add(config.NewStaticDevice(config.Named{
|
||||
Name: "test",
|
||||
}, api.Charger(nil))))
|
||||
}, suite.charger())))
|
||||
|
||||
err := configureLoadpoints(conf)
|
||||
suite.Require().NoError(err)
|
||||
|
|
@ -146,7 +150,7 @@ loadpoints:
|
|||
// mock charger
|
||||
suite.Require().NoError(config.Chargers().Add(config.NewStaticDevice(config.Named{
|
||||
Name: "test",
|
||||
}, api.Charger(nil))))
|
||||
}, suite.charger())))
|
||||
|
||||
err := configureLoadpoints(conf)
|
||||
suite.Require().NoError(err)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue