Skip to content

Commit

Permalink
(feat) use Cobra&Viper for Config with ENV vars
Browse files Browse the repository at this point in the history
  • Loading branch information
splattner committed Sep 28, 2023
1 parent fdcba78 commit 19e8b85
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 95 deletions.
12 changes: 12 additions & 0 deletions cmd/ucrt/ucrt.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import (
"os"
"path/filepath"

"github.com/spf13/viper"
"github.com/splattner/goucrt/pkg/cmd"
"github.com/splattner/goucrt/pkg/cmd/ucrt"

log "github.com/sirupsen/logrus"
)

const RELEASEDATE string = "21.09.2023"
Expand All @@ -14,6 +17,15 @@ func main() {

baseName := filepath.Base(os.Args[0])

viper.SetConfigName("config")
viper.AddConfigPath(".")
viper.SetEnvPrefix("UC_")
viper.AutomaticEnv()

if err := viper.ReadInConfig(); err != nil {
log.WithError(err).Info("Unable to read config")
}

err := ucrt.NewCommand(baseName).Execute()
cmd.CheckError(err)

Expand Down
24 changes: 4 additions & 20 deletions pkg/cmd/deconz/deconz.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
log "github.com/sirupsen/logrus"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/splattner/goucrt/pkg/client"
"github.com/splattner/goucrt/pkg/cmd"
"github.com/splattner/goucrt/pkg/integration"
Expand All @@ -21,32 +22,15 @@ func NewCommand(rootCmd *cobra.Command) *cobra.Command {

log.SetOutput(os.Stdout)

debug, _ := rootCmd.Flags().GetBool("debug")
debug := viper.GetBool("debug")
if debug {
log.SetLevel(log.DebugLevel)
} else {
log.SetLevel(log.InfoLevel)
}

var config = make(integration.Config)

listenPort, _ := rootCmd.Flags().GetInt("listenPort")
enableMDNS, _ := rootCmd.Flags().GetBool("mdns")
enableRegistration, _ := rootCmd.Flags().GetBool("registration")
registrationUsername, _ := rootCmd.Flags().GetString("registrationUsername")
registrationPin, _ := rootCmd.Flags().GetString("registrationPin")
websocketPath, _ := rootCmd.Flags().GetString("websocketPath")
remoteTwoIP, _ := rootCmd.Flags().GetString("remoteTwoIP")
remoteTwoPort, _ := rootCmd.Flags().GetInt("remoteTwoPort")

config["listenport"] = listenPort
config["enableMDNS"] = enableMDNS
config["enableRegistration"] = enableRegistration
config["registrationUsername"] = registrationUsername
config["registrationPin"] = registrationPin
config["remoteTwoIP"] = remoteTwoIP
config["remoteTwoPort"] = remoteTwoPort
config["websocketPath"] = websocketPath
var config integration.Config
viper.Unmarshal(&config)

i, err := integration.NewIntegration(config)
cmd.CheckError(err)
Expand Down
24 changes: 4 additions & 20 deletions pkg/cmd/denonavr/denonavr.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
log "github.com/sirupsen/logrus"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/splattner/goucrt/pkg/client"
"github.com/splattner/goucrt/pkg/cmd"
"github.com/splattner/goucrt/pkg/integration"
Expand All @@ -21,32 +22,15 @@ func NewCommand(rootCmd *cobra.Command) *cobra.Command {

log.SetOutput(os.Stdout)

debug, _ := rootCmd.Flags().GetBool("debug")
debug := viper.GetBool("debug")
if debug {
log.SetLevel(log.DebugLevel)
} else {
log.SetLevel(log.InfoLevel)
}

var config = make(integration.Config)

listenPort, _ := rootCmd.Flags().GetInt("listenPort")
enableMDNS, _ := rootCmd.Flags().GetBool("mdns")
enableRegistration, _ := rootCmd.Flags().GetBool("registration")
registrationUsername, _ := rootCmd.Flags().GetString("registrationUsername")
registrationPin, _ := rootCmd.Flags().GetString("registrationPin")
websocketPath, _ := rootCmd.Flags().GetString("websocketPath")
remoteTwoIP, _ := rootCmd.Flags().GetString("remoteTwoIP")
remoteTwoPort, _ := rootCmd.Flags().GetInt("remoteTwoPort")

config["listenport"] = listenPort
config["enableMDNS"] = enableMDNS
config["enableRegistration"] = enableRegistration
config["registrationUsername"] = registrationUsername
config["registrationPin"] = registrationPin
config["remoteTwoIP"] = remoteTwoIP
config["remoteTwoPort"] = remoteTwoPort
config["websocketPath"] = websocketPath
var config integration.Config
viper.Unmarshal(&config)

i, err := integration.NewIntegration(config)
cmd.CheckError(err)
Expand Down
22 changes: 3 additions & 19 deletions pkg/cmd/shelly/shelly.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
log "github.com/sirupsen/logrus"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/splattner/goucrt/pkg/client"
"github.com/splattner/goucrt/pkg/cmd"
"github.com/splattner/goucrt/pkg/integration"
Expand All @@ -28,25 +29,8 @@ func NewCommand(rootCmd *cobra.Command) *cobra.Command {
log.SetLevel(log.InfoLevel)
}

var config = make(integration.Config)

listenPort, _ := rootCmd.Flags().GetInt("listenPort")
enableMDNS, _ := rootCmd.Flags().GetBool("mdns")
enableRegistration, _ := rootCmd.Flags().GetBool("registration")
registrationUsername, _ := rootCmd.Flags().GetString("registrationUsername")
registrationPin, _ := rootCmd.Flags().GetString("registrationPin")
websocketPath, _ := rootCmd.Flags().GetString("websocketPath")
remoteTwoIP, _ := rootCmd.Flags().GetString("remoteTwoIP")
remoteTwoPort, _ := rootCmd.Flags().GetInt("remoteTwoPort")

config["listenport"] = listenPort
config["enableMDNS"] = enableMDNS
config["enableRegistration"] = enableRegistration
config["registrationUsername"] = registrationUsername
config["registrationPin"] = registrationPin
config["remoteTwoIP"] = remoteTwoIP
config["remoteTwoPort"] = remoteTwoPort
config["websocketPath"] = websocketPath
var config integration.Config
viper.Unmarshal(&config)

i, err := integration.NewIntegration(config)
cmd.CheckError(err)
Expand Down
22 changes: 3 additions & 19 deletions pkg/cmd/tasmota/tasmota.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
log "github.com/sirupsen/logrus"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/splattner/goucrt/pkg/client"
"github.com/splattner/goucrt/pkg/cmd"
"github.com/splattner/goucrt/pkg/integration"
Expand All @@ -28,25 +29,8 @@ func NewCommand(rootCmd *cobra.Command) *cobra.Command {
log.SetLevel(log.InfoLevel)
}

var config = make(integration.Config)

listenPort, _ := rootCmd.Flags().GetInt("listenPort")
enableMDNS, _ := rootCmd.Flags().GetBool("mdns")
enableRegistration, _ := rootCmd.Flags().GetBool("registration")
registrationUsername, _ := rootCmd.Flags().GetString("registrationUsername")
registrationPin, _ := rootCmd.Flags().GetString("registrationPin")
websocketPath, _ := rootCmd.Flags().GetString("websocketPath")
remoteTwoIP, _ := rootCmd.Flags().GetString("remoteTwoIP")
remoteTwoPort, _ := rootCmd.Flags().GetInt("remoteTwoPort")

config["listenport"] = listenPort
config["enableMDNS"] = enableMDNS
config["enableRegistration"] = enableRegistration
config["registrationUsername"] = registrationUsername
config["registrationPin"] = registrationPin
config["remoteTwoIP"] = remoteTwoIP
config["remoteTwoPort"] = remoteTwoPort
config["websocketPath"] = websocketPath
var config integration.Config
viper.Unmarshal(&config)

i, err := integration.NewIntegration(config)
cmd.CheckError(err)
Expand Down
34 changes: 31 additions & 3 deletions pkg/cmd/ucrt/ucrt.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ucrt

import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/splattner/goucrt/pkg/cmd/deconz"
"github.com/splattner/goucrt/pkg/cmd/denonavr"
"github.com/splattner/goucrt/pkg/cmd/shelly"
Expand All @@ -16,16 +17,43 @@ func NewCommand(name string) *cobra.Command {
}

rootCmd.PersistentFlags().IntP("listenPort", "l", 8080, "the port this integration is listening for websocket connection from the remote")
viper.BindPFlag("listenPort", rootCmd.PersistentFlags().Lookup("listenPort"))
viper.BindEnv("listenPort", "UC_INTEGRATION_LISTEN_PORT")

rootCmd.PersistentFlags().String("websocketPath", "/ws", "path where this integration is available for websocket connections")
viper.BindPFlag("websocketPath", rootCmd.PersistentFlags().Lookup("websocketPath"))
viper.BindEnv("websocketPath", "UC_INTEGRATION_WEBSOCKET_PATH")

rootCmd.PersistentFlags().Bool("disableMDNS", false, "Disable integration advertisement via mDNS")
viper.BindPFlag("disableMDNS", rootCmd.PersistentFlags().Lookup("disableMDNS"))
viper.BindEnv("disableMDNS", "UC_DISABLE_MDNS_PUBLISH")

rootCmd.PersistentFlags().String("remoteTwoIP", "", "IP Address of your Remote Two instance (disables Remote Two discovery)")
viper.BindPFlag("remoteTwoIP", rootCmd.PersistentFlags().Lookup("remoteTwoIP"))
viper.BindEnv("remoteTwoIP", "UC_RT_HOST")

rootCmd.PersistentFlags().Int("remoteTwoPort", 80, "Port of your Remote Two instance (disables Remote Two discovery)")
viper.BindPFlag("remoteTwoPort", rootCmd.PersistentFlags().Lookup("remoteTwoPort"))
viper.BindEnv("remoteTwoPort", "UC_RT_PORT")

rootCmd.PersistentFlags().Bool("mdns", true, "Enable integration advertisement via mDNS")
rootCmd.PersistentFlags().Bool("registration", false, "Enable driver registration on the Remote Two instead of mDNS advertisement")
viper.BindPFlag("registration", rootCmd.PersistentFlags().Lookup("registration"))
viper.BindEnv("registration", "UC_ENABLE_REGISTRATION")

rootCmd.PersistentFlags().String("registrationUsername", "web-configurator", "Username of the RemoteTwo for driver registration")
viper.BindPFlag("registrationUsername", rootCmd.PersistentFlags().Lookup("registrationUsername"))
viper.BindEnv("registrationUsername", "UC_REGISTRATION_USERNAME")

rootCmd.PersistentFlags().String("registrationPin", "", "Pin of the RemoteTwo for driver registration")
rootCmd.PersistentFlags().String("remoteTwoIP", "", "IP Address of your Remote Two instance (disables Remote Two discovery)")
rootCmd.PersistentFlags().Int("remoteTwoPort", 80, "Port of your Remote Two instance (disables Remote Two discovery)")
viper.BindPFlag("registrationPin", rootCmd.PersistentFlags().Lookup("registrationPin"))
viper.BindEnv("registrationUsername", "UC_REGISTRATION_PIN")

rootCmd.PersistentFlags().Bool("debug", false, "Enable debug log level")
viper.BindPFlag("debug", rootCmd.PersistentFlags().Lookup("debug"))

rootCmd.PersistentFlags().String("ucconfighome", "./", "Configuration directory to save the user configuration from the driver setup")
viper.BindPFlag("ucconfighome", rootCmd.PersistentFlags().Lookup("ucconfighome"))
viper.BindEnv("ucconfighome", "UC_CONFIG_HOME")

rootCmd.AddCommand(
denonavr.NewCommand(rootCmd),
Expand Down
4 changes: 2 additions & 2 deletions pkg/integration/advertisement.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ func (i *Integration) startAdvertising() {
"name=" + i.Metadata.Name.En,
"developer=" + i.Metadata.Developer.Name,
"ver=" + i.Metadata.Version,
"ws_path=" + i.Config["websocketPath"].(string),
"ws_path=" + i.Config.WebsocketPath,
}

server, err := zeroconf.Register(i.Metadata.DriverId, "_uc-integration._tcp", "local.", i.Config["listenport"].(int), txt, nil)
server, err := zeroconf.Register(i.Metadata.DriverId, "_uc-integration._tcp", "local.", i.Config.ListenPort, txt, nil)
if err != nil {
panic(err)
}
Expand Down
13 changes: 12 additions & 1 deletion pkg/integration/config.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
package integration

// Generic string key/value config map to store configuration option
type Config map[string]interface{}
type Config struct {
ListenPort int `mapstructure:"listenPort"`
DisableMDNS bool `mapstructure:"disableMDNS"`
EnableRegistration bool `mapstructure:"enableRegistration"`
RegistrationUsername string `mapstructure:"registrationUsername"`
RegistrationPin string `mapstructure:"registrationPin"`
WebsocketPath string `mapstructure:"websocketPath"`
ConfigHome string `mapstructure:"ucconfighome"`
RemoteTwoHost string `mapstructure:"remoteTwoIP"`
RemoteTwoPort int `mapstructure:"remoteTwoPort"`
IgnoreEntitySubscription bool
}
2 changes: 1 addition & 1 deletion pkg/integration/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func (i *Integration) SendEntityChangeEvent(e interface{}) {
log.WithField("subscribedEtities", i.SubscribedEntities).Debug("Currently subscribed entities")

// Only send the event when remote is subscribed to
if (i.Config["ignoreEntitySubscription"] != nil && i.Config["ignoreEntitySubscription"].(bool)) || slices.Contains(i.SubscribedEntities, entity_id) {
if i.Config.IgnoreEntitySubscription || slices.Contains(i.SubscribedEntities, entity_id) {

var res interface{}
now := time.Now()
Expand Down
12 changes: 6 additions & 6 deletions pkg/integration/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func NewIntegration(config Config) (*Integration, error) {

i := Integration{
Config: config,
listenAddress: fmt.Sprintf(":%d", config["listenport"].(int)),
listenAddress: fmt.Sprintf(":%d", config.ListenPort),
deviceState: DisconnectedDeviceState,
DeviceId: "", // I think device_id is not yet implemented in Remote TV, used for multi-device integrati

Expand Down Expand Up @@ -79,15 +79,15 @@ func (i *Integration) Run() error {
return fmt.Errorf("Metadata not set")
}

http.HandleFunc(i.Config["websocketPath"].(string), i.wsEndpoint)
http.HandleFunc(i.Config.WebsocketPath, i.wsEndpoint)

//MDNS
if i.Config["enableMDNS"].(bool) {
if !i.Config.DisableMDNS {
go i.startAdvertising()
}

// Register the integration
if i.Config["enableRegistration"].(bool) && i.Config["registrationPin"].(string) != "" {
if i.Config.EnableRegistration && i.Config.RegistrationPin != "" {
go i.registerIntegration()
}

Expand Down Expand Up @@ -135,7 +135,7 @@ func (i *Integration) SetDriverSetupState(event_Type DriverSetupEventType, state
// TODO: handle location via ENV's
func (i *Integration) LoadSetupData() {

file, err := os.ReadFile(i.Metadata.DriverId + ".json")
file, err := os.ReadFile(i.Config.ConfigHome + i.Metadata.DriverId + ".json")
if err != nil {
log.WithError(err).Info("Cannot read setupDataFile")
i.SetupData = make(SetupData)
Expand All @@ -151,5 +151,5 @@ func (i *Integration) PersistSetupData() {

log.WithField("SetupData", i.SetupData).Info("Persist setup data")
file, _ := json.MarshalIndent(i.SetupData, "", " ")
_ = os.WriteFile(i.Metadata.DriverId+".json", file, 0644)
_ = os.WriteFile(i.Config.ConfigHome+i.Metadata.DriverId+".json", file, 0644)
}
8 changes: 4 additions & 4 deletions pkg/integration/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ type DriverRegistration struct {
func (i *Integration) registerIntegration() {

// Use configured IP for registration instead of Remote Two discovery
if i.Config["remoteTwoIP"].(string) != "" && i.Config["remoteTwoPort"].(int) > 0 {
i.registerWithRemoteTwo(i.Config["remoteTwoIP"].(string), i.Config["remoteTwoPort"].(int))
if i.Config.RegistrationPin != "" && i.Config.RemoteTwoPort > 0 {
i.registerWithRemoteTwo(i.Config.RemoteTwoHost, i.Config.RemoteTwoPort)
} else {

entries := make(chan *zeroconf.ServiceEntry)
Expand Down Expand Up @@ -78,7 +78,7 @@ func (i *Integration) registerIntegration() {
func (i *Integration) registerWithRemoteTwo(remoteTwoIP string, remoteTwoPort int) {

myip := GetLocalIP()
driverURL := "ws://" + myip + i.listenAddress + i.Config["websocketPath"].(string)
driverURL := "ws://" + myip + i.listenAddress + i.Config.WebsocketPath
remoteTwoURL := "http://" + remoteTwoIP + ":" + fmt.Sprint(remoteTwoPort)

driverRegistration := DriverRegistration{
Expand Down Expand Up @@ -107,7 +107,7 @@ func (i *Integration) registerWithRemoteTwo(remoteTwoIP string, remoteTwoPort in
req.Header.Set("Content-Type", "application/json")

// Authentication wit the Remote Two
credentials := b64.StdEncoding.EncodeToString([]byte(i.Config["registrationUsername"].(string) + ":" + i.Config["registrationPin"].(string)))
credentials := b64.StdEncoding.EncodeToString([]byte(i.Config.RegistrationUsername + ":" + i.Config.RegistrationPin))
req.Header.Set("Authorization", "Basic "+credentials)

// send the request
Expand Down

0 comments on commit 19e8b85

Please sign in to comment.