|
- package mqttclient
-
- import (
- "encoding/json"
- "log"
- "time"
-
- "github.com/AFASystems/presence/internal/pkg/model"
- "github.com/AFASystems/presence/internal/pkg/persistence"
- "github.com/yosssi/gmq/mqtt"
- "github.com/yosssi/gmq/mqtt/client"
- )
-
- func getLikelyLocations(settings *model.SettingsVal, ctx *model.AppContext, cl *client.Client) {
- ctx.HTTPResults.HTTPResultsLock.Lock()
- defer ctx.HTTPResults.HTTPResultsLock.Unlock()
- ctx.HTTPResults.HTTPResults = model.HTTPLocationsList{Beacons: []model.HTTPLocation{}}
-
- shouldPersist := false
-
- for id, beacon := range ctx.Beacons.Beacons {
- if len(beacon.Beacon_metrics) == 0 {
- continue
- }
-
- if isExpired(&beacon, settings) {
- handleExpiredBeacon(&beacon, cl, ctx)
- continue
- }
-
- best := calculateBestLocation(&beacon)
- updateBeaconState(&beacon, best, settings, ctx, cl)
-
- appendHTTPResult(ctx, beacon, best)
- ctx.Beacons.Beacons[id] = beacon
- shouldPersist = true
- }
-
- if shouldPersist {
- persistence.PersistBeacons(&ctx.Beacons)
- }
- }
-
- func isExpired(b *model.Beacon, s *model.SettingsVal) bool {
- return time.Now().Unix()-b.Beacon_metrics[len(b.Beacon_metrics)-1].Timestamp > s.Last_seen_threshold
- }
-
- func handleExpiredBeacon(b *model.Beacon, cl *client.Client, ctx *model.AppContext) {
- if b.Expired_location == "expired" {
- return
- }
- b.Expired_location = "expired"
- msg := model.Message{
- Email: b.Previous_confident_location,
- Username: b.Name,
- Message: "expired",
- }
- data, _ := json.Marshal(msg)
- log.Println(string(data))
- ctx.Broadcast <- msg
- }
-
- func calculateBestLocation(b *model.Beacon) model.BestLocation {
- locScores := map[string]float64{}
- for _, m := range b.Beacon_metrics {
- score := 1.5 + 0.75*(1.0-(float64(m.Rssi)/-100.0))
- locScores[m.Location] += score
- }
- bestName, bestScore := "", 0.0
- for name, score := range locScores {
- if score > bestScore {
- bestName, bestScore = name, score
- }
- }
- last := b.Beacon_metrics[len(b.Beacon_metrics)-1]
- return model.BestLocation{Name: bestName, Distance: last.Distance, Last_seen: last.Timestamp}
- }
-
- func updateBeaconState(b *model.Beacon, best model.BestLocation, s *model.SettingsVal, ctx *model.AppContext, cl *client.Client) {
- updateLocationHistory(b, best.Name)
- updateConfidence(b, best.Name, s)
-
- if locationChanged(b, best, s) {
- publishLocationChange(b, best, cl)
- b.Location_confidence = 0
- b.Previous_confident_location = best.Name
- }
- }
-
- func updateLocationHistory(b *model.Beacon, loc string) {
- b.Location_history = append(b.Location_history, loc)
- if len(b.Location_history) > 10 {
- b.Location_history = b.Location_history[1:]
- }
- }
-
- func updateConfidence(b *model.Beacon, loc string, s *model.SettingsVal) {
- counts := map[string]int{}
- for _, l := range b.Location_history {
- counts[l]++
- }
-
- maxCount, mostCommon := 0, ""
- for l, c := range counts {
- if c > maxCount {
- maxCount, mostCommon = c, l
- }
- }
-
- if maxCount >= 7 {
- if mostCommon == b.Previous_confident_location {
- b.Location_confidence++
- } else {
- b.Location_confidence = 1
- b.Previous_confident_location = mostCommon
- }
- }
- }
-
- func locationChanged(b *model.Beacon, best model.BestLocation, s *model.SettingsVal) bool {
- return (b.Location_confidence == s.Location_confidence &&
- b.Previous_confident_location != best.Name) ||
- b.Expired_location == "expired"
- }
-
- func publishLocationChange(b *model.Beacon, best model.BestLocation, cl *client.Client) {
- location := best.Name
- if b.Expired_location == "expired" {
- location = "expired"
- }
-
- js, err := json.Marshal(model.LocationChange{
- Beacon_ref: *b,
- Name: b.Name,
- Previous_location: b.Previous_confident_location,
- New_location: location,
- Timestamp: time.Now().Unix(),
- })
- if err != nil {
- return
- }
-
- err = cl.Publish(&client.PublishOptions{
- QoS: mqtt.QoS1,
- TopicName: []byte("afa-systems/presence/changes"),
- Message: js,
- })
- if err != nil {
- log.Printf("mqtt publish error: %v", err)
- }
- }
-
- func appendHTTPResult(ctx *model.AppContext, b model.Beacon, best model.BestLocation) {
- ctx.HTTPResults.HTTPResultsLock.Lock()
- defer ctx.HTTPResults.HTTPResultsLock.Unlock()
-
- r := model.HTTPLocation{
- Name: b.Name,
- Beacon_id: b.Beacon_id,
- Location: best.Name,
- Distance: best.Distance,
- Last_seen: best.Last_seen,
- }
- ctx.HTTPResults.HTTPResults.Beacons = append(ctx.HTTPResults.HTTPResults.Beacons, r)
- }
|