Skip to content

Commit

Permalink
feat: add requesting of device state
Browse files Browse the repository at this point in the history
  • Loading branch information
MoonLiightz committed Jan 4, 2021
1 parent d7bb4a8 commit d2d6620
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 1 deletion.
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func main() {
Commands: []*cli.Command{
appcli.Command.Color,
appcli.Command.State,
appcli.Command.Status,
appcli.Command.Discover,
},
}
Expand Down
40 changes: 40 additions & 0 deletions examples/state/main.go
Original file line number Diff line number Diff line change
@@ -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)
}
50 changes: 50 additions & 0 deletions internal/appcli/command.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package appcli

import (
"encoding/json"
"fmt"
"net"
"strings"
Expand All @@ -14,6 +15,7 @@ import (
type command struct {
Color *cli.Command
State *cli.Command
Status *cli.Command
Discover *cli.Command
}

Expand Down Expand Up @@ -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: "<ip>",
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"},
Expand Down
9 changes: 9 additions & 0 deletions internal/appcli/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
},
}
1 change: 1 addition & 0 deletions pkg/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ type command struct {
on []byte
off []byte
color []byte
state []byte
}
34 changes: 34 additions & 0 deletions pkg/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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},
},
}

Expand Down Expand Up @@ -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()
Expand Down
10 changes: 10 additions & 0 deletions pkg/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit d2d6620

Please sign in to comment.