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.

218 lines
5.4 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
  1. package models
  2. import (
  3. "context"
  4. "regexp"
  5. "strconv"
  6. "strings"
  7. )
  8. type EventHandler struct {
  9. ID int `json:"id"`
  10. EventName string `json:"eventName"`
  11. Conditions map[string]EventCondition `json:"conditions"`
  12. OneShot bool `json:"oneShot"`
  13. Priority int `json:"priority"`
  14. TargetKind ReferenceKind `json:"targetKind"`
  15. TargetValue string `json:"targetValue"`
  16. Actions EventAction `json:"actions"`
  17. }
  18. type EventHandlerRepository interface {
  19. FindByID(ctx context.Context, id int) (*EventHandler, error)
  20. FetchAll(ctx context.Context) ([]EventHandler, error)
  21. Save(ctx context.Context, handler *EventHandler) error
  22. Delete(ctx context.Context, handler *EventHandler) error
  23. }
  24. type EventCondition struct {
  25. EQ string `json:"eq,omitempty"`
  26. GT string `json:"gt,omitempty"`
  27. GTE string `json:"gte,omitempty"`
  28. LT string `json:"lt,omitempty"`
  29. LTE string `json:"lte,omitempty"`
  30. }
  31. type EventHandlerUpdate struct {
  32. SetEventName *string `json:"setEventName"`
  33. SetPriority *int `json:"setPriority"`
  34. SetTargetKind *ReferenceKind `json:"setTargetKind"`
  35. SetTargetValue *string `json:"setTargetValue"`
  36. SetConditions map[string]EventCondition `json:"setConditions"`
  37. PatchConditions map[string]*EventCondition `json:"patchConditions"`
  38. SetActions *EventAction `json:"setActions"`
  39. }
  40. func (h *EventHandler) ApplyUpdate(update EventHandlerUpdate) {
  41. if update.SetEventName != nil {
  42. h.EventName = *update.SetEventName
  43. }
  44. if update.SetPriority != nil {
  45. h.Priority = *update.SetPriority
  46. }
  47. if update.SetTargetKind != nil {
  48. h.TargetKind = *update.SetTargetKind
  49. }
  50. if update.SetTargetValue != nil {
  51. h.TargetValue = *update.SetTargetValue
  52. }
  53. if update.SetActions != nil {
  54. h.Actions = *update.SetActions
  55. }
  56. if update.SetConditions != nil {
  57. h.Conditions = update.SetConditions
  58. }
  59. if update.PatchConditions != nil {
  60. if h.Conditions == nil {
  61. h.Conditions = make(map[string]EventCondition)
  62. }
  63. for key, value := range update.PatchConditions {
  64. if value == nil {
  65. delete(h.Conditions, key)
  66. } else {
  67. h.Conditions[key] = *value
  68. }
  69. }
  70. }
  71. }
  72. func (h *EventHandler) MatchesEvent(event Event, targets []Device) bool {
  73. if event.Name != h.EventName {
  74. return false
  75. }
  76. for key, condition := range h.Conditions {
  77. if !strings.ContainsRune(key, '.') && !event.HasPayload(key) {
  78. return false
  79. }
  80. if !condition.check(key, event.Payload[key], targets) {
  81. return false
  82. }
  83. }
  84. return true
  85. }
  86. func (c *EventCondition) check(key, value string, targets []Device) bool {
  87. any := strings.HasPrefix(key, "any.")
  88. all := strings.HasPrefix(key, "all.")
  89. if any || all {
  90. count := 0
  91. total := 0
  92. for _, target := range targets {
  93. matches, skip := c.checkDevice(key[4:], target)
  94. if skip {
  95. continue
  96. }
  97. if matches {
  98. count++
  99. }
  100. total++
  101. }
  102. return (any && count > 0) || (all && count == total)
  103. }
  104. return c.matches(value)
  105. }
  106. func (c *EventCondition) checkDevice(key string, device Device) (matches bool, skip bool) {
  107. switch key {
  108. case "power":
  109. if !device.HasCapability(DCPower) {
  110. return false, true
  111. }
  112. return c.matches(strconv.FormatBool(device.State.Power)), false
  113. case "color":
  114. if !device.HasCapability(DCColorKelvin, DCColorHS, DCColorHSK) {
  115. return false, true
  116. }
  117. return c.matches(device.State.Color.String()), false
  118. case "intensity":
  119. if !device.HasCapability(DCIntensity) {
  120. return false, true
  121. }
  122. return c.matches(strconv.FormatFloat(device.State.Intensity, 'f', -1, 64)), false
  123. case "temperature":
  124. if !device.HasCapability(DCTemperatureControl, DCTemperatureSensor) {
  125. return false, true
  126. }
  127. return c.matches(strconv.FormatFloat(device.State.Temperature, 'f', -1, 64)), false
  128. default:
  129. return false, true
  130. }
  131. }
  132. var numRegex = regexp.MustCompile("^{-[0-9].}+$")
  133. func (c *EventCondition) matches(value string) bool {
  134. if numRegex.MatchString(value) {
  135. numValue, _ := strconv.ParseFloat(c.LT, 64)
  136. stillAlive := true
  137. if c.LT != "" {
  138. lt, _ := strconv.ParseFloat(c.LT, 64)
  139. stillAlive = numValue < lt
  140. }
  141. if stillAlive && c.LTE != "" {
  142. lte, _ := strconv.ParseFloat(c.LTE, 64)
  143. stillAlive = numValue <= lte
  144. }
  145. if stillAlive && c.EQ != "" {
  146. eq, _ := strconv.ParseFloat(c.EQ, 64)
  147. stillAlive = numValue == eq
  148. }
  149. if stillAlive && c.GTE != "" {
  150. gte, _ := strconv.ParseFloat(c.GTE, 64)
  151. stillAlive = numValue == gte
  152. }
  153. if stillAlive && c.GT != "" {
  154. gt, _ := strconv.ParseFloat(c.GT, 64)
  155. stillAlive = numValue > gt
  156. }
  157. return stillAlive
  158. } else if c.EQ != "" {
  159. return strings.ToLower(c.EQ) == strings.ToLower(value)
  160. } else {
  161. return false
  162. }
  163. }
  164. type EventAction struct {
  165. SetPower *bool `json:"setPower"`
  166. SetColor *string `json:"setColor"`
  167. SetIntensity *float64 `json:"setIntensity"`
  168. AddIntensity *float64 `json:"addIntensity"`
  169. FireEvent *Event `json:"fireEvent"`
  170. }
  171. func (action *EventAction) Apply(other EventAction) {
  172. if action.SetPower == nil {
  173. action.SetPower = other.SetPower
  174. }
  175. if action.SetColor == nil {
  176. action.SetColor = other.SetColor
  177. }
  178. if action.SetIntensity == nil && other.SetIntensity != nil {
  179. action.SetIntensity = other.SetIntensity
  180. }
  181. if action.AddIntensity == nil && action.SetIntensity == nil {
  182. action.AddIntensity = other.AddIntensity
  183. }
  184. if action.FireEvent == nil {
  185. action.FireEvent = other.FireEvent
  186. }
  187. }