Wire up more of the config ; apply hdmi on/off schedules on save
This commit is contained in:
parent
769029b9c2
commit
15dfaa31f9
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/knadh/koanf/providers/posflag"
|
"github.com/knadh/koanf/providers/posflag"
|
||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
|
|
||||||
|
pfconfig "git.kemonine.info/PiFrame/config"
|
||||||
"git.kemonine.info/PiFrame/ui"
|
"git.kemonine.info/PiFrame/ui"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,8 +24,8 @@ func main() {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
// Command line flags
|
// Command line flags
|
||||||
f.Bool(ui.CLI_FLAG_CONFIG_ONLY, false, "Only show the config UI, NOT the slideshow")
|
f.Bool(pfconfig.CLI_FLAG_CONFIG_ONLY, false, "Only show the config UI, NOT the slideshow")
|
||||||
cliFlag := f.Lookup(ui.CLI_FLAG_CONFIG_ONLY)
|
cliFlag := f.Lookup(pfconfig.CLI_FLAG_CONFIG_ONLY)
|
||||||
if cliFlag != nil {
|
if cliFlag != nil {
|
||||||
cliFlag.NoOptDefVal = "true"
|
cliFlag.NoOptDefVal = "true"
|
||||||
}
|
}
|
||||||
|
@ -36,17 +37,17 @@ func main() {
|
||||||
|
|
||||||
// Setup some defaults
|
// Setup some defaults
|
||||||
pfConfig.Load(confmap.Provider(map[string]interface{}{
|
pfConfig.Load(confmap.Provider(map[string]interface{}{
|
||||||
ui.CONFIG_KEY_SLIDESHOW_INTERVAL: ui.DEFAULT_SLIDESHOW_INTERVAL,
|
pfconfig.CONFIG_KEY_SLIDESHOW_INTERVAL: pfconfig.DEFAULT_SLIDESHOW_INTERVAL,
|
||||||
ui.CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL: ui.DEFAULT_SLIDESHOW_RESTART_INTERVAL,
|
pfconfig.CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL: pfconfig.DEFAULT_SLIDESHOW_RESTART_INTERVAL,
|
||||||
ui.CONFIG_KEY_HDMI_OFF: ui.DEFAULT_HDMI_OFF,
|
pfconfig.CONFIG_KEY_HDMI_OFF: pfconfig.DEFAULT_HDMI_OFF,
|
||||||
ui.CONFIG_KEY_HDMI_ON: ui.DEFAULT_HDMI_ON,
|
pfconfig.CONFIG_KEY_HDMI_ON: pfconfig.DEFAULT_HDMI_ON,
|
||||||
ui.CONFIG_KEY_ALBUMS_ROOT: ui.DEFAULT_ALBUMS_ROOT,
|
pfconfig.CONFIG_KEY_ALBUMS_ROOT: pfconfig.DEFAULT_ALBUMS_ROOT,
|
||||||
ui.CONFIG_KEY_ALBUMS_SELECTED: []string{ui.DEFAULT_ALBUM_SELECTED},
|
pfconfig.CONFIG_KEY_ALBUMS_SELECTED: []string{pfconfig.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(ui.CONFIG_FILE_PATH)
|
configFileProvider := file.Provider(pfconfig.CONFIG_FILE_PATH)
|
||||||
_, err := os.Stat(ui.CONFIG_FILE_PATH)
|
_, err := os.Stat(pfconfig.CONFIG_FILE_PATH)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
//log.Printf("%s does not exist, USING DEFAULTS", ui.CONFIG_FILE_PATH)
|
//log.Printf("%s does not exist, USING DEFAULTS", ui.CONFIG_FILE_PATH)
|
||||||
} else {
|
} else {
|
||||||
|
@ -70,13 +71,13 @@ func main() {
|
||||||
log.Fatalf("Error loading command line flags : %s", err)
|
log.Fatalf("Error loading command line flags : %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !pfConfig.Bool(ui.CLI_FLAG_CONFIG_ONLY) {
|
if !pfConfig.Bool(pfconfig.CLI_FLAG_CONFIG_ONLY) {
|
||||||
ui.Slideshow(pfConfig)
|
ui.Slideshow(pfConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the CLI flag so it's never writted to the config as 'true'
|
// Reset the CLI flag so it's never writted to the config as 'true'
|
||||||
pfConfig.Load(confmap.Provider(map[string]interface{}{
|
pfConfig.Load(confmap.Provider(map[string]interface{}{
|
||||||
ui.CLI_FLAG_CONFIG_ONLY: false,
|
pfconfig.CLI_FLAG_CONFIG_ONLY: false,
|
||||||
}, "."), nil)
|
}, "."), nil)
|
||||||
|
|
||||||
ui.ConfigGui(pfConfig)
|
ui.ConfigGui(pfConfig)
|
||||||
|
|
3
config/README.md
Normal file
3
config/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# config
|
||||||
|
|
||||||
|
Mini module for working with PiFrame configuration file.
|
|
@ -1,4 +1,4 @@
|
||||||
package ui
|
package config
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CLI_FLAG_CONFIG_ONLY = "config-ui-only"
|
CLI_FLAG_CONFIG_ONLY = "config-ui-only"
|
73
ui/config.go
73
ui/config.go
|
@ -1,22 +1,25 @@
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
"github.com/guillermo/go.procmeminfo"
|
"github.com/guillermo/go.procmeminfo"
|
||||||
"github.com/knadh/koanf"
|
"github.com/knadh/koanf"
|
||||||
"github.com/knadh/koanf/parsers/toml"
|
"github.com/knadh/koanf/parsers/toml"
|
||||||
|
"github.com/knadh/koanf/providers/confmap"
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
|
|
||||||
|
"git.kemonine.info/PiFrame/config"
|
||||||
"git.kemonine.info/PiFrame/utils"
|
"git.kemonine.info/PiFrame/utils"
|
||||||
"git.kemonine.info/PiFrame/wifi"
|
"git.kemonine.info/PiFrame/wifi"
|
||||||
)
|
)
|
||||||
|
@ -35,7 +38,7 @@ const (
|
||||||
PAGE_POWEROFF = "PAGE_POWEROFF"
|
PAGE_POWEROFF = "PAGE_POWEROFF"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ConfigGui(config *koanf.Koanf) {
|
func ConfigGui(pfconfig *koanf.Koanf) {
|
||||||
// Memory info for status panel
|
// Memory info for status panel
|
||||||
meminfo := &procmeminfo.MemInfo{}
|
meminfo := &procmeminfo.MemInfo{}
|
||||||
err := meminfo.Update()
|
err := meminfo.Update()
|
||||||
|
@ -67,7 +70,7 @@ func ConfigGui(config *koanf.Koanf) {
|
||||||
|
|
||||||
// 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(config.String(CONFIG_KEY_ALBUMS_ROOT), func(path string, fi os.FileInfo, err error) error {
|
err = filepath.Walk(pfconfig.String(config.CONFIG_KEY_ALBUMS_ROOT), func(path string, fi os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -75,7 +78,7 @@ func ConfigGui(config *koanf.Koanf) {
|
||||||
if strings.Contains(path, SYNCTHING_FOLDER_SKIP) {
|
if strings.Contains(path, SYNCTHING_FOLDER_SKIP) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
albumName := strings.TrimPrefix(path, config.String(CONFIG_KEY_ALBUMS_ROOT))
|
albumName := strings.TrimPrefix(path, pfconfig.String(config.CONFIG_KEY_ALBUMS_ROOT))
|
||||||
if albumName == "" {
|
if albumName == "" {
|
||||||
albumName = "Main Folder"
|
albumName = "Main Folder"
|
||||||
}
|
}
|
||||||
|
@ -166,7 +169,7 @@ func ConfigGui(config *koanf.Koanf) {
|
||||||
|
|
||||||
// Select Albums Form
|
// Select Albums Form
|
||||||
selectAlbumsForm := tview.NewForm()
|
selectAlbumsForm := tview.NewForm()
|
||||||
configSelectedAlbums := config.Strings(CONFIG_KEY_ALBUMS_SELECTED)
|
configSelectedAlbums := pfconfig.Strings(config.CONFIG_KEY_ALBUMS_SELECTED)
|
||||||
for _, album := range albums {
|
for _, album := range albums {
|
||||||
albumSelected := false
|
albumSelected := false
|
||||||
for _, configSelectedAlbum := range configSelectedAlbums {
|
for _, configSelectedAlbum := range configSelectedAlbums {
|
||||||
|
@ -187,8 +190,8 @@ func ConfigGui(config *koanf.Koanf) {
|
||||||
|
|
||||||
// Slide Interval Form
|
// Slide Interval Form
|
||||||
intervalsForm := tview.NewForm()
|
intervalsForm := tview.NewForm()
|
||||||
configSlideInterval := config.String(CONFIG_KEY_SLIDESHOW_INTERVAL)
|
configSlideInterval := pfconfig.String(config.CONFIG_KEY_SLIDESHOW_INTERVAL)
|
||||||
configRestartInterval := config.String(CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL)
|
configRestartInterval := pfconfig.String(config.CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL)
|
||||||
intervalsForm.AddInputField("Slide", configSlideInterval, 0, nil, func(value string) {
|
intervalsForm.AddInputField("Slide", configSlideInterval, 0, nil, func(value string) {
|
||||||
configSlideInterval = value
|
configSlideInterval = value
|
||||||
})
|
})
|
||||||
|
@ -223,8 +226,8 @@ func ConfigGui(config *koanf.Koanf) {
|
||||||
|
|
||||||
// HDMI On/Off Form
|
// HDMI On/Off Form
|
||||||
hdmiForm := tview.NewForm()
|
hdmiForm := tview.NewForm()
|
||||||
configHDMIOff := config.String(CONFIG_KEY_HDMI_OFF)
|
configHDMIOff := pfconfig.String(config.CONFIG_KEY_HDMI_OFF)
|
||||||
configHDMIOn := config.String(CONFIG_KEY_HDMI_ON)
|
configHDMIOn := pfconfig.String(config.CONFIG_KEY_HDMI_ON)
|
||||||
hdmiForm.AddInputField("HDMI Off Schedule", configHDMIOff, 0, nil, func(value string) {
|
hdmiForm.AddInputField("HDMI Off Schedule", configHDMIOff, 0, nil, func(value string) {
|
||||||
configHDMIOff = value
|
configHDMIOff = value
|
||||||
})
|
})
|
||||||
|
@ -377,21 +380,49 @@ func ConfigGui(config *koanf.Koanf) {
|
||||||
AddButtons([]string{"Yes", "Cancel"}).
|
AddButtons([]string{"Yes", "Cancel"}).
|
||||||
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
||||||
if buttonLabel == "Yes" {
|
if buttonLabel == "Yes" {
|
||||||
|
// Housekeeping var for data to be written to disk
|
||||||
|
var hdmiForDisk bytes.Buffer
|
||||||
|
|
||||||
|
// Apply HDMI configuration (on/off)
|
||||||
|
valueForTemplate := utils.SystemdTimer{OnCalendar: configHDMIOn}
|
||||||
|
screenOn, err := template.New("screenon.systemd.timer").Parse(utils.SCREEN_ON_DOT_TIMER)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error setting up screen on systemd timer : %s", err)
|
||||||
|
}
|
||||||
|
err = screenOn.Execute(&hdmiForDisk, valueForTemplate)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error setting up screen on systemd timer : %s", err)
|
||||||
|
}
|
||||||
|
utils.WriteFile(utils.SCREEN_ON_TIMER_PATH, utils.SCREEN_ON_TIMER_PATH+".tmp", hdmiForDisk.Bytes())
|
||||||
|
|
||||||
|
valueForTemplate.OnCalendar = configHDMIOff
|
||||||
|
hdmiForDisk.Truncate(0)
|
||||||
|
screenOff, err := template.New("screenoff.systemd.timer").Parse(utils.SCREEN_OFF_DOT_TIMER)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error setting up screen off systemd timer : %s", err)
|
||||||
|
}
|
||||||
|
err = screenOff.Execute(&hdmiForDisk, valueForTemplate)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error setting up screen off systemd timer : %s", err)
|
||||||
|
}
|
||||||
|
utils.WriteFile(utils.SCREEN_OFF_TIMER_PATH, utils.SCREEN_OFF_TIMER_PATH+".tmp", hdmiForDisk.Bytes())
|
||||||
|
|
||||||
|
// Reload systemd units after applying HDMI config
|
||||||
|
utils.SystemdDaemonReload()
|
||||||
|
|
||||||
|
// Apply configuration updates to main config manager prior to saving
|
||||||
|
pfconfig.Load(confmap.Provider(map[string]interface{}{
|
||||||
|
config.DEFAULT_HDMI_ON: configHDMIOn,
|
||||||
|
config.DEFAULT_HDMI_OFF: configHDMIOff,
|
||||||
|
}, "."), nil)
|
||||||
|
|
||||||
|
// Save configuration
|
||||||
parser := toml.Parser()
|
parser := toml.Parser()
|
||||||
dataForDisk, err := config.Marshal(parser)
|
configForDisk, err := pfconfig.Marshal(parser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error preparing config for disk write : %s", err)
|
log.Fatalf("Error preparing config for disk write : %s", err)
|
||||||
}
|
}
|
||||||
existingStat, err := os.Lstat(CONFIG_FILE_PATH)
|
utils.WriteFile(config.CONFIG_FILE_PATH, config.CONFIG_FILE_PATH_TMP, configForDisk)
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error checking if config exists : %s", err)
|
|
||||||
}
|
|
||||||
if err := ioutil.WriteFile(CONFIG_FILE_PATH_TMP, dataForDisk, existingStat.Mode()); err != nil {
|
|
||||||
log.Fatalf("Error writing temp config file : %s", err)
|
|
||||||
}
|
|
||||||
if err := os.Rename(CONFIG_FILE_PATH_TMP, CONFIG_FILE_PATH); err != nil {
|
|
||||||
log.Fatalf("Error moving new config in place : %s", err)
|
|
||||||
}
|
|
||||||
app.Stop()
|
app.Stop()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
@ -472,7 +503,7 @@ func ConfigGui(config *koanf.Koanf) {
|
||||||
albumField != -1 || albumButton != -1 ||
|
albumField != -1 || albumButton != -1 ||
|
||||||
intervalField != -1 || intervalButton != -1 ||
|
intervalField != -1 || intervalButton != -1 ||
|
||||||
hdmiField != -1 || hdmiButton != -1 ||
|
hdmiField != -1 || hdmiButton != -1 ||
|
||||||
advancedField != -1 || advancedButton != -1{
|
advancedField != -1 || advancedButton != -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())
|
||||||
|
|
|
@ -10,6 +10,8 @@ import (
|
||||||
|
|
||||||
"github.com/eiannone/keyboard"
|
"github.com/eiannone/keyboard"
|
||||||
"github.com/knadh/koanf"
|
"github.com/knadh/koanf"
|
||||||
|
|
||||||
|
pfconfig "git.kemonine.info/PiFrame/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -32,7 +34,7 @@ func Slideshow(config *koanf.Koanf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance slideshow every interval as defined in const()
|
// Advance slideshow every interval as defined in const()
|
||||||
ticker := time.NewTicker(config.Duration(CONFIG_KEY_SLIDESHOW_INTERVAL))
|
ticker := time.NewTicker(config.Duration(pfconfig.CONFIG_KEY_SLIDESHOW_INTERVAL))
|
||||||
stop_ticker := make(chan struct{})
|
stop_ticker := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
@ -99,7 +101,7 @@ func Slideshow(config *koanf.Koanf) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error controlling fim : %s", err)
|
log.Fatalf("Error controlling fim : %s", err)
|
||||||
}
|
}
|
||||||
ticker.Reset(config.Duration(CONFIG_KEY_SLIDESHOW_INTERVAL))
|
ticker.Reset(config.Duration(pfconfig.CONFIG_KEY_SLIDESHOW_INTERVAL))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
utils/files.go
Normal file
20
utils/files.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WriteFile(destinationPath string, tempPath string, dataForDisk []byte) {
|
||||||
|
existingStat, err := os.Lstat(destinationPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error checking if file exists : %s", err)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(tempPath, dataForDisk, existingStat.Mode()); err != nil {
|
||||||
|
log.Fatalf("Error writing temp file : %s", err)
|
||||||
|
}
|
||||||
|
if err := os.Rename(tempPath, destinationPath); err != nil {
|
||||||
|
log.Fatalf("Error moving new in place : %s", err)
|
||||||
|
}
|
||||||
|
}
|
28
utils/hdmi.go
Normal file
28
utils/hdmi.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
type SystemdTimer struct {
|
||||||
|
OnCalendar string
|
||||||
|
}
|
||||||
|
|
||||||
|
const SCREEN_ON_DOT_TIMER = `
|
||||||
|
[Unit]
|
||||||
|
Description=Turn on display
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar={{.OnCalendar}}
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
`
|
||||||
|
const SCREEN_OFF_DOT_TIMER = `
|
||||||
|
[Unit]
|
||||||
|
Description=Turn off display
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar={{.OnCalendar}}
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
`
|
23
utils/systemd.go
Normal file
23
utils/systemd.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CMD_SYSTEMCTL = "/usr/bin/systemctl"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SCREEN_ON_TIMER_PATH = "/etc/systemd/system/screen-on.timer"
|
||||||
|
SCREEN_OFF_TIMER_PATH = "/etc/systemd/system/screen-off.timer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SystemdDaemonReload() {
|
||||||
|
// Reload systemd units
|
||||||
|
err := exec.Command(CMD_SYSTEMCTL, "daemon-reload").Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error running %s : %s", CMD_SYSTEMCTL, err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue