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.

116 lines
2.6 KiB

  1. package hue2
  2. import (
  3. "context"
  4. "encoding/json"
  5. "encoding/xml"
  6. "fmt"
  7. "git.aiterp.net/lucifer/new-server/models"
  8. "net/http"
  9. "sync"
  10. "time"
  11. )
  12. type Driver struct {
  13. mu sync.Mutex
  14. bridges []*Bridge
  15. }
  16. func (d *Driver) SearchBridge(ctx context.Context, address, token string, dryRun bool) ([]models.Bridge, error) {
  17. if address == "" {
  18. if !dryRun {
  19. return nil, models.ErrAddressOnlyDryRunnable
  20. }
  21. res, err := http.Get("https://discovery.meethue.com")
  22. if err != nil {
  23. return nil, err
  24. }
  25. defer res.Body.Close()
  26. entries := make([]DiscoveryEntry, 0, 8)
  27. err = json.NewDecoder(res.Body).Decode(&entries)
  28. if err != nil {
  29. return nil, err
  30. }
  31. bridges := make([]models.Bridge, 0, len(entries))
  32. for _, entry := range entries {
  33. bridges = append(bridges, models.Bridge{
  34. ID: -1,
  35. Name: entry.Id,
  36. Driver: models.DTHue2,
  37. Address: entry.InternalIPAddress,
  38. Token: "",
  39. })
  40. }
  41. return bridges, nil
  42. }
  43. deviceInfo := BridgeDeviceInfo{}
  44. res, err := http.Get(fmt.Sprintf("http://%s/description.xml", address))
  45. if err != nil {
  46. return nil, err
  47. }
  48. defer res.Body.Close()
  49. err = xml.NewDecoder(res.Body).Decode(&deviceInfo)
  50. if err != nil {
  51. return nil, err
  52. }
  53. bridge := models.Bridge{
  54. ID: -1,
  55. Name: deviceInfo.Device.FriendlyName,
  56. Driver: models.DTHue2,
  57. Address: address,
  58. Token: "",
  59. }
  60. if !dryRun {
  61. client := NewClient(address, "")
  62. timeout, cancel := context.WithTimeout(ctx, time.Second*30)
  63. defer cancel()
  64. bridge.Token, err = client.Register(timeout)
  65. if err != nil {
  66. return nil, err
  67. }
  68. }
  69. return []models.Bridge{bridge}, nil
  70. }
  71. func (d *Driver) SearchDevices(ctx context.Context, bridge models.Bridge, timeout time.Duration) ([]models.Device, error) {
  72. return d.ensureBridge(bridge).SearchDevices(ctx, timeout)
  73. }
  74. func (d *Driver) ListDevices(_ context.Context, bridge models.Bridge) ([]models.Device, error) {
  75. return d.ensureBridge(bridge).GenerateDevices(), nil
  76. }
  77. func (d *Driver) Publish(_ context.Context, bridge models.Bridge, devices []models.Device) error {
  78. d.ensureBridge(bridge).Update(devices...)
  79. return nil
  80. }
  81. func (d *Driver) Run(ctx context.Context, bridge models.Bridge, ch chan<- models.Event) error {
  82. return d.ensureBridge(bridge).Run(ctx, ch)
  83. }
  84. func (d *Driver) ensureBridge(info models.Bridge) *Bridge {
  85. d.mu.Lock()
  86. for _, bridge := range d.bridges {
  87. if bridge.client.host == info.Address {
  88. d.mu.Unlock()
  89. return bridge
  90. }
  91. }
  92. bridge := NewBridge(NewClient(info.Address, info.Token))
  93. bridge.externalID = info.ID
  94. d.bridges = append(d.bridges, bridge)
  95. d.mu.Unlock()
  96. return bridge
  97. }