implement some features of Venus OS
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jessevdk/go-flags"
|
||||
)
|
||||
@@ -11,7 +12,13 @@ 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."`
|
||||
ReadOnly bool `long:"read_only" env:"READ_ONLY" description:"Disable all write operations and run in monitoring-only mode."`
|
||||
Data struct {
|
||||
Control struct {
|
||||
Profile string `long:"control.profile" env:"CONTROL_PROFILE" default:"normal" description:"Write policy profile: normal, maintenance, or read_only."`
|
||||
MaxCurrentLimit float64 `long:"control.max_current_limit" env:"CONTROL_MAX_CURRENT_LIMIT" default:"0" description:"Optional max AC current limit guardrail in amps (0 disables)."`
|
||||
ModeChangeMinInterval time.Duration `long:"control.mode_change_min_interval" env:"CONTROL_MODE_CHANGE_MIN_INTERVAL" default:"3s" description:"Minimum time between mode changes."`
|
||||
LockoutWindow time.Duration `long:"control.lockout_window" env:"CONTROL_LOCKOUT_WINDOW" default:"0s" description:"Post-command lockout window for command arbitration."`
|
||||
}
|
||||
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."`
|
||||
@@ -26,12 +33,25 @@ type config struct {
|
||||
Topic string `long:"mqtt.topic" env:"MQTT_TOPIC" default:"invertergui/updates" description:"Set the MQTT topic updates published to."`
|
||||
CommandTopic string `long:"mqtt.command_topic" env:"MQTT_COMMAND_TOPIC" default:"invertergui/settings/set" description:"Set the MQTT topic that receives write commands for Victron settings/RAM variables."`
|
||||
StatusTopic string `long:"mqtt.status_topic" env:"MQTT_STATUS_TOPIC" default:"invertergui/settings/status" description:"Set the MQTT topic where write command status updates are published."`
|
||||
DeviceID string `long:"mqtt.device_id" env:"MQTT_DEVICE_ID" default:"invertergui" description:"Set the logical device ID used for per-device orchestration topics."`
|
||||
HistorySize int `long:"mqtt.history_size" env:"MQTT_HISTORY_SIZE" default:"120" description:"Number of telemetry samples retained for rolling history summaries."`
|
||||
InstanceID int `long:"mqtt.instance_id" env:"MQTT_INSTANCE_ID" default:"0" description:"Device instance ID for multi-device orchestration and Venus compatibility."`
|
||||
Phase string `long:"mqtt.phase" env:"MQTT_PHASE" default:"L1" description:"Electrical phase label for this instance (L1/L2/L3)."`
|
||||
PhaseGroup string `long:"mqtt.phase_group" env:"MQTT_PHASE_GROUP" default:"default" description:"Grouping key for parallel/3-phase system aggregation topics."`
|
||||
HA struct {
|
||||
Enabled bool `long:"mqtt.ha.enabled" env:"MQTT_HA_ENABLED" description:"Enable Home Assistant MQTT discovery integration."`
|
||||
DiscoveryPrefix string `long:"mqtt.ha.discovery_prefix" env:"MQTT_HA_DISCOVERY_PREFIX" default:"homeassistant" description:"Set Home Assistant MQTT discovery prefix."`
|
||||
NodeID string `long:"mqtt.ha.node_id" env:"MQTT_HA_NODE_ID" default:"invertergui" description:"Set Home Assistant node ID used for discovery topics and unique IDs."`
|
||||
DeviceName string `long:"mqtt.ha.device_name" env:"MQTT_HA_DEVICE_NAME" default:"Victron Inverter" description:"Set Home Assistant device display name."`
|
||||
}
|
||||
Venus struct {
|
||||
Enabled bool `long:"mqtt.venus.enabled" env:"MQTT_VENUS_ENABLED" description:"Enable Venus-style MQTT compatibility topics (N/W topic model)."`
|
||||
PortalID string `long:"mqtt.venus.portal_id" env:"MQTT_VENUS_PORTAL_ID" default:"invertergui" description:"Set Venus portal ID segment used in N/W topics."`
|
||||
Service string `long:"mqtt.venus.service" env:"MQTT_VENUS_SERVICE" default:"vebus/257" description:"Set Venus service segment used in N/W topics."`
|
||||
SubscribeWrites bool `long:"mqtt.venus.subscribe_writes" env:"MQTT_VENUS_SUBSCRIBE_WRITES" default:"true" description:"Subscribe to Venus write topics and map them to MK2 control commands."`
|
||||
TopicPrefix string `long:"mqtt.venus.topic_prefix" env:"MQTT_VENUS_TOPIC_PREFIX" default:"" description:"Optional topic prefix before Venus N/W topics, for example 'victron'."`
|
||||
GuideCompat bool `long:"mqtt.venus.guide_compat" env:"MQTT_VENUS_GUIDE_COMPAT" default:"true" description:"Enable guide-style settings/0/Settings/CGwacs compatibility paths for Home Assistant controls."`
|
||||
}
|
||||
Username string `long:"mqtt.username" env:"MQTT_USERNAME" default:"" description:"Set the MQTT username"`
|
||||
Password string `long:"mqtt.password" env:"MQTT_PASSWORD" default:"" description:"Set the MQTT password"`
|
||||
PasswordFile string `long:"mqtt.password-file" env:"MQTT_PASSWORD_FILE" default:"" description:"Path to a file containing the MQTT password"`
|
||||
|
||||
@@ -36,6 +36,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.coadcorp.com/nathan/invertergui/mk2core"
|
||||
"git.coadcorp.com/nathan/invertergui/mk2driver"
|
||||
@@ -77,7 +78,15 @@ func main() {
|
||||
"mqtt_topic": conf.MQTT.Topic,
|
||||
"mqtt_command_topic": conf.MQTT.CommandTopic,
|
||||
"mqtt_status_topic": conf.MQTT.StatusTopic,
|
||||
"mqtt_device_id": conf.MQTT.DeviceID,
|
||||
"mqtt_history_size": conf.MQTT.HistorySize,
|
||||
"mqtt_ha_enabled": conf.MQTT.HA.Enabled,
|
||||
"mqtt_venus_enabled": conf.MQTT.Venus.Enabled,
|
||||
"mqtt_venus_portal": conf.MQTT.Venus.PortalID,
|
||||
"mqtt_venus_service": conf.MQTT.Venus.Service,
|
||||
"mqtt_venus_prefix": conf.MQTT.Venus.TopicPrefix,
|
||||
"mqtt_venus_guide": conf.MQTT.Venus.GuideCompat,
|
||||
"control_profile": conf.Control.Profile,
|
||||
}).Info("Configuration loaded")
|
||||
|
||||
mk2, err := getMk2Device(conf.Data.Source, conf.Data.Host, conf.Data.Device)
|
||||
@@ -109,6 +118,36 @@ func main() {
|
||||
log.Info("READ_ONLY enabled")
|
||||
}
|
||||
writer = nil
|
||||
} else if writer != nil {
|
||||
policyProfile := mk2driver.WriterProfile(strings.ToLower(strings.TrimSpace(conf.Control.Profile)))
|
||||
if policyProfile == "" {
|
||||
policyProfile = mk2driver.WriterProfileNormal
|
||||
}
|
||||
if policyProfile != mk2driver.WriterProfileNormal &&
|
||||
policyProfile != mk2driver.WriterProfileMaintenance &&
|
||||
policyProfile != mk2driver.WriterProfileReadOnly {
|
||||
log.WithField("profile", conf.Control.Profile).Warn("Unknown control profile; defaulting to normal")
|
||||
policyProfile = mk2driver.WriterProfileNormal
|
||||
}
|
||||
|
||||
var maxCurrentLimit *float64
|
||||
if conf.Control.MaxCurrentLimit > 0 {
|
||||
limit := conf.Control.MaxCurrentLimit
|
||||
maxCurrentLimit = &limit
|
||||
}
|
||||
|
||||
writer = mk2driver.NewManagedWriter(writer, mk2driver.WriterPolicy{
|
||||
Profile: policyProfile,
|
||||
MaxCurrentLimitA: maxCurrentLimit,
|
||||
ModeChangeMinInterval: conf.Control.ModeChangeMinInterval,
|
||||
LockoutWindow: conf.Control.LockoutWindow,
|
||||
})
|
||||
log.WithFields(logrus.Fields{
|
||||
"profile": policyProfile,
|
||||
"max_current_limit": conf.Control.MaxCurrentLimit,
|
||||
"mode_change_min_interval": conf.Control.ModeChangeMinInterval,
|
||||
"lockout_window": conf.Control.LockoutWindow,
|
||||
}).Info("Write policy/arbitration layer enabled")
|
||||
}
|
||||
gui := webui.NewWebGui(core.NewSubscription(), writer)
|
||||
http.Handle("/", static.New())
|
||||
@@ -136,12 +175,25 @@ func main() {
|
||||
CommandTopic: conf.MQTT.CommandTopic,
|
||||
StatusTopic: conf.MQTT.StatusTopic,
|
||||
ClientID: conf.MQTT.ClientID,
|
||||
DeviceID: conf.MQTT.DeviceID,
|
||||
HistorySize: conf.MQTT.HistorySize,
|
||||
InstanceID: conf.MQTT.InstanceID,
|
||||
Phase: conf.MQTT.Phase,
|
||||
PhaseGroup: conf.MQTT.PhaseGroup,
|
||||
HomeAssistant: mqttclient.HomeAssistantConfig{
|
||||
Enabled: conf.MQTT.HA.Enabled,
|
||||
DiscoveryPrefix: conf.MQTT.HA.DiscoveryPrefix,
|
||||
NodeID: conf.MQTT.HA.NodeID,
|
||||
DeviceName: conf.MQTT.HA.DeviceName,
|
||||
},
|
||||
Venus: mqttclient.VenusConfig{
|
||||
Enabled: conf.MQTT.Venus.Enabled,
|
||||
PortalID: conf.MQTT.Venus.PortalID,
|
||||
Service: conf.MQTT.Venus.Service,
|
||||
SubscribeWrites: conf.MQTT.Venus.SubscribeWrites,
|
||||
TopicPrefix: conf.MQTT.Venus.TopicPrefix,
|
||||
GuideCompat: conf.MQTT.Venus.GuideCompat,
|
||||
},
|
||||
Username: conf.MQTT.Username,
|
||||
Password: conf.MQTT.Password,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user