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.

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