diff --git a/README.md b/README.md index 3ad7226..455f2db 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ This repository offers the possibility to control Magic Home (Magic Hue) LED Str - Change the state of the LED Strip Controller to on or off - Change the color of the LED Strip Controller with RGBW +- Request the current state ot the LED Strip Controller - Provides a simple ready-to-use CLI - Can be used as a library to control the controller in your own applications @@ -36,6 +37,7 @@ USAGE: COMMANDS: color, c Set the color of the LED Strip state, s Switch the LED Strip state to on or off + status Prints the status of the LED Strip discover, d Discover for Magic Home devices on the network help, h Shows a list of commands or help for one command @@ -68,6 +70,14 @@ $ ./magic-home color 192.168.1.42 255 0 0 0 $ ./magic-home color 192.168.1.42 0 255 255 0 ``` +- Request the status of a device +```bash +$ ./magic-home status 192.168.1.42 + +# You can also get the response as JSON +$ ./magic-home status --json 192.168.1.42 +``` + > Change `192.168.1.42` to the IP of your Controller. > If your controller only supports RGB instead of RGBW, just set the last value to 0. @@ -100,10 +110,27 @@ controller.SetColor(magichome.Color{ W: 0, }) +// Get the current state of the device +// The response looks like +// { +// "DeviceType": 51, +// "State": 1, +// "LedVersionNumber": 6, +// "Mode": 97, +// "Slowness": 15, +// "Color": { +// "R": 21, +// "G": 77, +// "B": 70, +// "W": 0 +// } +// } +deviceState, _ := controller.GetDeviceState() + // Don't forget to close the connection to the LED Strip Controller controller.Close() ``` -For a ready-to-use example take a look at [examples/basic/main.go](examples/basic/main.go). +For a ready-to-use example take a look at [examples/basic/main.go](examples/basic/main.go) or generally in the [examples](examples/) folder. ## License diff --git a/cmd/main.go b/cmd/main.go index e70a01f..d8c2bc2 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -15,6 +15,7 @@ func main() { Commands: []*cli.Command{ appcli.Command.Color, appcli.Command.State, + appcli.Command.Status, appcli.Command.Discover, }, } diff --git a/examples/state/main.go b/examples/state/main.go new file mode 100644 index 0000000..f96c18e --- /dev/null +++ b/examples/state/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + "net" + "os" + + magichome "github.com/moonliightz/magic-home/pkg" +) + +func checkError(e error) { + if e != nil { + fmt.Println("Error: ", e) + os.Exit(1) + } +} + +func main() { + // Create a new Magic Home LED Strip Controller + controller, err := magichome.New(net.ParseIP("192.168.42.105"), 5577) + checkError(err) + + // Get device state + var deviceState *magichome.DeviceState + deviceState, err = controller.GetDeviceState() + checkError(err) + + // Work with the response (print it) + fmt.Printf("Device is: ") + if deviceState.State == magichome.On { + fmt.Println("On") + } else { + fmt.Println("Off") + } + fmt.Printf("Color: \tR: %d \n\tG: %d \n\tB: %d \n\tW: %d\n", deviceState.Color.R, deviceState.Color.G, deviceState.Color.B, deviceState.Color.W) + + // And finaly close the connection to LED Strip Controller + err = controller.Close() + checkError(err) +} diff --git a/internal/appcli/command.go b/internal/appcli/command.go index 39ffed1..1dd1f2f 100644 --- a/internal/appcli/command.go +++ b/internal/appcli/command.go @@ -1,6 +1,7 @@ package appcli import ( + "encoding/json" "fmt" "net" "strings" @@ -14,6 +15,7 @@ import ( type command struct { Color *cli.Command State *cli.Command + Status *cli.Command Discover *cli.Command } @@ -101,6 +103,54 @@ var Command = command{ return nil }, }, + Status: &cli.Command{ + Name: "status", + Aliases: []string{}, + Usage: "Prints the status of the LED Strip", + ArgsUsage: "", + Flags: []cli.Flag{Flag.Port, Flag.JSON}, + Action: func(c *cli.Context) error { + ipArg := c.Args().Get(0) + if ip := net.ParseIP(ipArg); ip != nil { + controller, err := magichome.New(ip, uint16(c.Int("port"))) + if err != nil { + return err + } + + var deviceState *magichome.DeviceState + deviceState, err = controller.GetDeviceState() + if err != nil { + return err + } + + if c.Bool("json") { + res, err := json.Marshal(deviceState) + if err != nil { + return err + } + fmt.Println(string(res)) + } else { + fmt.Printf("Device is: ") + if deviceState.State == magichome.On { + fmt.Println("On") + } else { + fmt.Println("Off") + } + fmt.Printf("Color: \tR: %d \n\tG: %d \n\tB: %d \n\tW: %d\n", deviceState.Color.R, deviceState.Color.G, deviceState.Color.B, deviceState.Color.W) + } + + err = controller.Close() + if err != nil { + return err + } + } else { + fmt.Println("Invalid IP: ", ipArg) + cli.ShowCommandHelpAndExit(c, "status", 1) + } + + return nil + }, + }, Discover: &cli.Command{ Name: "discover", Aliases: []string{"d"}, diff --git a/internal/appcli/flag.go b/internal/appcli/flag.go index 63cd1b9..0317796 100644 --- a/internal/appcli/flag.go +++ b/internal/appcli/flag.go @@ -6,6 +6,7 @@ type flag struct { Port *cli.IntFlag BroadcastAddr *cli.StringFlag Timeout *cli.IntFlag + JSON *cli.BoolFlag } // Flag contains the options for the CLI @@ -34,4 +35,12 @@ var Flag = flag{ Value: 1, Required: false, }, + JSON: &cli.BoolFlag{ + Name: "json", + Aliases: []string{}, + Usage: "return output as a JSON-String", + DefaultText: "false", + Value: false, + Required: false, + }, } diff --git a/pkg/command.go b/pkg/command.go index b94fd5c..b0de119 100644 --- a/pkg/command.go +++ b/pkg/command.go @@ -4,4 +4,5 @@ type command struct { on []byte off []byte color []byte + state []byte } diff --git a/pkg/controller.go b/pkg/controller.go index fe319cf..020e585 100644 --- a/pkg/controller.go +++ b/pkg/controller.go @@ -22,6 +22,7 @@ func New(ip net.IP, port uint16) (*Controller, error) { on: []byte{0x71, 0x23, 0x94}, off: []byte{0x71, 0x24, 0x95}, color: []byte{0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + state: []byte{0x81, 0x8a, 0x8b, 0x96}, }, } @@ -69,6 +70,39 @@ func (c *Controller) SetColor(color Color) error { return nil } +// GetDeviceState can be used to get information about the state of the LED Strip +func (c *Controller) GetDeviceState() (*DeviceState, error) { + + _, err := c.conn.Write(c.command.state) + if err != nil { + return nil, err + } + + response := make([]byte, 14) + _, err = c.conn.Read(response) + if err != nil { + return nil, err + } + + deviceState := DeviceState{} + deviceState.DeviceType = response[1] + deviceState.Mode = response[3] + deviceState.Slowness = response[5] + deviceState.Color.R = response[6] + deviceState.Color.G = response[7] + deviceState.Color.B = response[8] + deviceState.Color.W = response[9] + deviceState.LedVersionNumber = response[10] + + if response[2] == 0x23 { + deviceState.State = On + } else { + deviceState.State = Off + } + + return &deviceState, nil +} + // Close closes the tcp connection to the LED Strip func (c *Controller) Close() error { return c.conn.Close() diff --git a/pkg/state.go b/pkg/state.go index 006e416..9fe6bf2 100644 --- a/pkg/state.go +++ b/pkg/state.go @@ -10,3 +10,13 @@ const ( // Off represents the switched-off state of the device Off State = 0 ) + +// DeviceState represents the state of the device +type DeviceState struct { + DeviceType uint8 + State State + LedVersionNumber uint8 + Mode uint8 + Slowness uint8 + Color Color +}