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.

191 lines
4.5 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. package services
  2. import (
  3. "context"
  4. "fmt"
  5. "git.aiterp.net/lucifer/new-server/app/config"
  6. "git.aiterp.net/lucifer/new-server/models"
  7. "log"
  8. "math"
  9. "sort"
  10. "strconv"
  11. "strings"
  12. "sync"
  13. "time"
  14. )
  15. func StartEventHandler() {
  16. config.EventChannel <- models.Event{Name: "LuciferStarted"}
  17. go func() {
  18. for event := range config.EventChannel {
  19. responses := handleEvent(event)
  20. for _, response := range responses {
  21. handleEvent(response)
  22. }
  23. }
  24. }()
  25. // Generate TimeChanged event
  26. go func() {
  27. drift := time.Now().Add(time.Minute).Truncate(time.Minute).Sub(time.Now())
  28. time.Sleep(drift + time.Millisecond*5)
  29. for range time.NewTicker(time.Minute).C {
  30. config.EventChannel <- models.Event{Name: "TimeChanged", Payload: map[string]string{
  31. "weekdayName": time.Now().In(loc).Format("Monday"),
  32. "month": time.Now().In(loc).Format("01"),
  33. "year": time.Now().In(loc).Format("2006"),
  34. }}
  35. }
  36. }()
  37. }
  38. var loc, _ = time.LoadLocation("Europe/Oslo")
  39. var ctx = context.Background()
  40. func handleEvent(event models.Event) (responses []models.Event) {
  41. startTime := time.Now()
  42. defer func() {
  43. duration := time.Since(startTime)
  44. if duration > time.Millisecond*250 {
  45. log.Println(event.Name, "took long to handle:", duration)
  46. }
  47. }()
  48. if !event.HasPayload("hour") {
  49. event.AddPayload("hour", time.Now().In(loc).Format("15"))
  50. }
  51. if !event.HasPayload("minute") {
  52. event.AddPayload("minute", time.Now().In(loc).Format("04"))
  53. }
  54. err := handleSpecial(event)
  55. if err != nil {
  56. log.Printf("Special event handler error (%s): %v", event.Name, err)
  57. return
  58. }
  59. paramStrings := make([]string, 0, 8)
  60. for key, value := range event.Payload {
  61. paramStrings = append(paramStrings, fmt.Sprintf("%s=%s", key, value))
  62. }
  63. sort.Strings(paramStrings)
  64. log.Printf("Event %s(%s)", event.Name, strings.Join(paramStrings, ", "))
  65. handlers, err := config.EventHandlerRepository().FetchAll(ctx)
  66. if err != nil {
  67. log.Printf("Error fetchin' event halders: %s", err)
  68. return
  69. }
  70. allDevices := make([]models.Device, 0, 16)
  71. actions := make(map[int]models.EventAction, 16)
  72. priorities := make(map[int]int, 16)
  73. highestPriority := 0
  74. var prioritizedEvent *models.Event
  75. for _, handler := range handlers {
  76. if handler.EventName != event.Name {
  77. continue
  78. }
  79. devices, err := config.DeviceRepository().FetchByReference(ctx, handler.TargetKind, handler.TargetValue)
  80. if err != nil {
  81. log.Printf("Error fetchin' event devices: %s", err)
  82. return
  83. }
  84. if !handler.MatchesEvent(event, devices) {
  85. continue
  86. }
  87. if handler.Priority > highestPriority {
  88. highestPriority = handler.Priority
  89. prioritizedEvent = handler.Actions.FireEvent
  90. }
  91. for _, device := range devices {
  92. _, ok := actions[device.ID]
  93. if !ok {
  94. allDevices = append(allDevices, device)
  95. actions[device.ID] = handler.Actions
  96. priorities[device.ID] = handler.Priority
  97. } else if handler.Priority > priorities[device.ID] {
  98. actions[device.ID] = handler.Actions
  99. priorities[device.ID] = handler.Priority
  100. }
  101. }
  102. }
  103. if prioritizedEvent != nil {
  104. responses = append(responses, *prioritizedEvent)
  105. }
  106. for i, device := range allDevices {
  107. action := actions[device.ID]
  108. newState := models.NewDeviceState{}
  109. newState.Color = action.SetColor
  110. newState.Power = action.SetPower
  111. if action.SetIntensity != nil {
  112. newState.Intensity = action.SetIntensity
  113. } else if action.AddIntensity != nil {
  114. newIntensity := math.Max(0, math.Min(1, device.State.Intensity+*action.AddIntensity))
  115. newState.Intensity = &newIntensity
  116. }
  117. err = allDevices[i].SetState(newState)
  118. if err != nil {
  119. log.Println("Error updating state for device", device.ID, "err:", err)
  120. }
  121. }
  122. config.PublishChannel <- allDevices
  123. wg := sync.WaitGroup{}
  124. for _, device := range allDevices {
  125. wg.Add(1)
  126. go func(device models.Device) {
  127. err := config.DeviceRepository().Save(context.Background(), &device)
  128. if err != nil {
  129. log.Println("Failed to save device for state:", err)
  130. }
  131. wg.Done()
  132. }(device)
  133. }
  134. wg.Wait()
  135. return
  136. }
  137. func handleSpecial(event models.Event) error {
  138. switch event.Name {
  139. case models.ENBridgeConnected:
  140. bridgeId, _ := strconv.Atoi(event.Payload["bridgeId"])
  141. bridge, err := config.BridgeRepository().Find(ctx, bridgeId)
  142. if err != nil {
  143. return err
  144. }
  145. devices, err := config.DeviceRepository().FetchByReference(ctx, models.RKBridgeID, event.Payload["bridgeId"])
  146. if err != nil {
  147. return err
  148. }
  149. driver, err := config.DriverProvider().Provide(bridge.Driver)
  150. if err != nil {
  151. return err
  152. }
  153. return driver.Publish(ctx, bridge, devices)
  154. default:
  155. return nil
  156. }
  157. }