diff --git a/internal/drivers/hue2/bridge.go b/internal/drivers/hue2/bridge.go index 2839acf..767c2f5 100644 --- a/internal/drivers/hue2/bridge.go +++ b/internal/drivers/hue2/bridge.go @@ -556,3 +556,52 @@ func (b *Bridge) applyPatches(patches []ResourceData) { b.resources = newResources b.mu.Unlock() } + +func (b *Bridge) SearchDevices(ctx context.Context, timeout time.Duration) ([]models.Device, error) { + // Record the current state. + b.mu.Lock() + before := b.resources + b.mu.Unlock() + + // Spend half the time waiting for devices + // TODO: Wait for v2 endpoint + err := b.client.LegacyDiscover(ctx, "sensors") + if err != nil { + return nil, err + } + select { + case <-time.After(timeout / 1): + case <-ctx.Done(): + return nil, ctx.Err() + } + + // Spend half the time waiting for lights + // TODO: Wait for v2 endpoint + err = b.client.LegacyDiscover(ctx, "lights") + if err != nil { + return nil, err + } + select { + case <-time.After(timeout / 1): + case <-ctx.Done(): + return nil, ctx.Err() + } + + // Perform a full refresh. + err = b.RefreshAll(ctx) + if err != nil { + return nil, err + } + + // Check for new devices + devices := b.GenerateDevices() + newDevices := make([]models.Device, 0) + for _, device := range devices { + if before[device.InternalID] == nil { + newDevices = append(newDevices, device) + } + } + + // Return said devices. + return newDevices, nil +} diff --git a/internal/drivers/hue2/client.go b/internal/drivers/hue2/client.go index de71a72..a97cfa7 100644 --- a/internal/drivers/hue2/client.go +++ b/internal/drivers/hue2/client.go @@ -92,8 +92,12 @@ func (c *Client) UpdateResource(ctx context.Context, link ResourceLink, update R return c.put(ctx, link.Path(), update, nil) } +func (c *Client) LegacyDiscover(ctx context.Context, kind string) error { + return c.legacyPost(ctx, kind, nil, nil) +} + func (c *Client) SSE(ctx context.Context) <-chan SSEUpdate { - ch := make(chan SSEUpdate, 4)0 + ch := make(chan SSEUpdate, 4) go func() { defer close(ch) @@ -264,6 +268,43 @@ func (c *Client) post(ctx context.Context, path string, body interface{}, target return json.NewDecoder(res.Body).Decode(&target) } +func (c *Client) legacyPost(ctx context.Context, resource string, body interface{}, target interface{}) error { + select { + case <-ctx.Done(): + return ctx.Err() + case <-c.ch: + defer func() { + c.ch <- struct{}{} + }() + } + + rb, err := reqBody(body) + if err != nil { + return err + } + + if c.token != "" { + resource = c.token + "/" + resource + } + + req, err := http.NewRequest("POST", fmt.Sprintf("http://%s/api/%s", c.host, resource), rb) + if err != nil { + return err + } + + res, err := httpClient.Do(req.WithContext(ctx)) + if err != nil { + return err + } + defer res.Body.Close() + + if target == nil { + return nil + } + + return json.NewDecoder(res.Body).Decode(target) +} + func reqBody(body interface{}) (io.Reader, error) { if body == nil { return nil, nil diff --git a/internal/drivers/hue2/data.go b/internal/drivers/hue2/data.go index da2a947..a48bcdd 100644 --- a/internal/drivers/hue2/data.go +++ b/internal/drivers/hue2/data.go @@ -5,7 +5,6 @@ import ( "encoding/xml" "fmt" "git.aiterp.net/lucifer/new-server/models" - "log" "strings" "time" ) @@ -205,8 +204,6 @@ func (r ResourceUpdate) MarshalJSON() ([]byte, error) { chunks = append(chunks, fmt.Sprintf(`"dynamics":{"duration":%d}`, r.TransitionDuration.Truncate(time.Millisecond*100).Milliseconds())) } - log.Println(fmt.Sprintf("{%s}", strings.Join(chunks, ","))) - return []byte(fmt.Sprintf("{%s}", strings.Join(chunks, ","))), nil } diff --git a/internal/drivers/hue2/driver.go b/internal/drivers/hue2/driver.go index cf89914..d176ce5 100644 --- a/internal/drivers/hue2/driver.go +++ b/internal/drivers/hue2/driver.go @@ -83,7 +83,7 @@ func (d *Driver) SearchBridge(ctx context.Context, address, token string, dryRun } func (d *Driver) SearchDevices(ctx context.Context, bridge models.Bridge, timeout time.Duration) ([]models.Device, error) { - return nil, nil + return d.ensureBridge(bridge).SearchDevices(ctx, timeout) } func (d *Driver) ListDevices(_ context.Context, bridge models.Bridge) ([]models.Device, error) {