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.

135 lines
2.9 KiB

2 years ago
2 years ago
2 years ago
2 years ago
  1. package hue
  2. import (
  3. "context"
  4. "fmt"
  5. lucifer3 "git.aiterp.net/lucifer3/server"
  6. "git.aiterp.net/lucifer3/server/commands"
  7. "git.aiterp.net/lucifer3/server/events"
  8. "git.aiterp.net/lucifer3/server/internal/gentools"
  9. "sync"
  10. "time"
  11. )
  12. func NewService() lucifer3.ActiveService {
  13. return &service{
  14. bridges: map[string]*Bridge{},
  15. }
  16. }
  17. type service struct {
  18. mu sync.Mutex
  19. bridges map[string]*Bridge
  20. }
  21. func (s *service) Active() bool {
  22. return true
  23. }
  24. func (s *service) HandleCommand(bus *lucifer3.EventBus, command lucifer3.Command) {
  25. switch command := command.(type) {
  26. case commands.PairDevice:
  27. {
  28. if hostname, ok := command.Matches("hue"); ok {
  29. go func() {
  30. timeout, cancel := context.WithTimeout(context.Background(), time.Second*30)
  31. defer cancel()
  32. client := NewClient(hostname, "")
  33. token, err := client.Register(timeout)
  34. if err != nil {
  35. return
  36. }
  37. bus.RunEvent(events.DeviceAccepted{
  38. ID: command.ID,
  39. APIKey: token,
  40. })
  41. }()
  42. }
  43. }
  44. case commands.SetStateBatch:
  45. for _, bridge := range s.bridges {
  46. bridge.SetStates(command)
  47. }
  48. case commands.SetState:
  49. if sub, ok := command.Matches("hue"); ok {
  50. if s.bridges[sub] != nil {
  51. s.bridges[sub].SetStates(gentools.OneItemMap(command.ID, command.State))
  52. }
  53. }
  54. case commands.SearchDevices:
  55. if sub, ok := command.Matches("hue"); ok {
  56. if s.bridges[sub] != nil {
  57. go func() {
  58. err := s.bridges[sub].SearchDevices(time.Second * 30)
  59. if err != nil {
  60. bus.RunEvent(events.Log{
  61. ID: command.ID,
  62. Level: "error",
  63. Code: "search_failed",
  64. Message: "Could not search: " + err.Error(),
  65. })
  66. }
  67. }()
  68. }
  69. }
  70. case commands.ConnectDevice:
  71. if sub, ok := command.Matches("hue"); ok {
  72. if s.bridges[sub] != nil {
  73. s.bridges[sub].cancel()
  74. delete(s.bridges, sub)
  75. }
  76. ctx, cancel := context.WithCancel(context.Background())
  77. client := NewClient(sub, command.APIKey)
  78. bridge := NewBridge(sub, client)
  79. bridge.ctx = ctx
  80. bridge.cancel = cancel
  81. s.bridges[sub] = bridge
  82. go func() {
  83. bus.RunEvent(events.Log{
  84. ID: command.ID,
  85. Level: "info",
  86. Code: "connecting_device",
  87. Message: "Connecting to device...",
  88. })
  89. for bridge.ctx.Err() == nil {
  90. ctx2, cancel2 := context.WithCancel(ctx)
  91. err := bridge.Run(ctx2, bus)
  92. cancel2()
  93. if err != nil {
  94. bus.RunEvent(events.DeviceFailed{
  95. ID: command.ID,
  96. Error: fmt.Sprintf("Run failed: %s", err),
  97. })
  98. bus.RunEvent(events.Log{
  99. ID: command.ID,
  100. Level: "error",
  101. Code: "connect_failed",
  102. Message: fmt.Sprintf("Could not connect device: %s", err),
  103. })
  104. }
  105. select {
  106. case <-time.After(time.Second * 5):
  107. case <-ctx.Done():
  108. return
  109. }
  110. }
  111. }()
  112. }
  113. }
  114. }
  115. func (s *service) HandleEvent(_ *lucifer3.EventBus, event lucifer3.Event) {}