Ver código fonte

feat: change used locations algorithm based on API call

master
Blaz Smehov 2 semanas atrás
pai
commit
62df32f715
10 arquivos alterados com 67 adições e 122 exclusões
  1. +8
    -28
      cmd/location/main.go
  2. +3
    -3
      cmd/server/main.go
  3. +1
    -0
      go.mod
  4. +2
    -0
      go.sum
  5. +15
    -19
      internal/pkg/common/appcontext/context.go
  6. +25
    -38
      internal/pkg/controller/settings_controller.go
  7. +1
    -1
      internal/pkg/database/database.go
  8. +12
    -0
      internal/pkg/model/settings.go
  9. +0
    -16
      internal/pkg/model/types.go
  10. +0
    -17
      internal/pkg/service/beacon_service.go

+ 8
- 28
cmd/location/main.go Ver arquivo

@@ -53,7 +53,7 @@ func main() {
defer locTicker.Stop()

chRaw := make(chan model.BeaconAdvertisement, 2000)
chSettings := make(chan model.SettingsVal, 5)
chSettings := make(chan map[string]any, 5)

wg.Add(3)
go kafkaclient.Consume(rawReader, chRaw, ctx, &wg)
@@ -65,7 +65,13 @@ eventLoop:
case <-ctx.Done():
break eventLoop
case <-locTicker.C:
getLikelyLocations(appState, writer)
settings := appState.GetSettings()
switch settings.CurrentAlgorithm {
case "filter":
getLikelyLocations(appState, writer)
case "ai":
fmt.Println("AI algorithm selected")
}
case msg := <-chRaw:
assignBeaconToList(msg, appState)
case msg := <-chSettings:
@@ -132,32 +138,6 @@ func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) {

if beacon.LocationConfidence == settings.LocationConfidence && beacon.PreviousConfidentLocation != bestLocName {
beacon.LocationConfidence = 0
// js, err := json.Marshal(model.LocationChange{
// Method: "LocationChange",
// BeaconRef: beacon,
// Name: beacon.Name,
// PreviousLocation: beacon.PreviousConfidentLocation,
// NewLocation: bestLocName,
// Timestamp: time.Now().Unix(),
// })

// if err != nil {
// eMsg := fmt.Sprintf("Error in marshaling: %v", err)
// slog.Error(eMsg)
// beacon.PreviousConfidentLocation = bestLocName
// beacon.PreviousLocation = bestLocName
// appState.UpdateBeacon(beacon.ID, beacon)
// continue
// }

// msg := kafka.Message{
// Value: js,
// }

// err = writer.WriteMessages(context.Background(), msg)
// if err != nil {
// fmt.Println("Error in sending Kafka message")
// }
}

beacon.PreviousLocation = bestLocName


+ 3
- 3
cmd/server/main.go Ver arquivo

@@ -114,9 +114,6 @@ func main() {

r := mux.NewRouter()

r.HandleFunc("/api/settings", controller.SettingsListController(appState, ctx)).Methods("GET")
r.HandleFunc("/api/settings", controller.SettingsEditController(settingsWriter, appState, ctx)).Methods("POST")

r.HandleFunc("/reslevis/getGateways", controller.GatewayListController(db)).Methods("GET")
r.HandleFunc("/reslevis/postGateway", controller.GatewayAddController(db)).Methods("POST")
r.HandleFunc("/reslevis/removeGateway/{id}", controller.GatewayDeleteController(db)).Methods("DELETE")
@@ -142,6 +139,9 @@ func main() {
r.HandleFunc("/configs/beacons/{id}", controller.ParserUpdateController(db, parserWriter, ctx)).Methods("PUT")
r.HandleFunc("/configs/beacons/{id}", controller.ParserDeleteController(db, parserWriter, ctx)).Methods("DELETE")

r.HandleFunc("/reslevis/settings", controller.SettingsUpdateController(db, settingsWriter, ctx)).Methods("PATCH")
r.HandleFunc("/reslevis/settings", controller.SettingsListController(db)).Methods("GET")

wsHandler := http.HandlerFunc(serveWs(db, ctx))
restApiHandler := handlers.CORS(originsOk, headersOk, methodsOk)(r)
mainHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {


+ 1
- 0
go.mod Ver arquivo

@@ -28,6 +28,7 @@ require (
github.com/jinzhu/now v1.1.5 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // indirect
golang.org/x/crypto v0.42.0 // indirect
golang.org/x/net v0.44.0 // indirect


+ 2
- 0
go.sum Ver arquivo

@@ -39,6 +39,8 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=


+ 15
- 19
internal/pkg/common/appcontext/context.go Ver arquivo

@@ -6,6 +6,7 @@ import (
"time"

"github.com/AFASystems/presence/internal/pkg/model"
"github.com/mitchellh/mapstructure"
"github.com/segmentio/kafka-go"
)

@@ -31,15 +32,14 @@ func NewAppState() *AppState {
Results: make(map[string]model.HTTPResult),
},
settings: model.Settings{
Settings: model.SettingsVal{
LocationConfidence: 4,
LastSeenThreshold: 15,
BeaconMetricSize: 30,
HASendInterval: 5,
HASendChangesOnly: false,
RSSIEnforceThreshold: false,
RSSIMinThreshold: 100,
},
CurrentAlgorithm: "filter", // possible values filter or AI
LocationConfidence: 4,
LastSeenThreshold: 15,
BeaconMetricSize: 30,
HASendInterval: 5,
HASendChangesOnly: false,
RSSIEnforceThreshold: false,
RSSIMinThreshold: 100,
},
beaconEvents: model.BeaconEventList{
Beacons: make(map[string]model.BeaconEvent),
@@ -283,17 +283,13 @@ func (m *AppState) GetBeaconCount() int {
}

// GetSettingsValue returns current settings as a value
func (m *AppState) GetSettingsValue() model.SettingsVal {
m.settings.Lock.RLock()
defer m.settings.Lock.RUnlock()

return m.settings.Settings
func (m *AppState) GetSettingsValue() model.Settings {
return m.settings
}

// UpdateSettings updates the system settings (thread-safe)
func (m *AppState) UpdateSettings(newSettings model.SettingsVal) {
m.settings.Lock.Lock()
defer m.settings.Lock.Unlock()

m.settings.Settings = newSettings
func (m *AppState) UpdateSettings(settings map[string]any) {
if err := mapstructure.Decode(settings, &m.settings); err != nil {
fmt.Printf("Error in persisting settings: %v\n", err)
}
}

+ 25
- 38
internal/pkg/controller/settings_controller.go Ver arquivo

@@ -3,64 +3,51 @@ package controller
import (
"context"
"encoding/json"
"fmt"
"net/http"

"github.com/AFASystems/presence/internal/pkg/common/appcontext"
"github.com/AFASystems/presence/internal/pkg/model"
"github.com/segmentio/kafka-go"
"gorm.io/gorm"
)

func SettingsEditController(writer *kafka.Writer, appstate *appcontext.AppState, ctx context.Context) http.HandlerFunc {
func SettingsListController(db *gorm.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)
var inSettings model.SettingsVal
if err := decoder.Decode(&inSettings); err != nil {
var settings []model.Settings
db.Find(&settings)
res, err := json.Marshal(settings)
if err != nil {
http.Error(w, err.Error(), 400)
fmt.Println("Error in decoding Settings body: ", err)
return
}

if !settingsCheck(inSettings) {
http.Error(w, "values must be greater than 0", 400)
fmt.Println("settings values must be greater than 0")
return
}
w.Write(res)
}
}

valueStr, err := json.Marshal(&inSettings)
if err != nil {
http.Error(w, "Error in encoding settings", 500)
fmt.Println("Error in encoding settings: ", err)
func SettingsUpdateController(db *gorm.DB, writer *kafka.Writer, ctx context.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var updates map[string]any
if err := json.NewDecoder(r.Body).Decode(&updates); err != nil {
http.Error(w, "Invalid JSON", 400)
return
}

msg := kafka.Message{
Value: valueStr,
if err := db.Model(&model.Settings{}).Where("id = ?", 1).Updates(updates).Error; err != nil {
http.Error(w, err.Error(), 500)
return
}

if err := writer.WriteMessages(ctx, msg); err != nil {
fmt.Println("error in sending Kafka message")
http.Error(w, "Error in sending kafka message", 500)
eMsg, err := json.Marshal(updates)
if err != nil {
http.Error(w, "Error in marshaling settings updates", 400)
return
}
msg := kafka.Message{
Value: eMsg,
}

// if all is OK persist settings
appstate.UpdateSettings(inSettings)

w.Write([]byte("ok"))
}
}

func settingsCheck(settings model.SettingsVal) bool {
if settings.LocationConfidence <= 0 || settings.LastSeenThreshold <= 0 || settings.HASendInterval <= 0 {
return false
}

return true
}

func SettingsListController(appstate *appcontext.AppState, ctx context.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
writer.WriteMessages(ctx, msg)

w.Write([]byte("Settings updated"))
}
}

+ 1
- 1
internal/pkg/database/database.go Ver arquivo

@@ -26,7 +26,7 @@ func Connect(cfg *config.Config) (*gorm.DB, error) {
return nil, err
}

if err := db.AutoMigrate(&model.Gateway{}, model.Zone{}, model.TrackerZones{}, model.Tracker{}, model.Config{}); err != nil {
if err := db.AutoMigrate(&model.Gateway{}, model.Zone{}, model.TrackerZones{}, model.Tracker{}, model.Config{}, model.Settings{}); err != nil {
return nil, err
}



+ 12
- 0
internal/pkg/model/settings.go Ver arquivo

@@ -0,0 +1,12 @@
package model

type Settings struct {
CurrentAlgorithm string
LocationConfidence int64
LastSeenThreshold int64
BeaconMetricSize int
HASendInterval int
HASendChangesOnly bool
RSSIEnforceThreshold bool
RSSIMinThreshold int64
}

+ 0
- 16
internal/pkg/model/types.go Ver arquivo

@@ -6,22 +6,6 @@ import (
"github.com/segmentio/kafka-go"
)

// Settings defines configuration parameters for presence detection behavior.
type SettingsVal struct {
LocationConfidence int64 `json:"location_confidence"`
LastSeenThreshold int64 `json:"last_seen_threshold"`
BeaconMetricSize int `json:"beacon_metrics_size"`
HASendInterval int64 `json:"ha_send_interval"`
HASendChangesOnly bool `json:"ha_send_changes_only"`
RSSIMinThreshold int64 `json:"rssi_min_threshold"`
RSSIEnforceThreshold bool `json:"enforce_rssi_threshold"`
}

type Settings struct {
Settings SettingsVal
Lock sync.RWMutex
}

// BeaconAdvertisement represents the JSON payload received from beacon advertisements.
type BeaconAdvertisement struct {
ID string


+ 0
- 17
internal/pkg/service/beacon_service.go Ver arquivo

@@ -60,23 +60,6 @@ func LocationToBeaconService(msg model.HTTPLocation, db *gorm.DB, writer *kafka.
}
}

// func LocationToBeaconService(msg model.HTTPLocation, appState *appcontext.AppState, ctx context.Context) error {
// id := msg.ID
// beacon, ok := appState.GetHTTPResult(id)
// if !ok {
// appState.UpdateHTTPResult(id, model.HTTPResult{ID: id, Position: msg.Location, Distance: msg.Distance, LastSeen: msg.LastSeen, PreviousConfidentLocation: msg.PreviousConfidentLocation})
// } else {
// beacon.ID = id
// beacon.Position = msg.Location
// beacon.Distance = msg.Distance
// beacon.LastSeen = msg.LastSeen
// beacon.PreviousConfidentLocation = msg.PreviousConfidentLocation
// appState.UpdateHTTPResult(id, beacon)
// }

// return nil
// }

func EventToBeaconService(msg model.BeaconEvent, appState *appcontext.AppState, ctx context.Context) error {
id := msg.ID
beacon, ok := appState.GetHTTPResult(id)


Carregando…
Cancelar
Salvar