diff --git a/README.md b/README.md index 0902374..a4315fd 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,14 @@ This project synchronizes your RGB lamp (connected via Home Assistant) with the ## 🧪 Example ```sh -ha-rgb-screen -url http://homeassistant.local:8123/api/webhook/xxxxx -screen 0 -delay 500 -delay 0.5 +ha-rgb-screen -url http://homeassistant.local:8123 -webhook xxxxxxxxxx -state input_boolean.ambiance_tv -screen 0 -delay 500 -delay 0.5 ``` Runs the RGB Screen Sync tool and connects it to your Home Assistant instance via a webhook: -- `-url` specifies the webhook endpoint used to send color updates +- `-url` specifies the webhook endpoint used to send color updates (without trailing slash) +- `-webhook` specifies the webhook name +- `-state` specifies the id of the entity that enable the light ambiance - `-screen 0` selects the first display (useful if multiple monitors are connected) - `-delay 500` sets the delay between color updates to 500 milliseconds - `-delta` sets the minimum delta to update the color ([Wikipedia: CIEDE2000](https://en.wikipedia.org/wiki/Color_difference#CIEDE2000)) diff --git a/cmd/main.go b/cmd/main.go index 526a1f0..0916057 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -24,6 +24,22 @@ func main() { var prevValue color.RGB for { + enabled, err := client.IsAmbianceEnabled() + + if err != nil { + log.Printf("[error] %s\n", err.Error()) + time.Sleep(3 * time.Second) + continue + } + + if !enabled { + if params.Debug { + log.Print("[debug] Ambiance is disabled\n") + time.Sleep(3 * time.Second) + continue + } + } + capture, err := s.Capture() if err == nil { @@ -37,7 +53,7 @@ func main() { if delta > params.Delta { prevValue = nextValue - if err := client.Update(nextValue); err != nil && !params.Debug { + if err := client.UpdateLight(nextValue); err != nil && !params.Debug { log.Printf("[error] %s\n", err.Error()) } } diff --git a/internal/config/config.go b/internal/config/config.go index b4bf412..b4a5c6a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -3,13 +3,16 @@ package config import "flag" type Config struct { - Url string - Delay int - Screen int - Delta float64 - Verbose bool - Debug bool - Usage func() + Url string + WebhookName string + StateId string + Token string + Delay int + Screen int + Delta float64 + Verbose bool + Debug bool + Usage func() } func (c *Config) IsValid() bool { @@ -17,11 +20,26 @@ func (c *Config) IsValid() bool { return false } + if c.WebhookName == "" { + return false + } + + if c.StateId == "" { + return false + } + + if c.Token == "" { + return false + } + return true } func GetConfig() *Config { - url := flag.String("url", "", "Webhook URL") + url := flag.String("url", "", "Home assistant base URL") + webhookName := flag.String("webhook", "", "Webhook name") + token := flag.String("token", "", "Token") + stateId := flag.String("state", "", "state entity name") delay := flag.Int("delay", 500, "Delay in ms") screen := flag.Int("screen", 0, "Screen index") delta := flag.Float64("delta", 0.5, "Mininum delta to update the color") @@ -31,12 +49,15 @@ func GetConfig() *Config { flag.Parse() return &Config{ - Url: *url, - Delay: *delay, - Screen: *screen, - Delta: *delta, - Verbose: *verbose, - Debug: *debug, - Usage: flag.Usage, + Url: *url, + WebhookName: *webhookName, + StateId: *stateId, + Token: *token, + Delay: *delay, + Screen: *screen, + Delta: *delta, + Verbose: *verbose, + Debug: *debug, + Usage: flag.Usage, } } diff --git a/internal/ha/client.go b/internal/ha/client.go index 7ef5f83..eb2ac58 100644 --- a/internal/ha/client.go +++ b/internal/ha/client.go @@ -2,7 +2,9 @@ package ha import ( "bytes" + "encoding/json" "fmt" + "io" "log" "net/http" @@ -22,7 +24,44 @@ func NewClient(params *config.Config) *Client { } } -func (c *Client) Update(rgb color.RGB) error { +func (c *Client) IsAmbianceEnabled() (bool, error) { + req, err := http.NewRequest( + "GET", + c.params.Url+"/api/states/"+c.params.StateId, + nil, + ) + + if err != nil { + return false, err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+c.params.Token) + + resp, err := c.client.Do(req) + + if err != nil { + return false, err + } + + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + + type value struct { + State string `json:"state"` + } + + v := new(value) + err = json.Unmarshal(body, v) + + if err != nil { + return false, err + } + + return v.State == "on", err +} + +func (c *Client) UpdateLight(rgb color.RGB) error { data := fmt.Sprintf(`{"rgb": [%.0f, %.0f, %.0f]}`, rgb.R, rgb.G, rgb.B) if c.params.Verbose { @@ -31,7 +70,7 @@ func (c *Client) Update(rgb color.RGB) error { req, err := http.NewRequest( "POST", - c.params.Url, + c.params.Url+"/api/webhook/"+c.params.WebhookName, bytes.NewBuffer([]byte(data)), )