evcc-io/api/globalconfig/types.go
2026-08-11 09:59:37 +02:00

249 lines
5.8 KiB
Go

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 // TODO deprecated
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"`
}
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
Temperature 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 || c.Temperature.Type != ""
}
type TariffRefs struct {
Grid string `json:"grid"`
FeedIn string `json:"feedIn"`
Co2 string `json:"co2"`
Planner string `json:"planner"`
Solar []string `json:"solar"`
Temperature string `json:"temperature"`
}
func (refs TariffRefs) IsConfigured() bool {
return refs.Grid != "" || refs.FeedIn != "" || refs.Co2 != "" || refs.Planner != "" || len(refs.Solar) > 0 || refs.Temperature != ""
}
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.Temperature}, 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(),
})
}