You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
2.8 KiB
121 lines
2.8 KiB
package hue2
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"encoding/xml"
|
|
"fmt"
|
|
"git.aiterp.net/lucifer/new-server/internal/lerrors"
|
|
"git.aiterp.net/lucifer/new-server/models"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type Driver struct {
|
|
mu sync.Mutex
|
|
bridges []*Bridge
|
|
}
|
|
|
|
func (d *Driver) SearchBridge(ctx context.Context, address, token string, dryRun bool) ([]models.Bridge, error) {
|
|
if address == "" {
|
|
if !dryRun {
|
|
return nil, lerrors.ErrAddressOnlyDryRunnable
|
|
}
|
|
|
|
res, err := http.Get("https://discovery.meethue.com")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
entries := make([]DiscoveryEntry, 0, 8)
|
|
err = json.NewDecoder(res.Body).Decode(&entries)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
bridges := make([]models.Bridge, 0, len(entries))
|
|
for _, entry := range entries {
|
|
bridges = append(bridges, models.Bridge{
|
|
ID: -1,
|
|
Name: entry.Id,
|
|
Driver: models.DTHue2,
|
|
Address: entry.InternalIPAddress,
|
|
Token: "",
|
|
})
|
|
}
|
|
|
|
return bridges, nil
|
|
}
|
|
|
|
deviceInfo := BridgeDeviceInfo{}
|
|
res, err := http.Get(fmt.Sprintf("http://%s/description.xml", address))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer res.Body.Close()
|
|
err = xml.NewDecoder(res.Body).Decode(&deviceInfo)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
bridge := models.Bridge{
|
|
ID: -1,
|
|
Name: deviceInfo.Device.FriendlyName,
|
|
Driver: models.DTHue2,
|
|
Address: address,
|
|
Token: "",
|
|
}
|
|
|
|
if !dryRun {
|
|
client := NewClient(address, "")
|
|
|
|
timeout, cancel := context.WithTimeout(ctx, time.Second*30)
|
|
defer cancel()
|
|
|
|
bridge.Token, err = client.Register(timeout)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return []models.Bridge{bridge}, nil
|
|
}
|
|
|
|
func (d *Driver) SearchDevices(ctx context.Context, bridge models.Bridge, timeout time.Duration) ([]models.Device, error) {
|
|
return d.ensureBridge(bridge).SearchDevices(ctx, timeout)
|
|
}
|
|
|
|
func (d *Driver) ListDevices(_ context.Context, bridge models.Bridge) ([]models.Device, error) {
|
|
return d.ensureBridge(bridge).GenerateDevices(), nil
|
|
}
|
|
|
|
func (d *Driver) Publish(_ context.Context, bridge models.Bridge, devices []models.Device) error {
|
|
d.ensureBridge(bridge).Update(devices...)
|
|
return nil
|
|
}
|
|
|
|
func (d *Driver) Run(ctx context.Context, bridge models.Bridge, ch chan<- models.Event) error {
|
|
return d.ensureBridge(bridge).Run(ctx, ch)
|
|
}
|
|
|
|
func (d *Driver) ForgetDevice(ctx context.Context, bridge models.Bridge, device models.Device) error {
|
|
return d.ensureBridge(bridge).Forget(ctx, device)
|
|
}
|
|
|
|
func (d *Driver) ensureBridge(info models.Bridge) *Bridge {
|
|
d.mu.Lock()
|
|
for _, bridge := range d.bridges {
|
|
if bridge.client.host == info.Address {
|
|
d.mu.Unlock()
|
|
return bridge
|
|
}
|
|
}
|
|
bridge := NewBridge(NewClient(info.Address, info.Token))
|
|
bridge.externalID = info.ID
|
|
d.bridges = append(d.bridges, bridge)
|
|
d.mu.Unlock()
|
|
|
|
return bridge
|
|
}
|