Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 

220 righe
5.8 KiB

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "math"
  6. "strconv"
  7. "time"
  8. "github.com/AFASystems/presence/internal/pkg/config"
  9. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  10. "github.com/AFASystems/presence/internal/pkg/model"
  11. "github.com/AFASystems/presence/internal/pkg/mqttclient"
  12. presenseredis "github.com/AFASystems/presence/internal/pkg/redis"
  13. "github.com/redis/go-redis/v9"
  14. )
  15. func main() {
  16. // Load global context to init beacons and latest list
  17. appCtx := model.AppContext{
  18. Beacons: model.BeaconsList{
  19. Beacons: make(map[string]model.Beacon),
  20. },
  21. LatestList: model.LatestBeaconsList{
  22. LatestList: make(map[string]model.Beacon),
  23. },
  24. Settings: model.Settings{
  25. Settings: model.SettingsVal{
  26. Location_confidence: 4,
  27. Last_seen_threshold: 15,
  28. Beacon_metrics_size: 30,
  29. HA_send_interval: 5,
  30. HA_send_changes_only: false,
  31. },
  32. },
  33. }
  34. cfg := config.Load()
  35. // Kafka writer idk why yet
  36. writer := kafkaclient.KafkaWriter(cfg.KafkaURL, "beacons")
  37. defer writer.Close()
  38. // Kafka reader for Raw MQTT beacons
  39. rawReader := kafkaclient.KafkaReader(cfg.KafkaURL, "rawbeacons", "someID")
  40. defer rawReader.Close()
  41. // Kafka reader for API server updates
  42. apiReader := kafkaclient.KafkaReader(cfg.KafkaURL, "apibeacons", "someID")
  43. defer apiReader.Close()
  44. // Kafka reader for latest list updates
  45. latestReader := kafkaclient.KafkaReader(cfg.KafkaURL, "latestbeacons", "someID")
  46. defer latestReader.Close()
  47. // Kafka reader for settings updates
  48. settingsReader := kafkaclient.KafkaReader(cfg.KafkaURL, "settings", "someID")
  49. defer settingsReader.Close()
  50. ctx := context.Background()
  51. // Init Redis Client
  52. client := redis.NewClient(&redis.Options{
  53. Addr: cfg.RedisURL,
  54. Password: "",
  55. })
  56. beaconsList := presenseredis.LoadBeaconsList(client, ctx)
  57. appCtx.Beacons.Beacons = beaconsList
  58. latestList := presenseredis.LoadLatestList(client, ctx)
  59. appCtx.LatestList.LatestList = latestList
  60. settings := presenseredis.LoadSettings(client, ctx)
  61. appCtx.Settings.Settings = settings
  62. // declare channel for collecting Kafka messages
  63. chRaw := make(chan model.Incoming_json, 2000)
  64. chApi := make(chan model.ApiUpdate, 2000)
  65. chLatest := make(chan model.Incoming_json, 2000)
  66. chSettings := make(chan model.SettingsVal, 10)
  67. go kafkaclient.Consume(rawReader, chRaw)
  68. go kafkaclient.Consume(apiReader, chApi)
  69. go kafkaclient.Consume(latestReader, chLatest)
  70. go kafkaclient.Consume(settingsReader, chSettings)
  71. go func() {
  72. // Syncing Redis cache every 1s with 2 lists: beacons, latest list
  73. ticker := time.NewTicker(1 * time.Second)
  74. defer ticker.Stop()
  75. for range ticker.C {
  76. presenseredis.SaveBeaconsList(&appCtx, client, ctx)
  77. presenseredis.SaveLatestList(&appCtx, client, ctx)
  78. presenseredis.SaveSettings(&appCtx, client, ctx)
  79. }
  80. }()
  81. for {
  82. select {
  83. case msg := <-chRaw:
  84. processIncoming(msg, &appCtx)
  85. case msg := <-chApi:
  86. switch msg.Method {
  87. case "POST":
  88. appCtx.Beacons.Lock.Lock()
  89. appCtx.Beacons.Beacons[msg.Beacon.Beacon_id] = msg.Beacon
  90. case "DELETE":
  91. _, exists := appCtx.Beacons.Beacons[msg.ID]
  92. if exists {
  93. appCtx.Beacons.Lock.Lock()
  94. delete(appCtx.Beacons.Beacons, msg.ID)
  95. }
  96. default:
  97. fmt.Println("unknown method: ", msg.Method)
  98. }
  99. appCtx.Beacons.Lock.Unlock()
  100. case msg := <-chLatest:
  101. fmt.Println("latest msg: ", msg)
  102. case msg := <-chSettings:
  103. appCtx.Settings.Lock.Lock()
  104. appCtx.Settings.Settings = msg
  105. fmt.Println("settings channel: ", msg)
  106. appCtx.Settings.Lock.Unlock()
  107. }
  108. }
  109. }
  110. func processIncoming(incoming model.Incoming_json, ctx *model.AppContext) {
  111. defer func() {
  112. if err := recover(); err != nil {
  113. fmt.Println("work failed:", err)
  114. }
  115. }()
  116. fmt.Println("message came")
  117. incoming = mqttclient.IncomingBeaconFilter(incoming)
  118. id := mqttclient.GetBeaconID(incoming)
  119. now := time.Now().Unix()
  120. beacons := &ctx.Beacons
  121. beacons.Lock.Lock()
  122. defer beacons.Lock.Unlock()
  123. latestList := &ctx.LatestList
  124. latestList.Lock.Lock()
  125. defer latestList.Lock.Unlock()
  126. beacon, exists := beacons.Beacons[id]
  127. if !exists {
  128. x, exists := latestList.LatestList[id]
  129. if exists {
  130. x.Last_seen = now
  131. x.Incoming_JSON = incoming
  132. x.Distance = getBeaconDistance(incoming)
  133. latestList.LatestList[id] = x
  134. } else {
  135. latestList.LatestList[id] = model.Beacon{Beacon_id: id, Beacon_type: incoming.Beacon_type, Last_seen: now, Incoming_JSON: incoming, Beacon_location: incoming.Hostname, Distance: getBeaconDistance(incoming)}
  136. }
  137. // Move this to seperate routine?
  138. for k, v := range latestList.LatestList {
  139. if (now - v.Last_seen) > 10 {
  140. delete(latestList.LatestList, k)
  141. }
  142. }
  143. return
  144. }
  145. updateBeacon(&beacon, incoming)
  146. beacons.Beacons[id] = beacon
  147. }
  148. func getBeaconDistance(incoming model.Incoming_json) float64 {
  149. rssi := incoming.RSSI
  150. power := incoming.TX_power
  151. distance := 100.0
  152. ratio := float64(rssi) * (1.0 / float64(twos_comp(power)))
  153. if ratio < 1.0 {
  154. distance = math.Pow(ratio, 10)
  155. } else {
  156. distance = (0.89976)*math.Pow(ratio, 7.7095) + 0.111
  157. }
  158. return distance
  159. }
  160. func updateBeacon(beacon *model.Beacon, incoming model.Incoming_json) {
  161. now := time.Now().Unix()
  162. beacon.Incoming_JSON = incoming
  163. beacon.Last_seen = now
  164. beacon.Beacon_type = incoming.Beacon_type
  165. beacon.HB_ButtonCounter = incoming.HB_ButtonCounter
  166. beacon.HB_Battery = incoming.HB_Battery
  167. beacon.HB_RandomNonce = incoming.HB_RandomNonce
  168. beacon.HB_ButtonMode = incoming.HB_ButtonMode
  169. if beacon.Beacon_metrics == nil {
  170. beacon.Beacon_metrics = make([]model.BeaconMetric, 10) // 10 is a placeholder for now
  171. }
  172. metric := model.BeaconMetric{}
  173. metric.Distance = getBeaconDistance(incoming)
  174. metric.Timestamp = now
  175. metric.Rssi = int64(incoming.RSSI)
  176. metric.Location = incoming.Hostname
  177. beacon.Beacon_metrics = append(beacon.Beacon_metrics, metric)
  178. // Leave the HB button implementation for now
  179. }
  180. func twos_comp(inp string) int64 {
  181. i, _ := strconv.ParseInt("0x"+inp, 0, 64)
  182. return i - 256
  183. }