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

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
}