package main import ( "encoding/json" "fmt" "log" "os" "os/signal" "strconv" "strings" "time" "github.com/AFASystems/presence/internal/pkg/config" "github.com/AFASystems/presence/internal/pkg/httpserver" "github.com/AFASystems/presence/internal/pkg/model" "github.com/AFASystems/presence/internal/pkg/mqttclient" "github.com/AFASystems/presence/internal/pkg/persistence" "github.com/boltdb/bolt" "github.com/gorilla/websocket" "github.com/yosssi/gmq/mqtt" "github.com/yosssi/gmq/mqtt/client" ) func main() { sigc := make(chan os.Signal, 1) signal.Notify(sigc, os.Interrupt) cfg := config.Load() fmt.Println("hello world") db, err := bolt.Open("presence.db", 0644, nil) if err != nil { log.Fatal(err) } defer db.Close() model.Db = db cli := client.New(&client.Options{ ErrorHandler: func(err error) { fmt.Println(err) }, }) defer cli.Terminate() fmt.Println("host: ", cfg.MQTTHost, " Client ID: ", cfg.MQTTClientID, "user: ", cfg.MQTTUser) err = cli.Connect(&client.ConnectOptions{ Network: "tcp", Address: cfg.MQTTHost, ClientID: []byte(cfg.MQTTClientID), UserName: []byte(cfg.MQTTUser), Password: []byte(cfg.MQTTPass), }) if err != nil { fmt.Println("Error comes from here") panic(err) } ctx := &model.AppContext{ HTTPResults: model.HTTPResultsList{ HTTPResults: model.HTTPLocationsList{Beacons: []model.HTTPLocation{}}, }, Beacons: model.BeaconsList{ Beacons: make(map[string]model.Beacon), }, ButtonsList: make(map[string]model.Button), Settings: model.Settings{ Location_confidence: 4, Last_seen_threshold: 15, Beacon_metrics_size: 30, HA_send_interval: 5, HA_send_changes_only: false, }, Clients: make(map[*websocket.Conn]bool), Broadcast: make(chan model.Message, 100), Locations: model.LocationsList{Locations: make(map[string]model.Location)}, LatestList: model.LatestBeaconsList{LatestList: make(map[string]model.Beacon)}, } persistence.LoadState(model.Db, ctx) incomingChan := mqttclient.IncomingMQTTProcessor(1*time.Second, cli, model.Db, ctx) err = cli.Subscribe(&client.SubscribeOptions{ SubReqs: []*client.SubReq{ &client.SubReq{ TopicFilter: []byte("publish_out/#"), QoS: mqtt.QoS0, Handler: func(topicName, message []byte) { msgStr := string(message) t := strings.Split(string(topicName), "/") hostname := t[1] fmt.Println("hostname: ", hostname) if strings.HasPrefix(msgStr, "[") { var readings []model.RawReading err := json.Unmarshal(message, &readings) if err != nil { log.Printf("Error parsing JSON: %v", err) return } for _, reading := range readings { if reading.Type == "Gateway" { continue } incoming := model.Incoming_json{ Hostname: hostname, MAC: reading.MAC, RSSI: int64(reading.RSSI), Data: reading.RawData, HB_ButtonCounter: parseButtonState(reading.RawData), } incomingChan <- incoming } } else { s := strings.Split(string(message), ",") if len(s) < 6 { log.Printf("Messaggio CSV non valido: %s", msgStr) return } rawdata := s[4] buttonCounter := parseButtonState(rawdata) if buttonCounter > 0 { incoming := model.Incoming_json{} i, _ := strconv.ParseInt(s[3], 10, 64) incoming.Hostname = hostname incoming.Beacon_type = "hb_button" incoming.MAC = s[1] incoming.RSSI = i incoming.Data = rawdata incoming.HB_ButtonCounter = buttonCounter read_line := strings.TrimRight(string(s[5]), "\r\n") it, err33 := strconv.Atoi(read_line) if err33 != nil { fmt.Println(it) fmt.Println(err33) os.Exit(2) } incomingChan <- incoming } } }, }, }, }) if err != nil { panic(err) } fmt.Println("CONNECTED TO MQTT") fmt.Println("\n ") fmt.Println("Visit http://" + cfg.HTTPAddr + " on your browser to see the web interface") fmt.Println("\n ") go httpserver.StartHTTPServer(cfg.HTTPAddr, ctx) <-sigc if err := cli.Disconnect(); err != nil { panic(err) } } func parseButtonState(raw string) int64 { raw = strings.ToUpper(raw) if strings.HasPrefix(raw, "0201060303E1FF12") && len(raw) >= 38 { buttonField := raw[34:38] if buttonValue, err := strconv.ParseInt(buttonField, 16, 64); err == nil { return buttonValue } } if strings.HasPrefix(raw, "02010612FF590") && len(raw) >= 24 { counterField := raw[22:24] buttonState, err := strconv.ParseInt(counterField, 16, 64) if err == nil { return buttonState } } return 0 }