diff --git a/cmd/fermentord/gpio.go b/cmd/fermentord/gpio.go index 0d88e91..8f876d3 100644 --- a/cmd/fermentord/gpio.go +++ b/cmd/fermentord/gpio.go @@ -9,7 +9,7 @@ import ( "git.joco.dk/sng/fermentord/internal/metrics" ) -func gpioSetState(state controllers.ChamberState, gpio *hw.Gpio, config *configuration.Configuration) { +func gpioSetState(state controllers.ChamberState, gpio *hw.Gpio, config configuration.Configuration) { switch state { case controllers.ChamberStateIdle: log.Printf("Setting chamber state idle") diff --git a/cmd/fermentord/loop.go b/cmd/fermentord/loop.go index 72fd58f..272f499 100644 --- a/cmd/fermentord/loop.go +++ b/cmd/fermentord/loop.go @@ -19,7 +19,7 @@ import ( "github.com/spf13/viper" ) -func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config *configuration.Configuration) { +func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream) { defer wg.Done() hub := sentry.CurrentHub().Clone() @@ -34,12 +34,14 @@ func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config defer display.Close() // Controller - ctrl := controllers.NewChamberController(*config) + config := configuration.Global() + ctrl := controllers.NewChamberController(config) // Configuration reload loadConfiguration := func() { - temperature.ConfigUpdate <- *config - ctrl.ConfigUpdates <- *config + cfg := configuration.Global() + temperature.ConfigUpdate <- cfg + ctrl.ConfigUpdates <- cfg //display.SetSetpointTemp(config.FermentationTemperature) } diff --git a/cmd/fermentord/main.go b/cmd/fermentord/main.go index 0adecce..8c0f262 100644 --- a/cmd/fermentord/main.go +++ b/cmd/fermentord/main.go @@ -29,9 +29,10 @@ func main() { defer sentry.Flush(10 * time.Second) // Configuration - config := configuration.LoadConfiguration() + configuration.LoadConfiguration() // NATS + config := configuration.Global() servers := strings.Join(config.NATS.Servers, ",") userInfo := nats.UserInfo(config.NATS.Username, config.NATS.Password) nc, err := nats.Connect(servers, userInfo) @@ -61,7 +62,7 @@ func main() { wg := &sync.WaitGroup{} wg.Add(1) - go mainLoop(ctx, wg, js, config) + go mainLoop(ctx, wg, js) go srv.ListenAndServe() diff --git a/internal/configuration/config.go b/internal/configuration/config.go index f6db64b..9759cf1 100644 --- a/internal/configuration/config.go +++ b/internal/configuration/config.go @@ -2,78 +2,30 @@ package configuration import ( "log" + "sync" "github.com/getsentry/sentry-go" "github.com/spf13/viper" ) -type Configuration struct { - NATS struct { - Servers []string `mapstructure:"servers"` - Username string `mapstructure:"username"` - Password string `mapstructure:"password"` - Stream string `mapstructure:"stream"` - Subject struct { - Event string `mapstructure:"event"` - State string `mapstructure:"state"` - Temp string `mapstructure:"temp"` - Tilt string `mapstructure:"tilt"` - } `mapstructure:"subject"` - } `mapstructure:"nats"` +var ( + globalConfig Configuration + globalLock *sync.Mutex +) - HTTP struct { - Port int16 `mapstructure:"port"` - } `mapstructure:"http"` - - Sensors struct { - Wort string `mapstructure:"wort"` - Chamber string `mapstructure:"chamber"` - Ambient string `mapstructure:"ambient"` - Weight float64 `mapstructure:"weight"` - } `mapstructure:"sensors"` - - FermentationTemperature float64 `mapstructure:"fermentation_temp"` - DeltaTemperatureCool float64 `mapstructure:"delta_temp_cool"` - DeltaTemperatureHeat float64 `mapstructure:"delta_temp_heat"` - HeaterEnabled bool `mapstructure:"heater_enabled"` - CoolerEnabled bool `mapstructure:"cooler_enabled"` - - Limits struct { - MinChamberTemperature float64 `mapstructure:"min_chamber_temp"` - MaxChamberTemperature float64 `mapstructure:"max_chamber_temp"` - MinCoolerRuntimeSecs float64 `mapstructure:"min_cooler_runtime_secs"` - MaxCoolerRuntimeSecs float64 `mapstructure:"max_cooler_runtime_secs"` - MinCoolerCooldownSecs float64 `mapstructure:"min_cooler_cooldown_secs"` - HeaterGraceTimeSecs float64 `mapstructure:"heater_grace_time_secs"` - } `mapstructure:"limits"` - - PID struct { - Kp float64 `mapstructure:"kp"` // 2.0 - Ki float64 `mapstructure:"ki"` // 0.0001 - Kd float64 `mapstructure:"kd"` // 2.0 - } `mapstructure:"pid"` +func init() { + globalLock = &sync.Mutex{} } -func LoadConfiguration() *Configuration { - viper.SetDefault("cooler_enabled", true) - viper.SetDefault("heater_enabled", true) - viper.SetDefault("http.port", 8000) - viper.SetDefault("nats.stream", "DWJONDAHL") - viper.SetDefault("nats.subject.event", "DWJONDAHL.ingest.fermentor.ingest_event") - viper.SetDefault("nats.subject.state", "DWJONDAHL.ingest.fermentor.ingest_state") - viper.SetDefault("nats.subject.temp", "DWJONDAHL.ingest.fermentor.ingest_temperature_reading") - viper.SetDefault("nats.subject.tilt", "DWJONDAHL.ingest.fermentor.ingest_tilt_reading") - viper.SetDefault("nats.url", "nats.service.consul") - viper.SetDefault("pid.kd", 2.0) - viper.SetDefault("pid.ki", 0.0001) - viper.SetDefault("pid.kp", 2.0) - viper.SetDefault("limits.heater_grace_time_secs", 1800) - viper.SetDefault("limits.max_chamber_temp", 40) - viper.SetDefault("limits.max_cooler_runtime_secs", 86400) - viper.SetDefault("limits.min_chamber_temp", 5) - viper.SetDefault("limits.min_cooler_cooldown_secs", 300) - viper.SetDefault("limits.min_cooler_runtime_secs", 300) - viper.SetDefault("sensors.weight", 0.8) +func Global() (c Configuration) { + globalLock.Lock() + c = globalConfig + globalLock.Unlock() + return +} + +func LoadConfiguration() { + setDefaults() viper.AddConfigPath("/etc") viper.AddConfigPath("/usr/local/etc") @@ -91,5 +43,7 @@ func LoadConfiguration() *Configuration { log.Fatal(err) } - return config + globalLock.Lock() + globalConfig = *config + globalLock.Unlock() } diff --git a/internal/configuration/global.go b/internal/configuration/global.go new file mode 100644 index 0000000..9229dba --- /dev/null +++ b/internal/configuration/global.go @@ -0,0 +1,72 @@ +package configuration + +import "github.com/spf13/viper" + +type Configuration struct { + NATS struct { + Servers []string `mapstructure:"servers"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` + Stream string `mapstructure:"stream"` + Subject struct { + Event string `mapstructure:"event"` + State string `mapstructure:"state"` + Temp string `mapstructure:"temp"` + Tilt string `mapstructure:"tilt"` + } `mapstructure:"subject"` + } `mapstructure:"nats"` + + HTTP struct { + Port int16 `mapstructure:"port"` + } `mapstructure:"http"` + + Sensors struct { + Wort string `mapstructure:"wort"` + Chamber string `mapstructure:"chamber"` + Ambient string `mapstructure:"ambient"` + Weight float64 `mapstructure:"weight"` + } `mapstructure:"sensors"` + + FermentationTemperature float64 `mapstructure:"fermentation_temp"` + DeltaTemperatureCool float64 `mapstructure:"delta_temp_cool"` + DeltaTemperatureHeat float64 `mapstructure:"delta_temp_heat"` + HeaterEnabled bool `mapstructure:"heater_enabled"` + CoolerEnabled bool `mapstructure:"cooler_enabled"` + + Limits struct { + MinChamberTemperature float64 `mapstructure:"min_chamber_temp"` + MaxChamberTemperature float64 `mapstructure:"max_chamber_temp"` + MinCoolerRuntimeSecs float64 `mapstructure:"min_cooler_runtime_secs"` + MaxCoolerRuntimeSecs float64 `mapstructure:"max_cooler_runtime_secs"` + MinCoolerCooldownSecs float64 `mapstructure:"min_cooler_cooldown_secs"` + HeaterGraceTimeSecs float64 `mapstructure:"heater_grace_time_secs"` + } `mapstructure:"limits"` + + PID struct { + Kp float64 `mapstructure:"kp"` // 2.0 + Ki float64 `mapstructure:"ki"` // 0.0001 + Kd float64 `mapstructure:"kd"` // 2.0 + } `mapstructure:"pid"` +} + +func setDefaults() { + viper.SetDefault("cooler_enabled", true) + viper.SetDefault("heater_enabled", true) + viper.SetDefault("http.port", 8000) + viper.SetDefault("nats.stream", "DWJONDAHL") + viper.SetDefault("nats.subject.event", "DWJONDAHL.ingest.fermentor.ingest_event") + viper.SetDefault("nats.subject.state", "DWJONDAHL.ingest.fermentor.ingest_state") + viper.SetDefault("nats.subject.temp", "DWJONDAHL.ingest.fermentor.ingest_temperature_reading") + viper.SetDefault("nats.subject.tilt", "DWJONDAHL.ingest.fermentor.ingest_tilt_reading") + viper.SetDefault("nats.url", "nats.service.consul") + viper.SetDefault("pid.kd", 2.0) + viper.SetDefault("pid.ki", 0.0001) + viper.SetDefault("pid.kp", 2.0) + viper.SetDefault("limits.heater_grace_time_secs", 1800) + viper.SetDefault("limits.max_chamber_temp", 40) + viper.SetDefault("limits.max_cooler_runtime_secs", 86400) + viper.SetDefault("limits.min_chamber_temp", 5) + viper.SetDefault("limits.min_cooler_cooldown_secs", 300) + viper.SetDefault("limits.min_cooler_runtime_secs", 300) + viper.SetDefault("sensors.weight", 0.8) +} diff --git a/internal/controllers/chamber.go b/internal/controllers/chamber.go index 542a6ff..b078a14 100644 --- a/internal/controllers/chamber.go +++ b/internal/controllers/chamber.go @@ -86,6 +86,7 @@ func (p *ChamberController) Run(ctx context.Context, wg *sync.WaitGroup) { case c := <-p.ConfigUpdates: p.config = c + log.Printf("Fermentation temperature set to %v", p.config.FermentationTemperature) case <-ctx.Done(): ticker.Stop() diff --git a/internal/dwingest/nats.go b/internal/dwingest/nats.go index 95fe392..3c86947 100644 --- a/internal/dwingest/nats.go +++ b/internal/dwingest/nats.go @@ -59,7 +59,7 @@ func (p *DWIngest) AddState(state controllers.ChamberState) { } } -func (p *DWIngest) Run(ctx context.Context, wg *sync.WaitGroup, config *configuration.Configuration) { +func (p *DWIngest) Run(ctx context.Context, wg *sync.WaitGroup, config configuration.Configuration) { defer wg.Done() defer p.hub.Flush(10 * time.Second)