Skip to content

Commit

Permalink
The setup command now allows the set the bridge IP using the --bridge…
Browse files Browse the repository at this point in the history
… flag parameter (#38)

Usage: 
```bash
openhue setup --bridge 192.168.1.100
```
or 
```bash
openhue setup -b 192.168.1.100
```
  • Loading branch information
thibauult authored Jan 16, 2024
1 parent 43cc966 commit 632bcd7
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 37 deletions.
3 changes: 1 addition & 2 deletions cmd/setup/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package setup

import (
"fmt"
"github.com/spf13/cobra"
"openhue-cli/openhue"
)
Expand Down Expand Up @@ -38,7 +37,7 @@ func NewCmdConfigure(io openhue.IOStreams) *cobra.Command {

path, err := c.Save()
cobra.CheckErr(err)
fmt.Fprintln(io.Out, "[OK] Configuration saved in file", path)
io.Println("[OK] Configuration saved in file", path)
},
}

Expand Down
3 changes: 1 addition & 2 deletions cmd/setup/discover.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package setup

import (
"fmt"
"github.com/spf13/cobra"
"net"
"openhue-cli/openhue"
Expand All @@ -21,7 +20,7 @@ func NewCmdDiscover(io openhue.IOStreams) *cobra.Command {

ip := make(chan *net.IP)
go mdns.DiscoverBridge(ip, 5*time.Second)
fmt.Fprintf(io.Out, "%s\n", <-ip)
io.Printf("%s\n", <-ip)
},
}

Expand Down
77 changes: 52 additions & 25 deletions cmd/setup/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ import (
"time"
)

const hueBridgeDiscover = "https://discovery.meethue.com"

type CmdSetupOptions struct {
deviceType string
generateClientKey bool
bridge string
}

func NewCmdSetup(io openhue.IOStreams) *cobra.Command {
Expand All @@ -38,63 +41,87 @@ the bridge button to perform initial pairing.

cmd.Flags().StringVarP(&o.deviceType, "devicetype", "d", getHostName(), "Device identifier")
cmd.Flags().BoolVarP(&o.generateClientKey, "generateclientkey", "k", true, "Generate the client key")
cmd.Flags().StringVarP(&o.bridge, "bridge", "b", "", "Set your Hue Bridge IP address ("+hueBridgeDiscover+")")

return cmd
}

func startSetup(io openhue.IOStreams, o *CmdSetupOptions) {
ipChan := make(chan *net.IP)
go mdns.DiscoverBridge(ipChan, 5*time.Second)
ip := <-ipChan

if ip == nil {
fmt.Fprintf(io.ErrOut, "❌ Unable to discover your Hue Bridge on your local network\n")
ip, err := getBridgeIPAddress(io, o)
if err != nil {
io.ErrPrintln(err.Error())
return
}

fmt.Fprintf(io.Out, "[OK] Found Hue Bridge with IP '%s'\n", ip)
client := openhue.NewOpenHueClientNoAuth(ip)

client := openhue.NewOpenHueClientNoAuth(ip.String())

fmt.Fprintln(io.Out, "[..] Please push the button on your Hue Bridge")
done := false
for done == false {
fmt.Fprintf(io.Out, ".")
key, err := tryAuth(client, o.toAuthenticateBody())
if err != nil {
io.Println("[..] Please push the button on your Hue Bridge")
for {
key, retry, err := tryAuth(client, o.toAuthenticateBody())
if err != nil && retry {
// this is an expected error, we just wait for the user to push the button
io.Printf(".")
time.Sleep(1 * time.Second)
continue
} else if err != nil && !retry {
// this is unexpected, let's print the error and exit
io.ErrPrintln(err.Error())
break
}
done = true
fmt.Fprintf(io.Out, "\n")
log.Info("Hue Application Key is ", key)
fmt.Fprintln(io.Out, "[OK] Successfully paired openhue with your Hue Bridge!")
path, err := saveConfig(ip.String(), key)
io.Println("\n[OK] Successfully paired openhue with your Hue Bridge!")
path, err := saveConfig(ip, key)
if err != nil {
fmt.Fprintf(io.ErrOut, "[KO] Unable to save config")
io.ErrPrintln("[KO] Unable to save config")
}
fmt.Fprintln(io.Out, "[OK] Configuration saved in file", path)
io.Println("[OK] Configuration saved in file", path)
break
}
}

func getBridgeIPAddress(io openhue.IOStreams, o *CmdSetupOptions) (string, error) {

if len(o.bridge) > 0 {
log.Infof("Bridge IP address set from flag --bridge with value %s", o.bridge)
io.Printf("[OK] Bridge IP is '%s'\n", o.bridge)
return o.bridge, nil
}

log.Info("Bridge IP address no set from flag --bridge, start lookup via mDNS service discovery")

ipChan := make(chan *net.IP)
go mdns.DiscoverBridge(ipChan, 5*time.Second)
ip := <-ipChan

if ip == nil {
return "", fmt.Errorf("[KO] Unable to discover your Hue Bridge on your local network, you can also visit %s\n", hueBridgeDiscover)
}

io.Printf("[OK] Found Hue Bridge with IP '%s'\n", ip)
return ip.String(), nil
}

func (o *CmdSetupOptions) toAuthenticateBody() gen.AuthenticateJSONRequestBody {
body := gen.AuthenticateJSONRequestBody{}
body.Devicetype = &o.deviceType
body.Generateclientkey = &o.generateClientKey
return body
}

func tryAuth(client *gen.ClientWithResponses, body gen.AuthenticateJSONRequestBody) (string, error) {
func tryAuth(client *gen.ClientWithResponses, body gen.AuthenticateJSONRequestBody) (string, bool, error) {

resp, err := client.AuthenticateWithResponse(context.Background(), body)
cobra.CheckErr(err)

if resp.JSON200 == nil {
return "", false, fmt.Errorf("[KO] Unable to reach the Bridge, verify that the IP is correct. You can verify it via %s", hueBridgeDiscover)
}

auth := (*resp.JSON200)[0]
if auth.Error != nil {
return "", errors.New(*auth.Error.Description)
return "", true, errors.New(*auth.Error.Description)
}

return *auth.Success.Username, nil
return *auth.Success.Username, false, nil
}

func saveConfig(bridge string, key string) (string, error) {
Expand Down
7 changes: 3 additions & 4 deletions cmd/version/version.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package version

import (
"fmt"
"github.com/spf13/cobra"
"openhue-cli/openhue"
)
Expand All @@ -22,9 +21,9 @@ openhue version
`,
Run: func(cmd *cobra.Command, args []string) {

fmt.Fprintln(ctx.Io.Out, "\n# Version\t", ctx.BuildInfo.Version)
fmt.Fprintln(ctx.Io.Out, "# Commit\t", BaseCommitUrl+ctx.BuildInfo.Commit)
fmt.Fprintln(ctx.Io.Out, "# Built at\t", ctx.BuildInfo.Date)
ctx.Io.Println("\n# Version\t", ctx.BuildInfo.Version)
ctx.Io.Println("# Commit\t", BaseCommitUrl+ctx.BuildInfo.Commit)
ctx.Io.Println("# Built at\t", ctx.BuildInfo.Date)
},
}

Expand Down
47 changes: 47 additions & 0 deletions openhue/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,24 @@ package openhue

import (
"bytes"
"fmt"
log "github.com/sirupsen/logrus"
"io"
"os"
)

type Console interface {
Printf(format string, a ...any)
Println(a ...any)

ErrPrintf(format string, a ...any)
ErrPrintln(a ...any)
}

// IOStreams provides the standard names for io streams.
// This is useful for embedding and for unit testing.
type IOStreams struct {
Console
// In think, os.Stdin
In io.Reader
// Out think, os.Stdout
Expand Down Expand Up @@ -48,3 +59,39 @@ func NewTestIOStreamsDiscard() IOStreams {
ErrOut: io.Discard,
}
}

//
// Console implementation
//

func (io *IOStreams) Printf(format string, a ...any) {
_, err := fmt.Fprintf(io.Out, format, a...)
if err != nil {
log.Error(err)
return
}
}

func (io *IOStreams) Println(a ...any) {
_, err := fmt.Fprintln(io.Out, a...)
if err != nil {
log.Error(err)
return
}
}

func (io *IOStreams) ErrPrintf(format string, a ...any) {
_, err := fmt.Fprintf(io.ErrOut, format, a...)
if err != nil {
log.Error(err)
return
}
}

func (io *IOStreams) ErrPrintln(a ...any) {
_, err := fmt.Fprintln(io.ErrOut, a...)
if err != nil {
log.Error(err)
return
}
}
8 changes: 4 additions & 4 deletions util/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ func PrintJsonArray[T any](streams openhue.IOStreams, array []T) {
}
}

func PrintJson[T any](streams openhue.IOStreams, array T) {
func PrintJson[T any](io openhue.IOStreams, array T) {
var out []byte
out, _ = json.MarshalIndent(array, "", " ")
fmt.Fprintln(streams.Out, string(out))
io.Println(string(out))
}

// PrintTable prints each line of the objects contained in the table value
func PrintTable[T any](streams openhue.IOStreams, table []T, lineFn func(T) string, header ...string) {
func PrintTable[T any](io openhue.IOStreams, table []T, lineFn func(T) string, header ...string) {

w := tabwriter.NewWriter(streams.Out, 0, 0, 3, ' ', 0)
w := tabwriter.NewWriter(io.Out, 0, 0, 3, ' ', 0)

for _, h := range header {
_, _ = fmt.Fprint(w, h+"\t")
Expand Down

0 comments on commit 632bcd7

Please sign in to comment.