From d6b0483feb598a0c69c0d17a754545a9355e500c Mon Sep 17 00:00:00 2001 From: Ben Burwell Date: Thu, 24 May 2018 23:59:09 -0400 Subject: Authenticate to bridge from config --- config.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++------ main.go | 65 +++++++++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 101 insertions(+), 22 deletions(-) diff --git a/config.go b/config.go index a12a240..1402c17 100644 --- a/config.go +++ b/config.go @@ -1,8 +1,10 @@ package main import ( + "errors" "io/ioutil" "log" + "strings" "github.com/BurntSushi/xdg" "gopkg.in/yaml.v2" @@ -10,13 +12,15 @@ import ( const XDG_CONFIG_NAME = "phlux" +type BridgeConfig struct { + BridgeID string `yaml:"id"` + Token string `yaml:"token"` +} + type PhluxConfig struct { - Latitude float64 `yaml:"latitude"` - Longitude float64 `yaml:"longitude"` - Bridges []struct { - BridgeID string `yaml:"id"` - Token string `yaml:"token"` - } `yaml:"bridges"` + Latitude float64 `yaml:"latitude"` + Longitude float64 `yaml:"longitude"` + Bridges []BridgeConfig `yaml:"bridges"` } func (c *PhluxConfig) Read() { @@ -37,3 +41,45 @@ func (c *PhluxConfig) Read() { return } } + +func (c *PhluxConfig) GetBridgeToken(id string) (string, error) { + lc := strings.ToLower(id) + for _, bridge := range c.Bridges { + if strings.ToLower(bridge.BridgeID) == lc { + return bridge.Token, nil + } + } + return "", errors.New("No token found for bridge " + id) +} + +func (c *PhluxConfig) SetBridgeToken(id, token string) { + for _, bridge := range c.Bridges { + if bridge.BridgeID == id { + bridge.Token = token + return + } + } + c.Bridges = append(c.Bridges, BridgeConfig{ + BridgeID: id, + Token: token, + }) +} + +func (c *PhluxConfig) Save() (err error) { + out, err := yaml.Marshal(c) + if err != nil { + log.Printf("Error marshalling config: %s\n", err.Error()) + } + var paths xdg.Paths + configFile, err := paths.ConfigFile(XDG_CONFIG_NAME) + if err != nil { + log.Printf("No config file found: %s\n", err.Error()) + return + } + err = ioutil.WriteFile(configFile, out, 0600) + if err != nil { + log.Printf("Error writing config file %s: %s\n", configFile, err.Error()) + return + } + return +} diff --git a/main.go b/main.go index 6253cbb..00850db 100644 --- a/main.go +++ b/main.go @@ -1,14 +1,15 @@ package main import ( + "errors" + "fmt" "log" - "os" "time" hue "github.com/benburwell/gohue" ) -const username = "phlux" +const USERNAME = "phlux" func main() { var config PhluxConfig @@ -23,29 +24,61 @@ func main() { desiredColorTemp := getDesiredColorTemperature(time.Now(), config.Latitude, config.Longitude) for _, bridge := range bridges { log.Printf("Bridge: %s\n", bridge.IPAddress) - updateBridge(bridge, desiredColorTemp) + updateBridge(&bridge, desiredColorTemp, &config) } } -func updateBridge(bridge hue.Bridge, ct ColorTemperature) { - //username, err := bridge.CreateUser(username) - //if err != nil { - // panic("Could not create user on bridge") - //} - //fmt.Printf("Made user %s for bridge %s\n", username, bridge.IPAddress) - err := bridge.Login(os.Getenv("HUE_LOGIN")) +// In case we don't know the bridge's serial number for some reason, we won't +// be able to look up the token, nor will we be able to save it. There is still +// a chance we will be able to successfully log in though: if the link button +// has been pressed, we should be able to create ourselves a temporary token. +func authenticateOnce(bridge *hue.Bridge) error { + token, err := bridge.CreateUser(USERNAME) if err != nil { - log.Fatalf("Could not log in to bridge: %s\n", err.Error()) + return errors.New(fmt.Sprintf("Could not create temporary token: %s", err.Error())) } - log.Println("Logged in to bridge") + log.Printf("Made token %s for bridge %s\n", token, bridge.IPAddress) + err = bridge.Login(token) + if err != nil { + return errors.New(fmt.Sprintf("Failed to log in with temporary token: %s", err.Error())) + } + log.Printf("Logged in to bridge %s\n", bridge.IPAddress) + return nil +} + +func createToken(bridge *hue.Bridge, config *PhluxConfig) error { + if err := authenticateOnce(bridge); err != nil { + return err + } + config.SetBridgeToken(bridge.Info.Device.SerialNumber, bridge.Username) + config.Save() + return nil +} - config, err := bridge.GetConfig() +// Attempt to authenticate to the bridge using a variety of techniques, +// including looking up a saved token for the bridge's serial number and +// attempting to generate a new token for the bridge assuming the link button +// has been pressed. +func authenticate(bridge *hue.Bridge, config *PhluxConfig) error { + // get bridge info, which contains serial number + err := bridge.GetInfo() if err != nil { - log.Fatalf("Could not get bridge info: %s\n", err.Error()) + return authenticateOnce(bridge) } - log.Printf("Bridge name: %s\n", config.Name) - log.Printf("Bridge ID: %s\n", config.BridgeID) + token, err := config.GetBridgeToken(bridge.Info.Device.SerialNumber) + if err != nil { + return createToken(bridge, config) + } + err = bridge.Login(token) + if err != nil { + log.Fatalf("Could not log in to bridge: %s\n", err.Error()) + } + log.Println("Logged in to bridge") + return nil +} +func updateBridge(bridge *hue.Bridge, ct ColorTemperature, config *PhluxConfig) { + authenticate(bridge, config) lights, err := bridge.GetAllLights() if err != nil { log.Fatalf("Error getting lights: %s\n", err.Error()) -- cgit v1.2.3