package globalconfig import ( "encoding/json" "iter" "net" "os" "strconv" "strings" "time" "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/charger/ocpp" "github.com/evcc-io/evcc/hems/shm" "github.com/evcc-io/evcc/plugin/mqtt" "github.com/evcc-io/evcc/server/eebus" "github.com/evcc-io/evcc/util" "github.com/evcc-io/evcc/util/config" "github.com/evcc-io/evcc/util/modbus" ) // ConfigStatus for publishing config, status and source to UI and external systems type ConfigStatus struct { Config any `json:"config,omitempty"` Status any `json:"status,omitempty"` YamlSource YamlSource `json:"yamlSource,omitempty"` } type YamlSource string const ( YamlSourceFile YamlSource = "file" YamlSourceDb YamlSource = "db" YamlSourceNone YamlSource = "" ) type All struct { Network Network Ocpp ocpp.Config Log string SponsorToken string Plant string // telemetry plant id Telemetry bool Mcp bool Metrics bool Profile bool Levels map[string]string Interval time.Duration Database DB Mqtt Mqtt ModbusProxy []ModbusProxy Javascript []Javascript Go []Go Influx Influx EEBus eebus.Config HEMS Hems SHM shm.Config Messaging Messaging MessagingEvents MessagingEvents Meters []config.Named Chargers []config.Named Vehicles []config.Named Tariffs Tariffs Site map[string]any Loadpoints []config.Named Circuits []config.Named } type Javascript struct { VM string Script string } type Go struct { VM string Script string } type ModbusProxy struct { Port int `json:"port"` ReadOnly string `yaml:",omitempty" json:"readonly,omitempty"` modbus.Settings `mapstructure:",squash" yaml:",inline,omitempty" json:"settings,omitempty"` } var _ api.Redactor = (*Hems)(nil) type Hems config.Typed func (c Hems) Redacted() any { return struct { Type string `json:"type,omitempty"` }{ Type: c.Type, } } var _ api.Redactor = (*Mqtt)(nil) type Mqtt struct { mqtt.Config `mapstructure:",squash"` Topic string `json:"topic"` } // Redacted implements the redactor interface used by the tee publisher func (m Mqtt) Redacted() any { return Mqtt{ Config: mqtt.Config{ Broker: m.Broker, User: m.User, Password: util.Masked(m.Password), ClientID: m.ClientID, Insecure: m.Insecure, CaCert: util.Masked(m.CaCert), ClientCert: util.Masked(m.ClientCert), ClientKey: util.Masked(m.ClientKey), }, Topic: m.Topic, } } // Influx is the influx db configuration type Influx struct { URL string `json:"url"` Database string `json:"database"` Token string `json:"token"` Org string `json:"org"` User string `json:"user"` Password string `json:"password"` Insecure bool `json:"insecure"` } // Redacted implements the redactor interface used by the tee publisher func (c Influx) Redacted() any { return Influx{ URL: c.URL, Database: c.Database, Token: util.Masked(c.Token), Org: c.Org, User: c.User, Password: util.Masked(c.Password), Insecure: c.Insecure, } } type DB struct { Type string Dsn string } type Messaging struct { Events MessagingEvents Services []config.Typed } type MessagingEvents = map[string]MessagingEventTemplate // MessagingEventTemplate is the push message configuration for an event type MessagingEventTemplate struct { Title string `json:"title"` Msg string `json:"msg"` Disabled bool `json:"disabled"` } func (c Messaging) IsConfigured() bool { return len(c.Services) > 0 || len(c.Events) > 0 } type Tariffs struct { Currency string Grid config.Typed FeedIn config.Typed Co2 config.Typed Planner config.Typed Solar []config.Typed } func (c Tariffs) IsConfigured() bool { return c.Currency != "" || c.Grid.Type != "" || c.FeedIn.Type != "" || c.Co2.Type != "" || c.Planner.Type != "" || len(c.Solar) > 0 } type TariffRefs struct { Grid string `json:"grid"` FeedIn string `json:"feedIn"` Co2 string `json:"co2"` Planner string `json:"planner"` Solar []string `json:"solar"` } func (refs TariffRefs) IsConfigured() bool { return refs.Grid != "" || refs.FeedIn != "" || refs.Co2 != "" || refs.Planner != "" || len(refs.Solar) > 0 } func (refs TariffRefs) Used() iter.Seq[string] { return func(yield func(string) bool) { for _, ref := range append([]string{refs.Grid, refs.FeedIn, refs.Co2, refs.Planner}, refs.Solar...) { if ref != "" { if !yield(ref) { return } } } } } type Network struct { Schema_ string `json:"schema,omitempty" mapstructure:"schema"` // TODO deprecated ExternalUrl string `json:"externalUrl"` Host string `json:"host"` Port int `json:"port"` } func (c Network) HostPort() string { host := "localhost" if h, err := os.Hostname(); err == nil { host = h } if ips := util.LocalIPs(); len(ips) > 0 { host = ips[0].IP.String() } if c.Port == 80 { return host } return net.JoinHostPort(host, strconv.Itoa(c.Port)) } func (c Network) InternalURL() string { return "http://" + c.HostPort() } func (c Network) ExternalURL() string { if c.ExternalUrl != "" { return strings.TrimRight(c.ExternalUrl, "/") } return c.InternalURL() } // MarshalJSON includes the computed InternalUrl field in JSON output func (c Network) MarshalJSON() ([]byte, error) { type networkAlias Network return json.Marshal(struct { networkAlias InternalUrl string `json:"internalUrl"` }{ networkAlias: networkAlias(c), InternalUrl: c.InternalURL(), }) }