package main import ( "encoding/hex" "fmt" "math" "strconv" "time" "github.com/AFASystems/presence/internal/pkg/config" "github.com/AFASystems/presence/internal/pkg/kafkaclient" "github.com/AFASystems/presence/internal/pkg/model" "github.com/AFASystems/presence/internal/pkg/mqttclient" ) func main() { // Load global context to init beacons and latest list appCtx := model.AppContext{ Beacons: model.BeaconsList{ Beacons: make(map[string]model.Beacon), }, LatestList: model.LatestBeaconsList{ LatestList: make(map[string]model.Beacon), }, Settings: model.Settings{ Settings: model.SettingsVal{ Location_confidence: 4, Last_seen_threshold: 15, Beacon_metrics_size: 30, HA_send_interval: 5, HA_send_changes_only: false, }, }, } fmt.Println("init") cfg := config.Load() // Kafka reader for Raw MQTT beacons rawReader := kafkaclient.KafkaReader(cfg.KafkaURL, "rawbeacons", "gid-raw") defer rawReader.Close() // Kafka reader for API server updates // apiReader := kafkaclient.KafkaReader(cfg.KafkaURL, "apibeacons", "gid-api") // defer apiReader.Close() // // Kafka reader for latest list updates // latestReader := kafkaclient.KafkaReader(cfg.KafkaURL, "latestbeacons", "gid-latest") // defer latestReader.Close() // // Kafka reader for settings updates // settingsReader := kafkaclient.KafkaReader(cfg.KafkaURL, "settings", "gid-settings") // defer settingsReader.Close() // declare channel for collecting Kafka messages chRaw := make(chan model.Incoming_json, 2000) // chApi := make(chan model.ApiUpdate, 2000) // chLatest := make(chan model.Incoming_json, 2000) // chSettings := make(chan model.SettingsVal, 10) go kafkaclient.Consume(rawReader, chRaw) // go kafkaclient.Consume(apiReader, chApi) // go kafkaclient.Consume(latestReader, chLatest) // go kafkaclient.Consume(settingsReader, chSettings) for { select { case msg := <-chRaw: processIncoming(msg, &appCtx) // case msg := <-chApi: // switch msg.Method { // case "POST": // fmt.Println("Incoming POST") // appCtx.Beacons.Lock.Lock() // appCtx.Beacons.Beacons[msg.Beacon.Beacon_id] = msg.Beacon // case "DELETE": // fmt.Println("Incoming delete") // _, exists := appCtx.Beacons.Beacons[msg.ID] // if exists { // appCtx.Beacons.Lock.Lock() // delete(appCtx.Beacons.Beacons, msg.ID) // } // default: // fmt.Println("unknown method: ", msg.Method) // } // appCtx.Beacons.Lock.Unlock() // case msg := <-chLatest: // fmt.Println("latest msg: ", msg) // case msg := <-chSettings: // appCtx.Settings.Lock.Lock() // appCtx.Settings.Settings = msg // fmt.Println("settings channel: ", msg) // appCtx.Settings.Lock.Unlock() } } } func processIncoming(incoming model.Incoming_json, ctx *model.AppContext) { defer func() { if err := recover(); err != nil { fmt.Println("work failed:", err) } }() // Get ID id := mqttclient.GetBeaconID(incoming) fmt.Println(incoming.Data) beacons := &ctx.Beacons beacons.Lock.Lock() defer beacons.Lock.Unlock() incoming = mqttclient.IncomingBeaconFilter(incoming) beacon, exists := beacons.Beacons[id] if !exists { return } fmt.Printf("%+v\n", beacon) updateBeacon(&beacon, incoming) beacons.Beacons[id] = beacon } func processBeacon(hexStr string) { b, _ := hex.DecodeString(hexStr) if len(b) > 2 && b[0] == 0x02 && b[1] == 0x01 { b = b[2+int(b[0]):] } ads := ParseADFast(b) _ = ads } func ParseADFast(b []byte) [][2]int { var res [][2]int i := 0 for i < len(b) { l := int(b[i]) if l == 0 || i+1+l > len(b) { break } res = append(res, [2]int{i, i + 1 + l}) i += 1 + l } return res } func getBeaconDistance(incoming model.Incoming_json) float64 { rssi := incoming.RSSI power := incoming.TX_power distance := 100.0 ratio := float64(rssi) * (1.0 / float64(twos_comp(power))) if ratio < 1.0 { distance = math.Pow(ratio, 10) } else { distance = (0.89976)*math.Pow(ratio, 7.7095) + 0.111 } return distance } func updateBeacon(beacon *model.Beacon, incoming model.Incoming_json) { now := time.Now().Unix() beacon.Incoming_JSON = incoming beacon.Last_seen = now beacon.Beacon_type = incoming.Beacon_type beacon.HB_ButtonCounter = incoming.HB_ButtonCounter beacon.HB_Battery = incoming.HB_Battery beacon.HB_RandomNonce = incoming.HB_RandomNonce beacon.HB_ButtonMode = incoming.HB_ButtonMode if beacon.Beacon_metrics == nil { beacon.Beacon_metrics = make([]model.BeaconMetric, 10) } metric := model.BeaconMetric{} metric.Distance = getBeaconDistance(incoming) metric.Timestamp = now metric.Rssi = int64(incoming.RSSI) metric.Location = incoming.Hostname beacon.Beacon_metrics = append(beacon.Beacon_metrics, metric) } func twos_comp(inp string) int64 { i, _ := strconv.ParseInt("0x"+inp, 0, 64) return i - 256 }