From 1ccbf4ee03166238ed6fde3f6ba7ac60376a3444 Mon Sep 17 00:00:00 2001 From: KemoNine Date: Sat, 5 Sep 2020 21:27:33 -0400 Subject: [PATCH] Update / adjust config handling code so its more reliable and less prone to crashes ; tweak default values + help text to ensure folks know its only seconds/minutes/hours ; add fim restart handling --- cmd/fan/fan.go | 36 +++++++++++++++++++++++++++--------- cmd/gui/gui.go | 36 ++++++++++++++++-------------------- config/config.go | 19 ++++++++++--------- config/constants.go | 2 +- ui/config.go | 2 +- ui/slideshow.go | 22 ++++++++++++++++++++-- 6 files changed, 75 insertions(+), 42 deletions(-) diff --git a/cmd/fan/fan.go b/cmd/fan/fan.go index d1993a3..e3f0d23 100644 --- a/cmd/fan/fan.go +++ b/cmd/fan/fan.go @@ -22,21 +22,29 @@ func main() { // Load the config file pfConfig, _ := config.LoadConfig() - // For some reason the map isn't populated 'right away' and/or doesn't always come in via koanf - // Work around by re-loading the config as necessary to get valid values - for pfConfig.Float64Map(config.CONFIG_KEY_FAN_SPEEDS)[config.CONFIG_MAP_KEY_FAN_SPEED_100] == 0 { - pfConfig, _ = config.LoadConfig() - } + log.Print("========================================") + pfConfig.Print() + log.Print("========================================") + log.Print(pfConfig.Keys()) + log.Print("========================================") // Get the various fan related config options as local variables speedMap := pfConfig.Float64Map(config.CONFIG_KEY_FAN_SPEEDS) POLL_INTERVAL := pfConfig.String(config.CONFIG_KEY_FAN_POLL_INTERVAL) - SPEED_FULL_TEMP := speedMap[config.CONFIG_MAP_KEY_FAN_SPEED_100] - SPEED_SEVENTY_FIVE_PERCENT_TEMP := speedMap[config.CONFIG_MAP_KEY_FAN_SPEED_75] - SPEED_FIFTY_PERCENT_TEMP := speedMap[config.CONFIG_MAP_KEY_FAN_SPEED_50] - SPEED_TWENTY_FIVE_PERCENT_TEMP := speedMap[config.CONFIG_MAP_KEY_FAN_SPEED_25] + SPEED_FULL_TEMP := pfConfig.Float64(config.CONFIG_KEY_FAN_SPEEDS + "." + config.CONFIG_MAP_KEY_FAN_SPEED_100) + SPEED_SEVENTY_FIVE_PERCENT_TEMP := pfConfig.Float64(config.CONFIG_KEY_FAN_SPEEDS + "." + config.CONFIG_MAP_KEY_FAN_SPEED_75) + SPEED_FIFTY_PERCENT_TEMP := pfConfig.Float64(config.CONFIG_KEY_FAN_SPEEDS + "." + config.CONFIG_MAP_KEY_FAN_SPEED_50) + SPEED_TWENTY_FIVE_PERCENT_TEMP := pfConfig.Float64(config.CONFIG_KEY_FAN_SPEEDS + "." + config.CONFIG_MAP_KEY_FAN_SPEED_25) SPEED_MINIMUM := pfConfig.Int(config.CONFIG_KEY_FAN_MIN_SPEED) + log.Print(speedMap) + log.Print(POLL_INTERVAL) + log.Print(SPEED_FULL_TEMP) + log.Print(SPEED_SEVENTY_FIVE_PERCENT_TEMP) + log.Print(SPEED_FIFTY_PERCENT_TEMP) + log.Print(SPEED_TWENTY_FIVE_PERCENT_TEMP) + log.Print(SPEED_MINIMUM) + // Setup fan and bail if we can't see it fan, err := argonFan.New(ADDRESS, BUS) if err != nil { @@ -71,42 +79,52 @@ func main() { if cpuTemp >= SPEED_FULL_TEMP || gpuTemp >= SPEED_FULL_TEMP { if SPEED_MINIMUM > 100 { + log.Print("MIN speed in 100") fan.SetSpeed(SPEED_MINIMUM) } else { + log.Print("Speed 100%") fan.SetSpeed(100) } continue } if cpuTemp >= SPEED_SEVENTY_FIVE_PERCENT_TEMP || gpuTemp >= SPEED_SEVENTY_FIVE_PERCENT_TEMP { if SPEED_MINIMUM > 75 { + log.Print("MIN speed in 75") fan.SetSpeed(SPEED_MINIMUM) } else { + log.Print("Speed 75%") fan.SetSpeed(75) } continue } if cpuTemp >= SPEED_FIFTY_PERCENT_TEMP || gpuTemp >= SPEED_FIFTY_PERCENT_TEMP { if SPEED_MINIMUM > 50 { + log.Print("MIN speed in 50") fan.SetSpeed(SPEED_MINIMUM) } else { + log.Print("Speed 50%") fan.SetSpeed(50) } continue } if cpuTemp >= SPEED_TWENTY_FIVE_PERCENT_TEMP || gpuTemp >= SPEED_TWENTY_FIVE_PERCENT_TEMP { if SPEED_MINIMUM > 25 { + log.Print("MIN speed in 25") fan.SetSpeed(SPEED_MINIMUM) } else { + log.Print("Speed 25%") fan.SetSpeed(25) } continue } if cpuTemp < SPEED_TWENTY_FIVE_PERCENT_TEMP || gpuTemp < SPEED_TWENTY_FIVE_PERCENT_TEMP { + log.Print("MIN SPEED") fan.SetSpeed(SPEED_MINIMUM) continue } // We should never get here but... // Maxing fan to be on the safe side + log.Print("This should never happen") fan.SetSpeed(100) } } diff --git a/cmd/gui/gui.go b/cmd/gui/gui.go index d03608a..d0c6cf2 100644 --- a/cmd/gui/gui.go +++ b/cmd/gui/gui.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "os" - "time" "github.com/knadh/koanf/providers/confmap" "github.com/knadh/koanf/providers/posflag" @@ -15,6 +14,7 @@ import ( ) func main() { + log.Print("Starting up") // Command line flag handler f := flag.NewFlagSet("piframe", flag.ContinueOnError) f.Usage = func() { @@ -22,6 +22,7 @@ func main() { os.Exit(0) } // Command line flags + log.Print("Setting up CLI flags") f.Bool(config.CLI_FLAG_CONFIG_ONLY, false, "Only show the config UI, NOT the slideshow") cliFlag := f.Lookup(config.CLI_FLAG_CONFIG_ONLY) if cliFlag != nil { @@ -30,30 +31,25 @@ func main() { // Process command line flags into handler f.Parse(os.Args[1:]) + log.Print("Loading config") // Load the config file - pfConfig, configFileProvider := config.LoadConfig() - - // For some reason the restart interval comes through the config as 0s - // Similar to the fan daemon, keep reloading config until we get a valid value - restartDuration := pfConfig.Duration(config.CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL) - for restartDuration.Milliseconds() < 1 { - pfConfig, configFileProvider = config.LoadConfig() - restartDuration = pfConfig.Duration(config.CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL) - } + pfConfig, _ := config.LoadConfig() + log.Printf("%v", pfConfig) + pfConfig.Print() // Watch for config changes and re-load config if needed - configFileProvider.Watch(func(event interface{}, err error) { - if err != nil { - log.Printf("Error setting up watch of config : %s", err) - return - } + // configFileProvider.Watch(func(event interface{}, err error) { + // if err != nil { + // log.Printf("Error setting up watch of config : %s", err) + // return + // } - // Give the config UI a chance to save and exit clean - time.Sleep(time.Minute) + // // Give the config UI a chance to save and exit clean + // time.Sleep(time.Minute) - // Bail on slideshow if there is a config change so it restarts with updated config - log.Fatalf("Config file changed! Exiting!") - }) + // // Bail on slideshow if there is a config change so it restarts with updated config + // log.Fatalf("Config file changed! Exiting!") + // }) // Process command line flags if err := pfConfig.Load(posflag.Provider(f, ".", pfConfig), nil); err != nil { diff --git a/config/config.go b/config/config.go index eee1bde..6e4a88e 100644 --- a/config/config.go +++ b/config/config.go @@ -2,7 +2,6 @@ package config import ( "log" - "os" "github.com/knadh/koanf" "github.com/knadh/koanf/parsers/toml" @@ -25,18 +24,20 @@ func LoadConfig() (*koanf.Koanf, *kfile.File) { CONFIG_KEY_FAN_POLL_INTERVAL: DEFAULT_FAN_POLL_INTERVAL, CONFIG_KEY_FAN_SPEEDS: DEFAULT_FAN_SPEEDS, CONFIG_KEY_FAN_MIN_SPEED: DEFAULT_FAN_MIN_SPEED, - }, "."), nil) + }, ""), nil) // Bring in /etc/defaults/pf.toml if it exists configFileProvider := kfile.Provider(CONFIG_FILE_PATH) - _, err := os.Stat(CONFIG_FILE_PATH) - if os.IsNotExist(err) { - //log.Printf("%s does not exist, USING DEFAULTS", CONFIG_FILE_PATH) - } else { - if errConfigFile := pfConfig.Load(configFileProvider, toml.Parser()); errConfigFile != nil { - log.Fatalf("Error loading config : %s", err) - } + log.Print("========================================") + if err := pfConfig.Load(configFileProvider, toml.Parser()); err != nil { + log.Fatalf("Error loading config : %s", err) } + log.Print("========================================") + + log.Print("========================================") + log.Print("Loaded Config") + pfConfig.Print() + log.Print("========================================") return pfConfig, configFileProvider } diff --git a/config/constants.go b/config/constants.go index b462992..97bcad0 100644 --- a/config/constants.go +++ b/config/constants.go @@ -24,7 +24,7 @@ const ( const ( DEFAULT_SLIDESHOW_INTERVAL = "300s" - DEFAULT_SLIDESHOW_RESTART_INTERVAL = "7d" + DEFAULT_SLIDESHOW_RESTART_INTERVAL = "168h" DEFAULT_HDMI_OFF = "*-*-* 00:00:00" DEFAULT_HDMI_ON = "*-*-* 06:00:00" DEFAULT_ALBUMS_ROOT = "/tank/pictures" diff --git a/ui/config.go b/ui/config.go index cb56f10..4cf4d91 100644 --- a/ui/config.go +++ b/ui/config.go @@ -272,7 +272,7 @@ func ConfigGui(pfconfig *koanf.Koanf) { main.SetTitle("Configure Intervals") main.Clear() main.AddItem(intervalsForm, 0, 1, true) - main.AddItem(tview.NewTextView().SetText("Intervals are a number + letter\n\nUse\ns for seconds\nm for minutes\nh for hours\nd for days\nw for weeks"), 0, 1, false) + main.AddItem(tview.NewTextView().SetText("Intervals are a number + letter\n\nUse\ns for seconds\nm for minutes\nh for hours"), 0, 1, false) app.SetFocus(intervalsForm) } if title == "HDMI On/Off" { diff --git a/ui/slideshow.go b/ui/slideshow.go index b781bfd..6fb5f27 100644 --- a/ui/slideshow.go +++ b/ui/slideshow.go @@ -25,6 +25,7 @@ var fim *exec.Cmd = nil var stdin io.WriteCloser = nil func setupFim(PATH_TEMP_FOR_SLIDESHOW string) { + log.Print("Setting up new fim process") // Prep slideshow command and arguments // NOTE: The random flag is seeded with time() ; this is bad as we will be restarting the slideshow at about the same time per the configurd schedule // We use the non-seeded form to ensure that it's a little more random (or at least hope it's a little more random) @@ -56,6 +57,7 @@ func Slideshow(pfconfig *koanf.Koanf) { // /run is a tmpfs so this won't wear on the sd card storage // Create temp folder + log.Print("Creating temp folder for album selections") _, err := os.Stat(PATH_TEMP_FOR_SLIDESHOW) if os.IsNotExist(err) { errDir := os.MkdirAll(PATH_TEMP_FOR_SLIDESHOW, 0755) @@ -65,6 +67,7 @@ func Slideshow(pfconfig *koanf.Koanf) { } // Cleanup temp folder if it already existed + log.Print("Cleaning up temp folder if it exists") dirRead, err := os.Open(PATH_TEMP_FOR_SLIDESHOW) if err != nil { log.Fatalf("Error setting up slideshow : %s", err) @@ -90,6 +93,7 @@ func Slideshow(pfconfig *koanf.Koanf) { // Setup symlinks to selected albums to be used with slideshow // Add albums full paths to command line args for fim + log.Print("Setting up symlinks to selected albums") albumRootPath := pfconfig.String(config.CONFIG_KEY_ALBUMS_ROOT) for _, album := range pfconfig.Strings(config.CONFIG_KEY_ALBUMS_SELECTED) { source := albumRootPath + album @@ -127,7 +131,13 @@ func Slideshow(pfconfig *koanf.Koanf) { setupFim(PATH_TEMP_FOR_SLIDESHOW) // Advance slideshow every interval as defined in const() - ticker := time.NewTicker(pfconfig.Duration(config.CONFIG_KEY_SLIDESHOW_INTERVAL)) + log.Print("Setting up slideshow advance slide ticker") + slideshowAdvanceDurationString := pfconfig.String(config.CONFIG_KEY_SLIDESHOW_INTERVAL) + slideshowAdvanceDuration, err := time.ParseDuration(slideshowAdvanceDurationString) + if err != nil { + log.Fatalf("Error parsing slide duration : %s", err) + } + ticker := time.NewTicker(slideshowAdvanceDuration) stop_ticker := make(chan struct{}) go func() { for { @@ -162,6 +172,7 @@ func Slideshow(pfconfig *koanf.Koanf) { STOP_SLIDESHOW := false // Goroutine for tracking which keys are pressed and controlling fim if appropriate + log.Print("Setting up keyboard listener") keyboardCtx, keyboardCancel := context.WithCancel(context.Background()) go func(keyboardCtx context.Context) { for { @@ -211,7 +222,13 @@ func Slideshow(pfconfig *koanf.Koanf) { }(keyboardCtx) // Restart fim after configured timeout ; This is setup as a ticker due to KemoNine not getting CommandWithContext stuff to work properly (lots of pointer related crashes and the like) - fimTicker := time.NewTicker(pfconfig.Duration(config.CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL)) + log.Print("Setting up fim restart ticker") + fimRestartDurationString := pfconfig.String(config.CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL) + fimRestartDuration, err := time.ParseDuration(fimRestartDurationString) + if err != nil { + log.Fatalf("Error parsing restart duration : %S", err) + } + fimTicker := time.NewTicker(fimRestartDuration) stop_fim_ticker := make(chan struct{}) go func() { for { @@ -234,6 +251,7 @@ func Slideshow(pfconfig *koanf.Koanf) { // Run fim for !STOP_SLIDESHOW { + log.Print("Top of fim slideshow loop") if err := fim.Run(); err != nil { // Unwrap the error a bit so we can find out if a signal killed fim or something else // An exit code of -1 means the program didn't exit in time or was terminated by a signal (per the docs)