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.

136 lines
3.1 KiB

2 years ago
2 years ago
2 years ago
2 years ago
  1. package nanoleaf
  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. "strings"
  9. "time"
  10. )
  11. func NewService() lucifer3.ActiveService {
  12. return &service{
  13. bridges: make(map[string]*bridge),
  14. cancels: make(map[string]context.CancelFunc),
  15. }
  16. }
  17. type service struct {
  18. bridges map[string]*bridge
  19. cancels map[string]context.CancelFunc
  20. }
  21. func (s *service) Active() bool {
  22. return true
  23. }
  24. func (s *service) HandleEvent(*lucifer3.EventBus, lucifer3.Event) {}
  25. func (s *service) HandleCommand(bus *lucifer3.EventBus, command lucifer3.Command) {
  26. switch command := command.(type) {
  27. case commands.SetState:
  28. if sub, ok := command.Matches("nanoleaf"); ok && s.bridges[sub] != nil {
  29. s.bridges[sub].Update(command.ID, command.State)
  30. }
  31. case commands.SetStateBatch:
  32. for _, b := range s.bridges {
  33. b.UpdateBatch(command)
  34. }
  35. case commands.SearchDevices:
  36. if sub, ok := command.Matches("nanoleaf"); ok {
  37. if s.bridges[sub] != nil {
  38. go func(bridge *bridge) {
  39. newIDs, err := bridge.Refresh(context.Background())
  40. if err != nil {
  41. bus.RunEvent(events.DeviceFailed{
  42. ID: command.ID,
  43. Error: fmt.Sprintf("Search failed: %s", err),
  44. })
  45. return
  46. }
  47. if len(newIDs) > 0 {
  48. for _, event := range bridge.HardwareEvents() {
  49. bus.RunEvent(event)
  50. }
  51. for _, id := range newIDs {
  52. bus.RunEvent(events.DeviceReady{ID: id})
  53. }
  54. }
  55. }(s.bridges[sub])
  56. }
  57. }
  58. case commands.PairDevice:
  59. if address, ok := command.Matches("nanoleaf"); ok {
  60. go func() {
  61. timeout, cancel := context.WithTimeout(context.Background(), time.Second*5)
  62. defer cancel()
  63. apiKey, info, err := Discover(timeout, address, true)
  64. if err != nil {
  65. bus.RunEvent(events.DeviceFailed{
  66. ID: command.ID,
  67. Error: fmt.Sprintf("Pairing failed: %s", err),
  68. })
  69. return
  70. }
  71. bus.RunEvent(events.DeviceAccepted{
  72. ID: command.ID,
  73. APIKey: apiKey,
  74. Extras: nil,
  75. })
  76. bus.RunEvent(events.HardwareMetadata{
  77. ID: command.ID,
  78. Icon: "bridge",
  79. SerialNumber: info.SerialNumber,
  80. FirmwareVersion: strings.Join([]string{
  81. info.FirmwareVersion, info.BootloaderVersion, info.HardwareVersion,
  82. }, "; "),
  83. })
  84. }()
  85. }
  86. case commands.ConnectDevice:
  87. if sub, ok := command.Matches("nanoleaf"); ok {
  88. if s.bridges[sub] != nil {
  89. s.cancels[sub]()
  90. }
  91. ctx, cancel := context.WithCancel(context.Background())
  92. s.bridges[sub] = &bridge{
  93. host: sub,
  94. apiKey: command.APIKey,
  95. panels: make([]*panel, 0, 64),
  96. panelIDMap: make(map[uint16]string),
  97. }
  98. s.cancels[sub] = cancel
  99. go func() {
  100. for ctx.Err() == nil {
  101. ctx2, cancel2 := context.WithCancel(ctx)
  102. err := s.bridges[sub].Run(ctx2, bus)
  103. cancel2()
  104. if err != nil {
  105. bus.RunEvent(events.DeviceFailed{
  106. ID: command.ID,
  107. Error: fmt.Sprintf("Run failed: %s", err),
  108. })
  109. }
  110. select {
  111. case <-time.After(time.Second * 5):
  112. case <-ctx.Done():
  113. return
  114. }
  115. }
  116. }()
  117. }
  118. }
  119. }