diff --git a/README.md b/README.md index 1a7b77e..7f877f3 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ An extensive Philips Hue client library for [`Go`](https://golang.org/) with an ![](./logo.png) -_This project is currently in **ALPHA** and not recommended for production use. All help in any form is highly appreciated. You are more than welcome to contact me if you have feedback, feature requests, report bugs etc._ +_This project is currently in **BETA** and not recommended for production use. All help in any form is highly appreciated. You are more than welcome to contact me if you have feedback, feature requests, report bugs etc._ Ses [godoc.org/github.com/amimof/huego](https://godoc.org/github.com/amimof/huego) for the full package documentation. @@ -17,7 +17,7 @@ Get the package go get github.com/amimof/huego ``` -Include it in your code. You may use `huego.New()` if you've already created a user and know the ip-address/hostname to your bridge. +Include it in your code. You may use [`New()`](https://godoc.org/github.com/amimof/huego#New) if you have already created an user and know the IP address to your bridge. ```Go package main @@ -27,16 +27,16 @@ import ( ) func main() { - bridge, err := huego.New("192.168.1.59", "username") + bridge := huego.New("192.168.1.59", "username") l, err := bridge.GetLights() if err != nil { - fmt.Fatal(err) + panic(err) } fmt.Printf("Found %d lights", len(l)) } ``` -To discover new bridges and add an user, use `huego.Discover()` and `huego.Login()` +Discover a bridge on your network with [`Discover()`](https://godoc.org/github.com/amimof/huego#Discover) and create a new user with [`CreateUser()`](https://godoc.org/github.com/amimof/huego#Bridge.CreateUser). ```Go func main() { bridge, _ := huego.Discover() @@ -49,34 +49,7 @@ func main() { ## Documentation -See [godoc.org/github.com/amimof/huego](https://godoc.org/github.com/amimof/huego). +See [godoc.org/github.com/amimof/huego](https://godoc.org/github.com/amimof/huego) -## Project Status - -This project is currently in **ALPHA** and still under heavy development. Current iteration is subject to big changes until the initial release. Below is the current status of *modules* that are expected to be implemented. - -| Module | Functions | Tests | -| ------ | ------ | ------ | -| Lights | `Complete` | `Complete` | -| Groups | `Complete` | `Complete` | -| Sensors | `Complete` | `Complete` | -| Schedules | `Complete` | `Complete` | -| Scenes | `Complete` | `Complete` | -| Rules | `Complete` | `Complete` | -| Resourcelinks | `Complete` | `Complete` | -| Configuration | `Complete` | `Complete` | -| Capabilities | `Complete` | `Complete` | - -Other than above core modules, each module needs additional *helper* methods for conveniance and flavour. The goal is to keep it simple, and not to bloat the library with functionality that developers might want to write on their own. - -## Goal - -The goal of this project is to provide an easy to use, stable and extensive library that is up to spec with the official [Philips Hue API](https://www.developers.meethue.com/philips-hue-api). It should be possible to interact with *all* API endpoints that is available on a Philips Hue bridge through the package(s) in this repository. - -## To-Do - -* Add helper methods on each module -* ~~Add `SetSceneLightState`~~ -* ~~Add `RecallScene`~~ -* ~~Finish `Capabilities`~~ -* More tests \ No newline at end of file +## Testing +The tests requires an accessible Philips Hue Bridge IP address and a pre-configured username for authenticating. Before running the tests, make sure to set the environment variables `HUE_HOSTNAME` and `HUE_USERNAME`. If you don't have an username, you may create one using [`CreateUser()`](https://godoc.org/github.com/amimof/huego#Bridge.CreateUser) or refer to the official [Getting Started Guide](https://www.developers.meethue.com/documentation/getting-started). \ No newline at end of file diff --git a/bridge.go b/bridge.go index 29a1f3d..b974c10 100644 --- a/bridge.go +++ b/bridge.go @@ -34,8 +34,9 @@ func (b *Bridge) getAPIPath(str ...string) (string, error) { return u.String(), nil } -// Login calls New() and passes Host on this Bridge instance +// Login calls New() and passes Host on this Bridge instance. func (b *Bridge) Login(u string) *Bridge { + b.User = u return New(b.Host, u) } @@ -1561,10 +1562,10 @@ func (b *Bridge) DeleteSensor(i int) error { } // UpdateSensorConfig updates the configuration of one sensor. The allowed configuration parameters depend on the sensor type -func (b *Bridge) UpdateSensorConfig(i int, config *SensorConfig) (*Response, error) { +func (b *Bridge) UpdateSensorConfig(i int, c interface{}) (*Response, error) { var a []*APIResponse - data, err := json.Marshal(&config) + data, err := json.Marshal(&c) if err != nil { return nil, err } diff --git a/config_test.go b/config_test.go index 0e1f345..48ffd17 100644 --- a/config_test.go +++ b/config_test.go @@ -6,7 +6,6 @@ import ( "testing" ) -// O60ECZZJhwrTI8AkY1xjOK5ifj20igjw6R5WsWih func TestGetConfig(t *testing.T) { b := huego.New(os.Getenv("HUE_HOSTNAME"), os.Getenv("HUE_USERNAME")) config, err := b.GetConfig() @@ -67,7 +66,7 @@ func TestGetConfig(t *testing.T) { func TestCreateUser(t *testing.T) { b := huego.New(os.Getenv("HUE_HOSTNAME"), "") - u, err := b.CreateUser("github.com/amimof/huego#tests") + u, err := b.CreateUser("github.com/amimof/huego#go test") if err != nil { t.Fatal(err) } else { @@ -92,11 +91,18 @@ func TestGetUsers(t *testing.T) { func TestDeleteUser(t *testing.T) { b := huego.New(os.Getenv("HUE_HOSTNAME"), os.Getenv("HUE_USERNAME")) - uid := "9zLKE0LNZOJuLDGI6QYjQpWHmVTWO7BVwuirvIbh" - err := b.DeleteUser(uid) + users, err := b.GetUsers() if err != nil { t.Fatal(err) - } else { - t.Logf("Deleted user %s", uid) } + for _, user := range users { + if user.Name == "huego#tests" { + err := b.DeleteUser(user.Username) + if err != nil { + t.Fatal(err) + } + t.Logf("Deleted user '%s' (%s)", user.Name, user.Username) + } + } + } diff --git a/huego.go b/huego.go index 8a47ff4..f8fe10f 100644 --- a/huego.go +++ b/huego.go @@ -22,7 +22,7 @@ type APIError struct { Description string } -// Response is a wrapper struct of the success response returned from the bridge after a successfull API call. +// Response is a wrapper struct of the success response returned from the bridge after a successful API call. type Response struct { Success map[string]interface{} } @@ -166,7 +166,8 @@ func delete(url string) ([]byte, error) { } -// DiscoverAll performs a discovery on the network looking for bridges using https://www.meethue.com/api/nupnp service +// DiscoverAll performs a discovery on the network looking for bridges using https://www.meethue.com/api/nupnp service. +// DiscoverAll returns a list of Bridge objects. func DiscoverAll() ([]Bridge, error) { res, err := get("https://www.meethue.com/api/nupnp") @@ -185,7 +186,8 @@ func DiscoverAll() ([]Bridge, error) { } -// Discover performs a discovery on the network looking for bridges using https://www.meethue.com/api/nupnp service. Returns the first bridge if any found +// Discover performs a discovery on the network looking for bridges using https://www.meethue.com/api/nupnp service. +// Discover uses DiscoverAll() but only returns the first instance in the array of bridges if any. func Discover() (*Bridge, error) { var b *Bridge @@ -203,7 +205,9 @@ func Discover() (*Bridge, error) { } -// New instantiates and returns a new Bridge +// New instantiates and returns a new Bridge. New accepts hostname/ip address to the bridge (h) as well as an username (u). +// h may or may not be prefixed with http(s)://. For example http://192.168.1.20/ or 192.168.1.20. +// u is a username known to the bridge. Use Discover() and CreateUser() to create a user. func New(h, u string) *Bridge { return &Bridge{h, u, ""} } diff --git a/huego_test.go b/huego_test.go index 1057028..0f5b13b 100644 --- a/huego_test.go +++ b/huego_test.go @@ -1,5 +1,9 @@ package huego_test +// I'm too lazy to have this elsewhere +// export HUE_USERNAME=9D6iHMbM-Bt7Kd0Cwh9Quo4tE02FMnmrNrnFAdAq +// export HUE_HOSTNAME=192.168.1.59 + import ( "github.com/amimof/huego" "testing" diff --git a/sensor.go b/sensor.go index 4b07147..62b0525 100644 --- a/sensor.go +++ b/sensor.go @@ -2,8 +2,8 @@ package huego // Sensor represents a bridge sensor https://developers.meethue.com/documentation/sensors-api type Sensor struct { - State *SensorState `json:"state,omitempty"` - Config *SensorConfig `json:"config,omitempty"` + State interface{} `json:"state,omitempty"` + Config interface{} `json:"config,omitempty"` Name string `json:"name,omitempty"` Type string `json:"type,omitempty"` ModelID string `json:"modelid,omitempty"` @@ -12,19 +12,19 @@ type Sensor struct { ID int `json:",omitempty"` } -// SensorState defines the state a sensor has -type SensorState struct { - Daylight string `json:"daylight,omitempty"` - LastUpdated string `json:"lastupdated,omitempty"` -} +// // SensorState defines the state a sensor has +// type SensorState struct { +// Daylight string `json:"daylight,omitempty"` +// LastUpdated string `json:"lastupdated,omitempty"` +// } -// SensorConfig defines the configuration of a sensor -type SensorConfig struct { - On bool `json:"on,omitempty"` - Configured bool `json:"configured,omitempty"` - SunriseOffset int `json:"sunriseoffset,omitempty"` - SunsetOffset int `json:"sunsetoffset,omitempty"` -} +// // SensorConfig defines the configuration of a sensor +// type SensorConfig struct { +// On bool `json:"on,omitempty"` +// Configured bool `json:"configured,omitempty"` +// SunriseOffset int `json:"sunriseoffset,omitempty"` +// SunsetOffset int `json:"sunsetoffset,omitempty"` +// } // NewSensor defines a list of sensors discovered the last time the bridge performed a sensor discovery. // Also stores the timestamp the last time a discovery was performed. diff --git a/sensor_test.go b/sensor_test.go index 4518084..c6c6025 100644 --- a/sensor_test.go +++ b/sensor_test.go @@ -14,7 +14,16 @@ func TestGetSensors(t *testing.T) { } t.Logf("Found %d sensors", len(sensors)) for _, sensor := range sensors { - t.Logf("Sensor id=%d name=%s", sensor.ID, sensor.Name) + t.Logf("State:") + t.Logf(" Interface: %+v", sensor.State) + t.Logf("Config:") + t.Logf(" On: %+v", sensor.Config) + t.Logf("Name: %s", sensor.Name) + t.Logf("Type: %s", sensor.Type) + t.Logf("ModelID: %s", sensor.ModelID) + t.Logf("ManufacturerName: %s", sensor.ManufacturerName) + t.Logf("SwVersion: %s", sensor.SwVersion) + t.Logf("ID: %d", sensor.ID) } } @@ -27,11 +36,20 @@ func TestGetSensor(t *testing.T) { t.Logf("Found %d sensors", len(sensors)) for _, sensor := range sensors { t.Logf("Getting sensor %d, skipping the rest", sensor.ID) - s, err := b.GetSensor(sensor.ID) + sensor, err := b.GetSensor(sensor.ID) if err != nil { t.Fatal(err) } - t.Logf("Got sensor name=%s", s.Name) + t.Logf("State:") + t.Logf(" Interface: %+v", sensor.State) + t.Logf("Config:") + t.Logf(" On: %+v", sensor.Config) + t.Logf("Name: %s", sensor.Name) + t.Logf("Type: %s", sensor.Type) + t.Logf("ModelID: %s", sensor.ModelID) + t.Logf("ManufacturerName: %s", sensor.ManufacturerName) + t.Logf("SwVersion: %s", sensor.SwVersion) + t.Logf("ID: %d", sensor.ID) break } } @@ -43,12 +61,12 @@ func TestCreateSensor(t *testing.T) { }) if err != nil { t.Fatal(err) - } else { - t.Logf("Sensor created") - for k, v := range resp.Success { - t.Logf("%v: %s", k, v) - } + } + t.Logf("Sensor created") + for k, v := range resp.Success { + t.Logf("%v: %s", k, v) } + } func TestFindSensors(t *testing.T) { @@ -56,11 +74,11 @@ func TestFindSensors(t *testing.T) { resp, err := b.FindSensors() if err != nil { t.Fatal(err) - } else { - for k, v := range resp.Success { - t.Logf("%v: %s", k, v) - } + } + for k, v := range resp.Success { + t.Logf("%v: %s", k, v) } + } func TestGetNewSensors(t *testing.T) { @@ -72,13 +90,9 @@ func TestGetNewSensors(t *testing.T) { t.Logf("Sensors:") for _, sensor := range newSensors.Sensors { t.Logf("State:") - t.Logf(" Daylight: %s", sensor.State.Daylight) - t.Logf(" LastUpdated: %s", sensor.State.LastUpdated) + t.Logf(" Interface: %+v", sensor.State) t.Logf("Config:") - t.Logf(" On: %t", sensor.Config.On) - t.Logf(" Configured: %t", sensor.Config.Configured) - t.Logf(" SunriseOffset: %d", sensor.Config.SunriseOffset) - t.Logf(" SunsetOffset: %d", sensor.Config.SunsetOffset) + t.Logf(" On: %+v", sensor.Config) t.Logf("Name: %s", sensor.Name) t.Logf("Type: %s", sensor.Type) t.Logf("ModelID: %s", sensor.ModelID) @@ -96,11 +110,11 @@ func TestUpdateSensor(t *testing.T) { }) if err != nil { t.Fatal(err) - } else { - for k, v := range resp.Success { - t.Logf("%v: %s", k, v) - } + } + for k, v := range resp.Success { + t.Logf("%v: %s", k, v) } + } func TestDeleteSensor(t *testing.T) { @@ -109,7 +123,6 @@ func TestDeleteSensor(t *testing.T) { err := b.DeleteSensor(id) if err != nil { t.Fatal(err) - } else { - t.Logf("Sensor %d deleted", id) - } + } + t.Logf("Sensor %d deleted", id) }