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.
 
 
 
 

183 lines
4.4 KiB

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log"
  6. "os"
  7. "os/signal"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "github.com/AFASystems/presence/internal/pkg/config"
  12. "github.com/AFASystems/presence/internal/pkg/httpserver"
  13. "github.com/AFASystems/presence/internal/pkg/model"
  14. "github.com/AFASystems/presence/internal/pkg/mqtt_client"
  15. "github.com/AFASystems/presence/internal/pkg/persistence"
  16. "github.com/boltdb/bolt"
  17. "github.com/gorilla/websocket"
  18. "github.com/yosssi/gmq/mqtt"
  19. "github.com/yosssi/gmq/mqtt/client"
  20. )
  21. func main() {
  22. sigc := make(chan os.Signal, 1)
  23. signal.Notify(sigc, os.Interrupt)
  24. cfg := config.Load()
  25. db, err := bolt.Open("presence.db", 0644, nil)
  26. if err != nil {
  27. log.Fatal(err)
  28. }
  29. defer db.Close()
  30. model.Db = db
  31. cli := client.New(&client.Options{
  32. ErrorHandler: func(err error) {
  33. fmt.Println(err)
  34. },
  35. })
  36. defer cli.Terminate()
  37. err = cli.Connect(&client.ConnectOptions{
  38. Network: "tcp",
  39. Address: cfg.MQTTHost,
  40. ClientID: []byte(cfg.MQTTClientID),
  41. UserName: []byte(cfg.MQTTUser),
  42. Password: []byte(cfg.MQTTPass),
  43. })
  44. if err != nil {
  45. panic(err)
  46. }
  47. ctx := &model.AppContext{
  48. HTTPResults: model.HTTPResultsList{
  49. HTTPResults: model.HTTPLocationsList{Beacons: []model.HTTPLocation{}},
  50. },
  51. Beacons: model.BeaconsList{
  52. Beacons: make(map[string]model.Beacon),
  53. },
  54. ButtonsList: make(map[string]model.Button),
  55. Settings: model.Settings{
  56. Location_confidence: 4,
  57. Last_seen_threshold: 15,
  58. Beacon_metrics_size: 30,
  59. HA_send_interval: 5,
  60. HA_send_changes_only: false,
  61. },
  62. Clients: make(map[*websocket.Conn]bool),
  63. Broadcast: make(chan model.Message, 100),
  64. Locations: model.LocationsList{Locations: make(map[string]model.Location)},
  65. LatestList: model.LatestBeaconsList{LatestList: make(map[string]model.Beacon)},
  66. }
  67. persistence.LoadState(model.Db, ctx)
  68. incomingChan := mqtt_client.IncomingMQTTProcessor(1*time.Second, cli, model.Db, ctx)
  69. err = cli.Subscribe(&client.SubscribeOptions{
  70. SubReqs: []*client.SubReq{
  71. &client.SubReq{
  72. TopicFilter: []byte("publish_out/#"),
  73. QoS: mqtt.QoS0,
  74. Handler: func(topicName, message []byte) {
  75. msgStr := string(message)
  76. t := strings.Split(string(topicName), "/")
  77. hostname := t[1]
  78. if strings.HasPrefix(msgStr, "[") {
  79. var readings []model.RawReading
  80. err := json.Unmarshal(message, &readings)
  81. if err != nil {
  82. log.Printf("Errore parsing JSON: %v", err)
  83. return
  84. }
  85. for _, reading := range readings {
  86. if reading.Type == "Gateway" {
  87. continue
  88. }
  89. incoming := model.Incoming_json{
  90. Hostname: hostname,
  91. MAC: reading.MAC,
  92. RSSI: int64(reading.RSSI),
  93. Data: reading.RawData,
  94. HB_ButtonCounter: parseButtonState(reading.RawData),
  95. }
  96. incomingChan <- incoming
  97. }
  98. } else {
  99. s := strings.Split(string(message), ",")
  100. if len(s) < 6 {
  101. log.Printf("Messaggio CSV non valido: %s", msgStr)
  102. return
  103. }
  104. rawdata := s[4]
  105. buttonCounter := parseButtonState(rawdata)
  106. if buttonCounter > 0 {
  107. incoming := model.Incoming_json{}
  108. i, _ := strconv.ParseInt(s[3], 10, 64)
  109. incoming.Hostname = hostname
  110. incoming.Beacon_type = "hb_button"
  111. incoming.MAC = s[1]
  112. incoming.RSSI = i
  113. incoming.Data = rawdata
  114. incoming.HB_ButtonCounter = buttonCounter
  115. read_line := strings.TrimRight(string(s[5]), "\r\n")
  116. it, err33 := strconv.Atoi(read_line)
  117. if err33 != nil {
  118. fmt.Println(it)
  119. fmt.Println(err33)
  120. os.Exit(2)
  121. }
  122. incomingChan <- incoming
  123. }
  124. }
  125. },
  126. },
  127. },
  128. })
  129. if err != nil {
  130. panic(err)
  131. }
  132. fmt.Println("CONNECTED TO MQTT")
  133. fmt.Println("\n ")
  134. fmt.Println("Visit http://" + cfg.HTTPAddr + " on your browser to see the web interface")
  135. fmt.Println("\n ")
  136. go httpserver.StartHTTPServer(cfg.HTTPAddr, ctx)
  137. <-sigc
  138. if err := cli.Disconnect(); err != nil {
  139. panic(err)
  140. }
  141. }
  142. func parseButtonState(raw string) int64 {
  143. raw = strings.ToUpper(raw)
  144. if strings.HasPrefix(raw, "0201060303E1FF12") && len(raw) >= 38 {
  145. buttonField := raw[34:38]
  146. if buttonValue, err := strconv.ParseInt(buttonField, 16, 64); err == nil {
  147. return buttonValue
  148. }
  149. }
  150. if strings.HasPrefix(raw, "02010612FF590") && len(raw) >= 24 {
  151. counterField := raw[22:24]
  152. buttonState, err := strconv.ParseInt(counterField, 16, 64)
  153. if err == nil {
  154. return buttonState
  155. }
  156. }
  157. return 0
  158. }