Move client library to separate repo
git.kill0.net/chill9/lifx-go
This commit is contained in:
		
							
								
								
									
										335
									
								
								client.go
									
									
									
									
									
								
							
							
						
						
									
										335
									
								
								client.go
									
									
									
									
									
								
							@@ -1,335 +0,0 @@
 | 
			
		||||
package lifx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	//"crypto/tls"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const defaultUserAgent = "lifx-go"
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	Client struct {
 | 
			
		||||
		accessToken string
 | 
			
		||||
		userAgent   string
 | 
			
		||||
		Client      *http.Client
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Result struct {
 | 
			
		||||
		Id     string `json:"id"`
 | 
			
		||||
		Label  string `json:"label"`
 | 
			
		||||
		Status Status `json:"status"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Error struct {
 | 
			
		||||
		Field   string   `json:"field"`
 | 
			
		||||
		Message []string `json:"message"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Warning struct {
 | 
			
		||||
		Warning string `json:"warning"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	RateLimit struct {
 | 
			
		||||
		Limit     int
 | 
			
		||||
		Remaining int
 | 
			
		||||
		Reset     time.Time
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Response struct {
 | 
			
		||||
		StatusCode int
 | 
			
		||||
		Header     http.Header
 | 
			
		||||
		Body       io.ReadCloser
 | 
			
		||||
		RateLimit  RateLimit
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LifxResponse struct {
 | 
			
		||||
		Error    string    `json:"error"`
 | 
			
		||||
		Errors   []Error   `json:"errors"`
 | 
			
		||||
		Warnings []Warning `json:"warnings"`
 | 
			
		||||
		Results  []Result  `json:"results"`
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var errorMap = map[int]error{
 | 
			
		||||
	http.StatusNotFound:            errors.New("Selector did not match any lights"),
 | 
			
		||||
	http.StatusUnauthorized:        errors.New("Bad access token"),
 | 
			
		||||
	http.StatusForbidden:           errors.New("Bad OAuth scope"),
 | 
			
		||||
	http.StatusUnprocessableEntity: errors.New("Missing or malformed parameters"),
 | 
			
		||||
	http.StatusUpgradeRequired:     errors.New("HTTP was used to make the request instead of HTTPS. Repeat the request using HTTPS instead"),
 | 
			
		||||
	http.StatusTooManyRequests:     errors.New("The request exceeded a rate limit"),
 | 
			
		||||
	http.StatusInternalServerError: errors.New("Something went wrong on LIFX's end"),
 | 
			
		||||
	http.StatusBadGateway:          errors.New("Something went wrong on LIFX's end"),
 | 
			
		||||
	http.StatusServiceUnavailable:  errors.New("Something went wrong on LIFX's end"),
 | 
			
		||||
	523:                            errors.New("Something went wrong on LIFX's end"),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewClient(accessToken string, options ...func(*Client)) *Client {
 | 
			
		||||
	var c *Client
 | 
			
		||||
	tr := &http.Transport{
 | 
			
		||||
		//TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c = &Client{
 | 
			
		||||
		accessToken: accessToken,
 | 
			
		||||
		Client:      &http.Client{Transport: tr},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, option := range options {
 | 
			
		||||
		option(c)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func WithUserAgent(userAgent string) func(*Client) {
 | 
			
		||||
	return func(c *Client) {
 | 
			
		||||
		c.userAgent = userAgent
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewClientWithUserAgent(accessToken string, userAgent string) *Client {
 | 
			
		||||
	tr := &http.Transport{
 | 
			
		||||
		//TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
 | 
			
		||||
	}
 | 
			
		||||
	return &Client{
 | 
			
		||||
		accessToken: accessToken,
 | 
			
		||||
		userAgent:   userAgent,
 | 
			
		||||
		Client:      &http.Client{Transport: tr},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewResponse(r *http.Response) (*Response, error) {
 | 
			
		||||
	resp := Response{
 | 
			
		||||
		StatusCode: r.StatusCode,
 | 
			
		||||
		Header:     r.Header,
 | 
			
		||||
		Body:       r.Body,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if t := r.Header.Get("X-RateLimit-Limit"); t != "" {
 | 
			
		||||
		if n, err := strconv.ParseInt(t, 10, 32); err == nil {
 | 
			
		||||
			resp.RateLimit.Limit = int(n)
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if t := r.Header.Get("X-RateLimit-Remaining"); t != "" {
 | 
			
		||||
		if n, err := strconv.ParseInt(t, 10, 32); err == nil {
 | 
			
		||||
			resp.RateLimit.Remaining = int(n)
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if t := r.Header.Get("X-RateLimit-Reset"); t != "" {
 | 
			
		||||
		if n, err := strconv.ParseInt(t, 10, 32); err == nil {
 | 
			
		||||
			resp.RateLimit.Reset = time.Unix(n, 0)
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Response) IsError() bool {
 | 
			
		||||
	return r.StatusCode > 299
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Response) GetLifxError() (err error) {
 | 
			
		||||
	var (
 | 
			
		||||
		s *LifxResponse
 | 
			
		||||
	)
 | 
			
		||||
	if err = json.NewDecoder(r.Body).Decode(&s); err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return errors.New(s.Error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) NewRequest(method, url string, body io.Reader) (req *http.Request, err error) {
 | 
			
		||||
	req, err = http.NewRequest(method, url, body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.accessToken))
 | 
			
		||||
	req.Header.Add("Content-Type", "application/json")
 | 
			
		||||
	req.Header.Add("User-Agent", c.userAgent)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) setState(selector string, state State) (*Response, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		j    []byte
 | 
			
		||||
		req  *http.Request
 | 
			
		||||
		r    *http.Response
 | 
			
		||||
		resp *Response
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if j, err = json.Marshal(state); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req, err = c.NewRequest("PUT", EndpointState(selector), bytes.NewBuffer(j)); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if r, err = c.Client.Do(req); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = NewResponse(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) setStates(selector string, states States) (*Response, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		j    []byte
 | 
			
		||||
		req  *http.Request
 | 
			
		||||
		r    *http.Response
 | 
			
		||||
		resp *Response
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if j, err = json.Marshal(states); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req, err = c.NewRequest("PUT", EndpointStates(), bytes.NewBuffer(j)); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if r, err = c.Client.Do(req); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = NewResponse(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) toggle(selector string, duration float64) (*Response, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		j    []byte
 | 
			
		||||
		req  *http.Request
 | 
			
		||||
		r    *http.Response
 | 
			
		||||
		resp *Response
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if j, err = json.Marshal(&Toggle{Duration: duration}); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req, err = c.NewRequest("POST", EndpointToggle(selector), bytes.NewBuffer(j)); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if r, err = c.Client.Do(req); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = NewResponse(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) validateColor(color Color) (*Response, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		req  *http.Request
 | 
			
		||||
		r    *http.Response
 | 
			
		||||
		resp *Response
 | 
			
		||||
		q    url.Values
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if req, err = c.NewRequest("GET", EndpointColor(), nil); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	q = req.URL.Query()
 | 
			
		||||
	q.Set("string", color.ColorString())
 | 
			
		||||
	req.URL.RawQuery = q.Encode()
 | 
			
		||||
 | 
			
		||||
	if r, err = c.Client.Do(req); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = NewResponse(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) listLights(selector string) (*Response, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		req  *http.Request
 | 
			
		||||
		r    *http.Response
 | 
			
		||||
		resp *Response
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if req, err = c.NewRequest("GET", EndpointListLights(selector), nil); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if r, err = c.Client.Do(req); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = NewResponse(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) stateDelta(selector string, delta StateDelta) (*Response, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		j    []byte
 | 
			
		||||
		req  *http.Request
 | 
			
		||||
		r    *http.Response
 | 
			
		||||
		resp *Response
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if j, err = json.Marshal(delta); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req, err = c.NewRequest("POST", EndpointStateDelta(selector), bytes.NewBuffer(j)); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if r, err = c.Client.Do(req); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = NewResponse(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -6,7 +6,7 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	lifx "git.kill0.net/chill9/lume"
 | 
			
		||||
	"git.kill0.net/chill9/lifx-go"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ import (
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	lifx "git.kill0.net/chill9/lume"
 | 
			
		||||
	"git.kill0.net/chill9/lifx-go"
 | 
			
		||||
	"github.com/BurntSushi/toml"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package lumecmd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	lifx "git.kill0.net/chill9/lume"
 | 
			
		||||
	"git.kill0.net/chill9/lifx-go"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func PoweroffCmd(args CmdArgs) (int, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package lumecmd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	lifx "git.kill0.net/chill9/lume"
 | 
			
		||||
	"git.kill0.net/chill9/lifx-go"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func PoweronCmd(args CmdArgs) (int, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ package lumecmd
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	lifx "git.kill0.net/chill9/lume"
 | 
			
		||||
	"git.kill0.net/chill9/lifx-go"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func SetColorCmd(args CmdArgs) (int, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package lumecmd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	lifx "git.kill0.net/chill9/lume"
 | 
			
		||||
	"git.kill0.net/chill9/lifx-go"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func SetStateCmd(args CmdArgs) (int, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package lumecmd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	lifx "git.kill0.net/chill9/lume"
 | 
			
		||||
	"git.kill0.net/chill9/lifx-go"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func SetWhiteCmd(args CmdArgs) (int, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	lifx "git.kill0.net/chill9/lume"
 | 
			
		||||
	"git.kill0.net/chill9/lifx-go"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func powerColor(s string) string {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										224
									
								
								color.go
									
									
									
									
									
								
							
							
						
						
									
										224
									
								
								color.go
									
									
									
									
									
								
							@@ -1,224 +0,0 @@
 | 
			
		||||
package lifx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	Color interface {
 | 
			
		||||
		ColorString() string
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	RGBColor struct {
 | 
			
		||||
		R, G, B uint8
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	HSBKColor struct {
 | 
			
		||||
		H *float32 `json:"hue"`
 | 
			
		||||
		S *float32 `json:"saturation"`
 | 
			
		||||
		B *float32 `json:"brightness"`
 | 
			
		||||
		K *int16   `json:"kelvin"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	NamedColor string
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	KelvinCandlelight    = 1500
 | 
			
		||||
	KelvinSunset         = 2000
 | 
			
		||||
	KelvinUltraWarm      = 2500
 | 
			
		||||
	KelvinIncandescent   = 2700
 | 
			
		||||
	KelvinWarm           = 3000
 | 
			
		||||
	KelvinCool           = 4000
 | 
			
		||||
	KelvinCoolDaylight   = 4500
 | 
			
		||||
	KelvinSoftDaylight   = 5000
 | 
			
		||||
	KelvinDaylight       = 5600
 | 
			
		||||
	KelvinNoonDaylight   = 6000
 | 
			
		||||
	KelvinBrightDaylight = 6500
 | 
			
		||||
	KelvinCloudDaylight  = 7000
 | 
			
		||||
	KelvinBlueDaylight   = 7500
 | 
			
		||||
	KelvinBlueOvercast   = 8000
 | 
			
		||||
	KelvinBlueIce        = 9000
 | 
			
		||||
 | 
			
		||||
	HueWhite  = 0
 | 
			
		||||
	HueRed    = 0
 | 
			
		||||
	HueOrange = 36
 | 
			
		||||
	HueYellow = 60
 | 
			
		||||
	HueGreen  = 120
 | 
			
		||||
	HueCyan   = 180
 | 
			
		||||
	HueBlue   = 250
 | 
			
		||||
	HuePurple = 280
 | 
			
		||||
	HuePink   = 325
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	DefaultWhites = map[string]int{
 | 
			
		||||
		"candlelight":    KelvinCandlelight,
 | 
			
		||||
		"sunset":         KelvinSunset,
 | 
			
		||||
		"ultrawarm":      KelvinUltraWarm,
 | 
			
		||||
		"incandescent":   KelvinIncandescent,
 | 
			
		||||
		"warm":           KelvinWarm,
 | 
			
		||||
		"cool":           KelvinCool,
 | 
			
		||||
		"cooldaylight":   KelvinCoolDaylight,
 | 
			
		||||
		"softdaylight":   KelvinSoftDaylight,
 | 
			
		||||
		"daylight":       KelvinDaylight,
 | 
			
		||||
		"noondaylight":   KelvinNoonDaylight,
 | 
			
		||||
		"brightdaylight": KelvinBrightDaylight,
 | 
			
		||||
		"clouddaylight":  KelvinCloudDaylight,
 | 
			
		||||
		"bluedaylight":   KelvinBlueDaylight,
 | 
			
		||||
		"blueovercast":   KelvinBlueOvercast,
 | 
			
		||||
		"blueice":        KelvinBlueIce,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func NewRGBColor(r, g, b uint8) (RGBColor, error) {
 | 
			
		||||
	var c RGBColor
 | 
			
		||||
	if (r < 0 || r > 255) && (g < 0 || r > 255) && (b < 0 || b > 255) {
 | 
			
		||||
		return c, errors.New("values must be between 0-255")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return RGBColor{R: r, G: g, B: b}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewHSColor(h, s float32) (HSBKColor, error) {
 | 
			
		||||
	var c HSBKColor
 | 
			
		||||
 | 
			
		||||
	if h < 0 || h > 360 {
 | 
			
		||||
		return c, errors.New("hue must be between 0.0-360.0")
 | 
			
		||||
	}
 | 
			
		||||
	if s < 0 || s > 1 {
 | 
			
		||||
		return c, errors.New("saturation must be between 0.0-1.0")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c = HSBKColor{
 | 
			
		||||
		H: Float32Ptr(h),
 | 
			
		||||
		S: Float32Ptr(s),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewHSBColor(h, s, b float32) (HSBKColor, error) {
 | 
			
		||||
	var c HSBKColor
 | 
			
		||||
 | 
			
		||||
	if h < 0 || h > 360 {
 | 
			
		||||
		return c, errors.New("hue must be between 0.0-360.0")
 | 
			
		||||
	}
 | 
			
		||||
	if s < 0 || s > 1 {
 | 
			
		||||
		return c, errors.New("saturation must be between 0.0-1.0")
 | 
			
		||||
	}
 | 
			
		||||
	if b < 0 || b > 1 {
 | 
			
		||||
		return c, errors.New("brightness must be between 0.0-1.0")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c = HSBKColor{
 | 
			
		||||
		H: Float32Ptr(h),
 | 
			
		||||
		S: Float32Ptr(s),
 | 
			
		||||
		B: Float32Ptr(b),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewRed() (HSBKColor, error)    { return NewHSColor(HueRed, 1) }
 | 
			
		||||
func NewOrange() (HSBKColor, error) { return NewHSColor(HueOrange, 1) }
 | 
			
		||||
func NewYellow() (HSBKColor, error) { return NewHSColor(HueYellow, 1) }
 | 
			
		||||
func NewGreen() (HSBKColor, error)  { return NewHSColor(HueGreen, 1) }
 | 
			
		||||
func NewCyan() (HSBKColor, error)   { return NewHSColor(HueCyan, 1) }
 | 
			
		||||
func NewPurple() (HSBKColor, error) { return NewHSColor(HuePurple, 1) }
 | 
			
		||||
func NewPink() (HSBKColor, error)   { return NewHSColor(HuePink, 1) }
 | 
			
		||||
 | 
			
		||||
func NewWhite(k int16) (HSBKColor, error) {
 | 
			
		||||
	var c HSBKColor
 | 
			
		||||
 | 
			
		||||
	if k < 1500 || k > 9000 {
 | 
			
		||||
		return c, errors.New("kelvin must be between 1500-9000")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c = HSBKColor{
 | 
			
		||||
		H: Float32Ptr(HueWhite),
 | 
			
		||||
		S: Float32Ptr(0.0),
 | 
			
		||||
		K: Int16Ptr(k),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewWhiteString(s string) (HSBKColor, error) {
 | 
			
		||||
	k, ok := DefaultWhites[s]
 | 
			
		||||
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return HSBKColor{}, fmt.Errorf("'%s' is not a valid default white", s)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NewWhite(int16(k))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c RGBColor) ColorString() string {
 | 
			
		||||
	return fmt.Sprintf("rgb:%d,%d,%d", c.R, c.G, c.B)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c RGBColor) Hex() string {
 | 
			
		||||
	return fmt.Sprintf("#%x%x%x", c.R, c.G, c.B)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c HSBKColor) ColorString() string {
 | 
			
		||||
	var s []string
 | 
			
		||||
	if c.H != nil {
 | 
			
		||||
		s = append(s, fmt.Sprintf("hue:%g", *c.H))
 | 
			
		||||
	}
 | 
			
		||||
	if c.S != nil {
 | 
			
		||||
		s = append(s, fmt.Sprintf("saturation:%g", *c.S))
 | 
			
		||||
	}
 | 
			
		||||
	if c.B != nil {
 | 
			
		||||
		s = append(s, fmt.Sprintf("brightness:%g", *c.B))
 | 
			
		||||
	}
 | 
			
		||||
	if c.K != nil {
 | 
			
		||||
		s = append(s, fmt.Sprintf("kelvin:%d", *c.K))
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Join(s, " ")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c HSBKColor) MarshalText() ([]byte, error) {
 | 
			
		||||
	return []byte(c.ColorString()), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c RGBColor) MarshalText() ([]byte, error) {
 | 
			
		||||
	return []byte(c.ColorString()), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c NamedColor) ColorString() string {
 | 
			
		||||
	return string(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) ValidateColor(color Color) (Color, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		s    *HSBKColor
 | 
			
		||||
		r    *http.Response
 | 
			
		||||
		resp *Response
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if resp, err = c.validateColor(color); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = NewResponse(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	if err = json.NewDecoder(resp.Body).Decode(&s); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								endpoints.go
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								endpoints.go
									
									
									
									
									
								
							@@ -1,35 +0,0 @@
 | 
			
		||||
package lifx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"path"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func BuildURL(rawurl, rawpath string) string {
 | 
			
		||||
	u, _ := url.Parse(rawurl)
 | 
			
		||||
	u.Path = path.Join(u.Path, rawpath)
 | 
			
		||||
	return u.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	Endpoint      = "https://api.lifx.com/v1"
 | 
			
		||||
	EndpointState = func(selector string) string {
 | 
			
		||||
		return BuildURL(Endpoint, fmt.Sprintf("/lights/%s/state", selector))
 | 
			
		||||
	}
 | 
			
		||||
	EndpointStateDelta = func(selector string) string {
 | 
			
		||||
		return BuildURL(Endpoint, fmt.Sprintf("/lights/%s/state/delta", selector))
 | 
			
		||||
	}
 | 
			
		||||
	EndpointListLights = func(selector string) string {
 | 
			
		||||
		return BuildURL(Endpoint, fmt.Sprintf("/lights/%s", selector))
 | 
			
		||||
	}
 | 
			
		||||
	EndpointStates = func() string {
 | 
			
		||||
		return BuildURL(Endpoint, "/lights/states")
 | 
			
		||||
	}
 | 
			
		||||
	EndpointColor = func() string {
 | 
			
		||||
		return BuildURL(Endpoint, "/color")
 | 
			
		||||
	}
 | 
			
		||||
	EndpointToggle = func(selector string) string {
 | 
			
		||||
		return BuildURL(Endpoint, fmt.Sprintf("/lights/%s/toggle", selector))
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							@@ -3,6 +3,7 @@ module git.kill0.net/chill9/lume
 | 
			
		||||
go 1.15
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	git.kill0.net/chill9/lifx-go v0.0.0-20210215004437-f86c28b0a5ef
 | 
			
		||||
	github.com/BurntSushi/toml v0.3.1
 | 
			
		||||
	golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							@@ -1,3 +1,5 @@
 | 
			
		||||
git.kill0.net/chill9/lifx-go v0.0.0-20210215004437-f86c28b0a5ef h1:8yyXAk+qiRvrowTeHHAOBZqGXXCr8SxWFydez61ZGp8=
 | 
			
		||||
git.kill0.net/chill9/lifx-go v0.0.0-20210215004437-f86c28b0a5ef/go.mod h1:ZFKIcwdJ4Nqlrkn/eUHbeLt0NVhFsfxBREkVoA+jzUc=
 | 
			
		||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 | 
			
		||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 | 
			
		||||
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061 h1:DQmQoKxQWtyybCtX/3dIuDBcAhFszqq8YiNeS6sNu1c=
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										221
									
								
								lights.go
									
									
									
									
									
								
							
							
						
						
									
										221
									
								
								lights.go
									
									
									
									
									
								
							@@ -1,221 +0,0 @@
 | 
			
		||||
package lifx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	//"crypto/tls"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	OK       Status = "ok"
 | 
			
		||||
	TimedOut Status = "timed_out"
 | 
			
		||||
	Offline  Status = "offline"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	Status string
 | 
			
		||||
 | 
			
		||||
	Selector struct {
 | 
			
		||||
		Id   string `json:"id"`
 | 
			
		||||
		Name string `json:"name"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Product struct {
 | 
			
		||||
		Name         string       `json:"name"`
 | 
			
		||||
		Identifier   string       `json:"identifier"`
 | 
			
		||||
		Company      string       `json:"company"`
 | 
			
		||||
		Capabilities Capabilities `json:"capabilities"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Capabilities struct {
 | 
			
		||||
		HasColor             bool    `json:"has_color"`
 | 
			
		||||
		HasVariableColorTemp bool    `json:"has_variable_color_temp"`
 | 
			
		||||
		HasIR                bool    `json:"has_ir"`
 | 
			
		||||
		HasChain             bool    `json:"has_chain"`
 | 
			
		||||
		HasMultizone         bool    `json:"has_multizone"`
 | 
			
		||||
		MinKelvin            float64 `json:"min_kelvin"`
 | 
			
		||||
		MaxKelvin            float64 `json:"max_kelvin"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Light struct {
 | 
			
		||||
		Id              string    `json:"id"`
 | 
			
		||||
		UUID            string    `json:"uuid"`
 | 
			
		||||
		Label           string    `json:"label"`
 | 
			
		||||
		Connected       bool      `json:"connected"`
 | 
			
		||||
		Power           string    `json:"power"`
 | 
			
		||||
		Color           HSBKColor `json:"color"`
 | 
			
		||||
		Brightness      float64   `json:"brightness"`
 | 
			
		||||
		Effect          string    `json:"effect"`
 | 
			
		||||
		Group           Selector  `json:"group"`
 | 
			
		||||
		Location        Selector  `json:"location"`
 | 
			
		||||
		Product         Product   `json:"product"`
 | 
			
		||||
		LastSeen        time.Time `json:"last_seen"`
 | 
			
		||||
		SecondsLastSeen float64   `json:"seconds_last_seen"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	State struct {
 | 
			
		||||
		Power      string  `json:"power,omitempty"`
 | 
			
		||||
		Color      Color   `json:"color,omitempty"`
 | 
			
		||||
		Brightness float64 `json:"brightness,omitempty"`
 | 
			
		||||
		Duration   float64 `json:"duration,omitempty"`
 | 
			
		||||
		Infrared   float64 `json:"infrared,omitempty"`
 | 
			
		||||
		Fast       bool    `json:"fast,omitempty"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	StateDelta struct {
 | 
			
		||||
		Power      *string  `json:"power,omitempty"`
 | 
			
		||||
		Duration   *float64 `json:"duration,omitempty"`
 | 
			
		||||
		Infrared   *float64 `json:"infrared,omitempty"`
 | 
			
		||||
		Hue        *float64 `json:"hue,omitempty"`
 | 
			
		||||
		Saturation *float64 `json:"saturation,omitempty"`
 | 
			
		||||
		Brightness *float64 `json:"brightness,omitempty"`
 | 
			
		||||
		Kelvin     *int     `json:"kelvin,omitempty"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	StateWithSelector struct {
 | 
			
		||||
		State
 | 
			
		||||
		Selector string `json:"selector"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	States struct {
 | 
			
		||||
		States   []StateWithSelector `json:"states,omitempty"`
 | 
			
		||||
		Defaults State               `json:"defaults,omitempty"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Toggle struct {
 | 
			
		||||
		Duration float64 `json:"duration,omitempty"`
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (c *Client) SetState(selector string, state State) (*LifxResponse, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		s    *LifxResponse
 | 
			
		||||
		resp *Response
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if resp, err = c.setState(selector, state); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	if resp.IsError() {
 | 
			
		||||
		return nil, resp.GetLifxError()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if state.Fast && resp.StatusCode == http.StatusAccepted {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = json.NewDecoder(resp.Body).Decode(&s); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) FastSetState(selector string, state State) (*LifxResponse, error) {
 | 
			
		||||
	state.Fast = true
 | 
			
		||||
	return c.SetState(selector, state)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) SetStates(selector string, states States) (*LifxResponse, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		s    *LifxResponse
 | 
			
		||||
		resp *Response
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if resp, err = c.setStates(selector, states); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	if err = json.NewDecoder(resp.Body).Decode(&s); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) StateDelta(selector string, delta StateDelta) (*LifxResponse, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		s    *LifxResponse
 | 
			
		||||
		resp *Response
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if resp, err = c.stateDelta(selector, delta); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	if err = json.NewDecoder(resp.Body).Decode(&s); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) Toggle(selector string, duration float64) (*LifxResponse, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		s    *LifxResponse
 | 
			
		||||
		resp *Response
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if resp, err = c.toggle(selector, duration); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	if resp.IsError() {
 | 
			
		||||
		return nil, resp.GetLifxError()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = json.NewDecoder(resp.Body).Decode(&s); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) ListLights(selector string) ([]Light, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err  error
 | 
			
		||||
		s    []Light
 | 
			
		||||
		resp *Response
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if resp, err = c.listLights(selector); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode > 299 {
 | 
			
		||||
		return nil, resp.GetLifxError()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = json.NewDecoder(resp.Body).Decode(&s); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) PowerOff(selector string) (*LifxResponse, error) {
 | 
			
		||||
	return c.SetState(selector, State{Power: "off"})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) FastPowerOff(selector string) {
 | 
			
		||||
	c.SetState(selector, State{Power: "off", Fast: true})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) PowerOn(selector string) (*LifxResponse, error) {
 | 
			
		||||
	return c.SetState(selector, State{Power: "on"})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) FastPowerOn(selector string) {
 | 
			
		||||
	c.SetState(selector, State{Power: "on", Fast: true})
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user