Add read-only mode support and enhance logging throughout the application
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2026-02-19 12:36:52 +11:00
parent bdcb8e6f73
commit 1c15ff5911
8 changed files with 281 additions and 33 deletions

View File

@@ -9,8 +9,9 @@ import (
)
type config struct {
Address string `long:"address" env:"ADDRESS" default:":8080" description:"The IP/DNS and port of the machine that the application is running on."`
Data struct {
Address string `long:"address" env:"ADDRESS" default:":8080" description:"The IP/DNS and port of the machine that the application is running on."`
ReadOnly bool `long:"read_only" env:"READ_ONLY" description:"Disable all write operations and run in monitoring-only mode."`
Data struct {
Source string `long:"data.source" env:"DATA_SOURCE" default:"serial" description:"Set the source of data for the inverter gui. \"serial\", \"tcp\" or \"mock\""`
Host string `long:"data.host" env:"DATA_HOST" default:"localhost:8139" description:"Host to connect when source is set to tcp."`
Device string `long:"data.device" env:"DATA_DEVICE" default:"/dev/ttyUSB0" description:"TTY device to use when source is set to serial."`

View File

@@ -55,6 +55,7 @@ var log = logrus.WithField("ctx", "inverter-gui")
func main() {
conf, err := parseConfig()
if err != nil {
log.WithError(err).Error("Could not parse configuration")
os.Exit(1)
}
log.Info("Starting invertergui")
@@ -63,16 +64,33 @@ func main() {
log.Fatalf("Could not parse log level: %v", err)
}
logrus.SetLevel(logLevel)
log.WithFields(logrus.Fields{
"loglevel": conf.Loglevel,
"address": conf.Address,
"read_only": conf.ReadOnly,
"data_source": conf.Data.Source,
"data_host": conf.Data.Host,
"data_device": conf.Data.Device,
"cli_enabled": conf.Cli.Enabled,
"mqtt_enabled": conf.MQTT.Enabled,
"mqtt_broker": conf.MQTT.Broker,
"mqtt_topic": conf.MQTT.Topic,
"mqtt_command_topic": conf.MQTT.CommandTopic,
"mqtt_status_topic": conf.MQTT.StatusTopic,
"mqtt_ha_enabled": conf.MQTT.HA.Enabled,
}).Info("Configuration loaded")
mk2, err := getMk2Device(conf.Data.Source, conf.Data.Host, conf.Data.Device)
if err != nil {
log.Fatalf("Could not open data source: %v", err)
}
defer mk2.Close()
log.Info("MK2 device connection established")
core := mk2core.NewCore(mk2)
if conf.Cli.Enabled {
log.Info("CLI plugin enabled")
cli.NewCli(core.NewSubscription())
}
@@ -80,21 +98,35 @@ func main() {
var writer mk2driver.SettingsWriter
if w, ok := mk2.(mk2driver.SettingsWriter); ok {
writer = w
log.Info("MK2 data source supports settings writes")
} else {
log.Warn("MK2 data source does not support settings writes")
}
if conf.ReadOnly {
if writer != nil {
log.Warn("READ_ONLY enabled; disabling all write operations")
} else {
log.Info("READ_ONLY enabled")
}
writer = nil
}
gui := webui.NewWebGui(core.NewSubscription(), writer)
http.Handle("/", static.New())
http.Handle("/ws", http.HandlerFunc(gui.ServeHub))
http.Handle("/api/remote-panel/state", http.HandlerFunc(gui.ServeRemotePanelState))
http.Handle("/api/remote-panel/standby", http.HandlerFunc(gui.ServeRemotePanelStandby))
log.Info("Web UI routes registered")
// Munin
mu := munin.NewMunin(core.NewSubscription())
http.Handle("/munin", http.HandlerFunc(mu.ServeMuninHTTP))
http.Handle("/muninconfig", http.HandlerFunc(mu.ServeMuninConfigHTTP))
log.Info("Munin routes registered")
// Prometheus
prometheus.NewPrometheus(core.NewSubscription())
http.Handle("/metrics", promhttp.Handler())
log.Info("Prometheus route registered")
// MQTT
if conf.MQTT.Enabled {
@@ -119,6 +151,7 @@ func main() {
if err := mqttclient.New(core.NewSubscription(), writer, mqttConf); err != nil {
log.Fatalf("Could not setup MQTT client: %v", err)
}
log.Info("MQTT client initialized")
}
log.Infof("Invertergui web server starting on: %v", conf.Address)
@@ -134,12 +167,14 @@ func getMk2Device(source, ip, dev string) (mk2driver.Mk2, error) {
switch source {
case "serial":
log.WithField("device", dev).Info("Opening serial MK2 source")
serialConfig := &serial.Config{Name: dev, Baud: 2400}
p, err = serial.OpenPort(serialConfig)
if err != nil {
return nil, err
}
case "tcp":
log.WithField("host", ip).Info("Opening TCP MK2 source")
tcpAddr, err = net.ResolveTCPAddr("tcp", ip)
if err != nil {
return nil, err
@@ -149,6 +184,7 @@ func getMk2Device(source, ip, dev string) (mk2driver.Mk2, error) {
return nil, err
}
case "mock":
log.Info("Using mock MK2 data source")
return mk2driver.NewMk2Mock(), nil
default:
return nil, fmt.Errorf("Invalid source selection: %v\nUse \"serial\", \"tcp\" or \"mock\"", source)
@@ -158,6 +194,7 @@ func getMk2Device(source, ip, dev string) (mk2driver.Mk2, error) {
if err != nil {
return nil, err
}
log.WithField("source", source).Info("MK2 connection ready")
return mk2, nil
}