Further implementation of config management

This commit is contained in:
KemoNine 2020-09-03 21:01:13 -04:00
parent 1b5d77e07a
commit fffd67f8c0
5 changed files with 117 additions and 62 deletions

View file

@ -9,7 +9,8 @@ The GUI will work off a config similar to the following. Use the ```generate con
``` ```
[slideshow] [slideshow]
duration = "300s" slideinterval = "300s"
restartinterval = "7d"
[hdmi] [hdmi]
# These are SYSTEMD.TIME formatted times # These are SYSTEMD.TIME formatted times

View file

@ -15,27 +15,6 @@ import (
"git.kemonine.info/PiFrame/ui" "git.kemonine.info/PiFrame/ui"
) )
const (
CLI_FLAG_CONFIG_ONLY = "config-ui-only"
)
const (
CONFIG_FILE_PATH = "/etc/default/pf.toml"
CONFIG_KEY_SLIDESHOW_DURATION = "slideshow.duration"
CONFIG_KEY_HDMI_OFF = "hdmi.off"
CONFIG_KEY_HDMI_ON = "hdmi.on"
CONFIG_KEY_ALBUMS_ROOT = "albums.root"
CONFIG_KEY_ALBUMS_SELECTED = "albums.selected"
)
const (
DEFAULT_SLIDESHOW_DURATION = "300s"
DEFAULT_HDMI_OFF = "*-*-* 00:00:00"
DEFAULT_HDMI_ON = "*-*-* 06:00:00"
DEFAULT_ALBUMS_ROOT = "/tank/pictures"
DEFAULT_ALBUM_SELECTED = "/"
)
func main() { func main() {
// Command line flag handler // Command line flag handler
f := flag.NewFlagSet("piframe", flag.ContinueOnError) f := flag.NewFlagSet("piframe", flag.ContinueOnError)
@ -44,8 +23,8 @@ func main() {
os.Exit(0) os.Exit(0)
} }
// Command line flags // Command line flags
f.Bool(CLI_FLAG_CONFIG_ONLY, false, "Only show the config UI, NOT the slideshow") f.Bool(ui.CLI_FLAG_CONFIG_ONLY, false, "Only show the config UI, NOT the slideshow")
cliFlag := f.Lookup(CLI_FLAG_CONFIG_ONLY) cliFlag := f.Lookup(ui.CLI_FLAG_CONFIG_ONLY)
if cliFlag != nil { if cliFlag != nil {
cliFlag.NoOptDefVal = "true" cliFlag.NoOptDefVal = "true"
} }
@ -57,25 +36,24 @@ func main() {
// Setup some defaults // Setup some defaults
pfConfig.Load(confmap.Provider(map[string]interface{}{ pfConfig.Load(confmap.Provider(map[string]interface{}{
CONFIG_KEY_SLIDESHOW_DURATION: DEFAULT_SLIDESHOW_DURATION, ui.CONFIG_KEY_SLIDESHOW_INTERVAL: ui.DEFAULT_SLIDESHOW_INTERVAL,
CONFIG_KEY_HDMI_OFF: DEFAULT_HDMI_OFF, ui.CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL: ui.DEFAULT_SLIDESHOW_RESTART_INTERVAL,
CONFIG_KEY_HDMI_ON: DEFAULT_HDMI_ON, ui.CONFIG_KEY_HDMI_OFF: ui.DEFAULT_HDMI_OFF,
CONFIG_KEY_ALBUMS_ROOT: DEFAULT_ALBUMS_ROOT, ui.CONFIG_KEY_HDMI_ON: ui.DEFAULT_HDMI_ON,
CONFIG_KEY_ALBUMS_SELECTED: []string{DEFAULT_ALBUM_SELECTED}, ui.CONFIG_KEY_ALBUMS_ROOT: ui.DEFAULT_ALBUMS_ROOT,
ui.CONFIG_KEY_ALBUMS_SELECTED: []string{ui.DEFAULT_ALBUM_SELECTED},
}, "."), nil) }, "."), nil)
// Bring in /etc/defaults/pf.toml if it exists // Bring in /etc/defaults/pf.toml if it exists
configFileProvider := file.Provider(CONFIG_FILE_PATH) configFileProvider := file.Provider(ui.CONFIG_FILE_PATH)
_, err := os.Stat(CONFIG_FILE_PATH) _, err := os.Stat(ui.CONFIG_FILE_PATH)
if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
// log.Printf("%s does not exist, USING DEFAULTS", CONFIG_FILE_PATH) //log.Printf("%s does not exist, USING DEFAULTS", ui.CONFIG_FILE_PATH)
} else { } else {
if errConfigFile := pfConfig.Load(configFileProvider, toml.Parser()); errConfigFile != nil { if errConfigFile := pfConfig.Load(configFileProvider, toml.Parser()); errConfigFile != nil {
log.Fatalf("Error loading config : %s", err) log.Fatalf("Error loading config : %s", err)
} }
} }
}
// Watch for config changes and re-load config if needed // Watch for config changes and re-load config if needed
configFileProvider.Watch(func(event interface{}, err error) { configFileProvider.Watch(func(event interface{}, err error) {
@ -92,9 +70,9 @@ func main() {
log.Fatalf("Error loading command line flags : %s", err) log.Fatalf("Error loading command line flags : %s", err)
} }
if !pfConfig.Bool(CLI_FLAG_CONFIG_ONLY) { if !pfConfig.Bool(ui.CLI_FLAG_CONFIG_ONLY) {
ui.Slideshow() ui.Slideshow(pfConfig)
} }
ui.ConfigGui() ui.ConfigGui(pfConfig)
} }

View file

@ -14,6 +14,7 @@ import (
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
"github.com/guillermo/go.procmeminfo" "github.com/guillermo/go.procmeminfo"
"github.com/knadh/koanf"
"github.com/rivo/tview" "github.com/rivo/tview"
"git.kemonine.info/PiFrame/wifi" "git.kemonine.info/PiFrame/wifi"
@ -24,7 +25,6 @@ const (
CMD_FINDMNT = "/usr/bin/findmnt" CMD_FINDMNT = "/usr/bin/findmnt"
CMD_VCGENCMD = "/opt/vc/bin/vcgencmd" CMD_VCGENCMD = "/opt/vc/bin/vcgencmd"
FILE_CPU_TEMP = "/sys/class/thermal/thermal_zone0/temp" FILE_CPU_TEMP = "/sys/class/thermal/thermal_zone0/temp"
ALBUM_ROOT_DIR = "/tank/pictures/"
SYNCTHING_FOLDER_SKIP = ".stfolder" SYNCTHING_FOLDER_SKIP = ".stfolder"
) )
@ -35,7 +35,7 @@ const (
PAGE_POWEROFF = "PAGE_POWEROFF" PAGE_POWEROFF = "PAGE_POWEROFF"
) )
func ConfigGui() { func ConfigGui(config *koanf.Koanf) {
// Memory info for status panel // Memory info for status panel
meminfo := &procmeminfo.MemInfo{} meminfo := &procmeminfo.MemInfo{}
err := meminfo.Update() err := meminfo.Update()
@ -80,7 +80,7 @@ func ConfigGui() {
// Get list of all folders that can be used as albums // Get list of all folders that can be used as albums
var albums []string var albums []string
err = filepath.Walk(ALBUM_ROOT_DIR, func(path string, fi os.FileInfo, err error) error { err = filepath.Walk(config.String(CONFIG_KEY_ALBUMS_ROOT), func(path string, fi os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
@ -88,7 +88,7 @@ func ConfigGui() {
if strings.Contains(path, SYNCTHING_FOLDER_SKIP) { if strings.Contains(path, SYNCTHING_FOLDER_SKIP) {
return nil return nil
} }
albumName := strings.TrimPrefix(path, ALBUM_ROOT_DIR) albumName := strings.TrimPrefix(path, config.String(CONFIG_KEY_ALBUMS_ROOT))
if albumName == "" { if albumName == "" {
albumName = "Main Folder" albumName = "Main Folder"
} }
@ -154,7 +154,9 @@ func ConfigGui() {
SetTitle("Menu"). SetTitle("Menu").
SetTitleColor(tcell.ColorAqua) SetTitleColor(tcell.ColorAqua)
menu.AddItem("Select Albums", "", '1', nil) menu.AddItem("Select Albums", "", '1', nil)
menu.AddItem("Configure WiFi", "", '2', nil) menu.AddItem("Intervals", "", '2', nil)
menu.AddItem("WiFi", "", '3', nil)
menu.AddItem("HDMI On/Off", "", '5', nil)
// Setup base var for main column so the menu setup is easier to manage // Setup base var for main column so the menu setup is easier to manage
main := tview.NewFlex(). main := tview.NewFlex().
@ -165,6 +167,39 @@ func ConfigGui() {
SetBorder(true). SetBorder(true).
SetTitleColor(tcell.ColorAqua) SetTitleColor(tcell.ColorAqua)
// Select Albums Form
selectAlbumsForm := tview.NewForm()
configSelectedAlbums := config.Strings(CONFIG_KEY_ALBUMS_SELECTED)
for _, album := range albums {
albumSelected := false
for _, configSelectedAlbum := range configSelectedAlbums {
if configSelectedAlbum == "/" {
configSelectedAlbum = "Main Folder"
}
if album == configSelectedAlbum {
albumSelected = true
}
}
selectAlbumsForm.AddCheckbox(album, albumSelected, nil)
}
selectAlbumsForm.AddButton("Apply", nil)
selectAlbumsForm.AddButton("Cancel", func() {
main.Clear()
app.SetFocus(menu)
})
// Slide Interval Form
intervalsForm := tview.NewForm()
configSlideInterval := config.String(CONFIG_KEY_SLIDESHOW_INTERVAL)
configRestartInterval := config.String(CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL)
intervalsForm.AddInputField("Slide", configSlideInterval, 0, nil, nil)
intervalsForm.AddInputField("Restart/Reshuffle", configRestartInterval, 0, nil, nil)
intervalsForm.AddButton("Apply", nil)
intervalsForm.AddButton("Cancel", func() {
main.Clear()
app.SetFocus(menu)
})
// WiFi Config Form // WiFi Config Form
wifiConfigForm := tview.NewForm() wifiConfigForm := tview.NewForm()
wifiConfigAccessPoint := "" wifiConfigAccessPoint := ""
@ -185,13 +220,14 @@ func ConfigGui() {
app.SetFocus(menu) app.SetFocus(menu)
}) })
// Select Albums Form // HDMI On/Off Form
selectAlbumsForm := tview.NewForm() hdmiForm := tview.NewForm()
for _, album := range albums { configHDMIOff := config.String(CONFIG_KEY_HDMI_OFF)
selectAlbumsForm.AddCheckbox(album, true, nil) configHDMIOn := config.String(CONFIG_KEY_HDMI_ON)
} hdmiForm.AddInputField("HDMI Off Schedule", configHDMIOff, 0, nil, nil)
selectAlbumsForm.AddButton("Apply", nil) hdmiForm.AddInputField("HDMI On Schedule", configHDMIOn, 0, nil, nil)
selectAlbumsForm.AddButton("Cancel", func() { hdmiForm.AddButton("Apply", nil)
hdmiForm.AddButton("Cancel", func() {
main.Clear() main.Clear()
app.SetFocus(menu) app.SetFocus(menu)
}) })
@ -204,12 +240,24 @@ func ConfigGui() {
main.AddItem(selectAlbumsForm, 0, 1, true) main.AddItem(selectAlbumsForm, 0, 1, true)
app.SetFocus(selectAlbumsForm) app.SetFocus(selectAlbumsForm)
} }
if title == "Configure WiFi" { if title == "WiFi" {
main.SetTitle("Configure WiFi") main.SetTitle("Configure WiFi")
main.Clear() main.Clear()
main.AddItem(wifiConfigForm, 0, 1, true) main.AddItem(wifiConfigForm, 0, 1, true)
app.SetFocus(wifiConfigForm) app.SetFocus(wifiConfigForm)
} }
if title == "Intervals" {
main.SetTitle("Configure Intervals")
main.Clear()
main.AddItem(intervalsForm, 0, 1, true)
app.SetFocus(intervalsForm)
}
if title == "HDMI On/Off" {
main.SetTitle("Configure HDMI On/Off")
main.Clear()
main.AddItem(hdmiForm, 0, 1, true)
app.SetFocus(hdmiForm)
}
}) })
// Side bar fields // Side bar fields
@ -364,9 +412,14 @@ func ConfigGui() {
// Override some of the default behavior so up/dn move between fields in forms // Override some of the default behavior so up/dn move between fields in forms
// Per API GetFocusedItemIndex on a form will be -1 if a form item isn't currently focused // Per API GetFocusedItemIndex on a form will be -1 if a form item isn't currently focused
// We use this as a bit of a cheat to figure out if we're inside of a form that needs better nav options for users (ie. tab doesn't exist on a remote) // We use this as a bit of a cheat to figure out if we're inside of a form that needs better nav options for users (ie. tab doesn't exist on a remote)
wifiField, wifiButton := wifiConfigForm.GetFocusedItemIndex()
albumField, albumButton := selectAlbumsForm.GetFocusedItemIndex() albumField, albumButton := selectAlbumsForm.GetFocusedItemIndex()
if wifiField != -1 || wifiButton != -1 || albumField != -1 || albumButton != -1 { intervalField, intervalButton := intervalsForm.GetFocusedItemIndex()
wifiField, wifiButton := wifiConfigForm.GetFocusedItemIndex()
hdmiField, hdmiButton := hdmiForm.GetFocusedItemIndex()
if (wifiField != -1 || wifiButton != -1 ||
albumField != -1 || albumButton != -1 ||
intervalField != -1 || intervalButton != -1 ||
hdmiField != -1 || hdmiButton != -1) {
switch event.Key() { switch event.Key() {
case tcell.KeyUp: case tcell.KeyUp:
return tcell.NewEventKey(tcell.KeyBacktab, 0, event.Modifiers()) return tcell.NewEventKey(tcell.KeyBacktab, 0, event.Modifiers())

24
ui/constants.go Normal file
View file

@ -0,0 +1,24 @@
package ui
const (
CLI_FLAG_CONFIG_ONLY = "config-ui-only"
)
const (
CONFIG_FILE_PATH = "/etc/default/pf.toml"
CONFIG_KEY_SLIDESHOW_INTERVAL = "slideshow.slideinterval"
CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL = "slideshow.restartinterval"
CONFIG_KEY_HDMI_OFF = "hdmi.off"
CONFIG_KEY_HDMI_ON = "hdmi.on"
CONFIG_KEY_ALBUMS_ROOT = "albums.root"
CONFIG_KEY_ALBUMS_SELECTED = "albums.selected"
)
const (
DEFAULT_SLIDESHOW_INTERVAL = "300s"
DEFAULT_SLIDESHOW_RESTART_INTERVAL = "7d"
DEFAULT_HDMI_OFF = "*-*-* 00:00:00"
DEFAULT_HDMI_ON = "*-*-* 06:00:00"
DEFAULT_ALBUMS_ROOT = "/tank/pictures"
DEFAULT_ALBUM_SELECTED = "/"
)

View file

@ -9,14 +9,14 @@ import (
"time" "time"
"github.com/eiannone/keyboard" "github.com/eiannone/keyboard"
"github.com/knadh/koanf"
) )
const ( const (
CMD_FIM = "/usr/local/bin/pf-fim.sh" CMD_FIM = "/usr/local/bin/pf-fim.sh"
SLIDESHOW_INTERVAL = 300 * time.Second
) )
func Slideshow() { func Slideshow(config *koanf.Koanf) {
// fim placeholder so we can operate on it when a exit slideshow is received // fim placeholder so we can operate on it when a exit slideshow is received
var fim *exec.Cmd = nil var fim *exec.Cmd = nil
@ -32,7 +32,7 @@ func Slideshow() {
} }
// Advance slideshow every interval as defined in const() // Advance slideshow every interval as defined in const()
ticker := time.NewTicker(SLIDESHOW_INTERVAL) ticker := time.NewTicker(config.Duration(CONFIG_KEY_SLIDESHOW_INTERVAL))
stop_ticker := make(chan struct{}) stop_ticker := make(chan struct{})
go func() { go func() {
for { for {
@ -68,7 +68,6 @@ func Slideshow() {
if event.Err != nil { if event.Err != nil {
log.Fatalf("Error listening to key events : %s", err) log.Fatalf("Error listening to key events : %s", err)
} }
log.Printf("You pressed: key %X\n", event.Key)
// Keys for fim event management (previous/next in particular) // Keys for fim event management (previous/next in particular)
fimKey := "" fimKey := ""
@ -100,7 +99,7 @@ func Slideshow() {
if err != nil { if err != nil {
log.Fatalf("Error controlling fim : %s", err) log.Fatalf("Error controlling fim : %s", err)
} }
ticker.Reset(SLIDESHOW_INTERVAL) ticker.Reset(config.Duration(CONFIG_KEY_SLIDESHOW_INTERVAL))
} }
} }
} }