diff --git a/bridge b/bridge index f04f2dd..7f49ad8 100755 Binary files a/bridge and b/bridge differ diff --git a/decoder b/decoder index c8b10c3..e6f87f0 100755 Binary files a/decoder and b/decoder differ diff --git a/internal/app/decoder/app.go b/internal/app/decoder/app.go index 080899e..337cf53 100644 --- a/internal/app/decoder/app.go +++ b/internal/app/decoder/app.go @@ -19,7 +19,7 @@ type DecoderApp struct { KafkaManager *kafkaclient.KafkaManager AppState *appcontext.AppState ParserRegistry *model.ParserRegistry - ChRaw chan model.BeaconAdvertisement + ChRaw chan appcontext.BeaconAdvertisement ChParser chan model.KafkaParser Cleanup func() wg sync.WaitGroup @@ -48,7 +48,7 @@ func New(cfg *config.Config) (*DecoderApp, error) { KafkaManager: kafkaManager, AppState: appState, ParserRegistry: registry, - ChRaw: make(chan model.BeaconAdvertisement, config.LARGE_CHANNEL_SIZE), + ChRaw: make(chan appcontext.BeaconAdvertisement, config.LARGE_CHANNEL_SIZE), ChParser: make(chan model.KafkaParser, config.SMALL_CHANNEL_SIZE), Cleanup: cleanup, }, nil diff --git a/internal/app/location/app.go b/internal/app/location/app.go index 14f9692..c0c0ddc 100644 --- a/internal/app/location/app.go +++ b/internal/app/location/app.go @@ -22,7 +22,7 @@ type LocationApp struct { KafkaManager *kafkaclient.KafkaManager AppState *appcontext.AppState Inferencer pkglocation.Inferencer - ChRaw chan model.BeaconAdvertisement + ChRaw chan appcontext.BeaconAdvertisement ChSettings chan map[string]any Cleanup func() wg sync.WaitGroup @@ -47,7 +47,7 @@ func New(cfg *config.Config) (*LocationApp, error) { KafkaManager: kafkaManager, AppState: appState, Inferencer: pkglocation.NewDefaultInferencer(cfg.TLSInsecureSkipVerify), - ChRaw: make(chan model.BeaconAdvertisement, config.LARGE_CHANNEL_SIZE), + ChRaw: make(chan appcontext.BeaconAdvertisement, config.LARGE_CHANNEL_SIZE), ChSettings: make(chan map[string]any, config.SMALL_CHANNEL_SIZE), Cleanup: cleanup, }, nil diff --git a/internal/app/server/app.go b/internal/app/server/app.go index 433fe5b..4e438a5 100644 --- a/internal/app/server/app.go +++ b/internal/app/server/app.go @@ -28,7 +28,7 @@ type ServerApp struct { KafkaManager *kafkaclient.KafkaManager AppState *appcontext.AppState ChLoc chan model.HTTPLocation - ChEvents chan model.BeaconEvent + ChEvents chan appcontext.BeaconEvent ctx context.Context Server *http.Server Cleanup func() @@ -98,12 +98,12 @@ func (a *ServerApp) Init(ctx context.Context) error { slog.Error("UpdateDB", "err", err) } - readerTopics := []string{"locevents", "alertbeacons"} + readerTopics := []string{"locevents", "alertbeacons", "health"} a.KafkaManager.PopulateKafkaManager(a.Cfg.KafkaURL, "server", readerTopics) slog.Info("Kafka readers initialized", "topics", readerTopics) a.ChLoc = make(chan model.HTTPLocation, config.SMALL_CHANNEL_SIZE) - a.ChEvents = make(chan model.BeaconEvent, config.MEDIUM_CHANNEL_SIZE) + a.ChEvents = make(chan appcontext.BeaconEvent, config.MEDIUM_CHANNEL_SIZE) a.wg.Add(2) go kafkaclient.Consume(a.KafkaManager.GetReader("locevents"), a.ChLoc, ctx, &a.wg) diff --git a/internal/pkg/apiclient/updatedb.go b/internal/pkg/apiclient/updatedb.go index ce4bae4..d1d38f0 100644 --- a/internal/pkg/apiclient/updatedb.go +++ b/internal/pkg/apiclient/updatedb.go @@ -70,7 +70,7 @@ func UpdateDB(db *gorm.DB, ctx context.Context, cfg *config.Config, writer *kafk } } - var settings model.Settings + var settings appcontext.Settings db.First(&settings) if settings.ID == 0 { msg := "settings are empty" diff --git a/internal/pkg/bridge/handler.go b/internal/pkg/bridge/handler.go index 88d167a..dcc5865 100644 --- a/internal/pkg/bridge/handler.go +++ b/internal/pkg/bridge/handler.go @@ -7,6 +7,7 @@ import ( "strings" "time" + "github.com/AFASystems/presence/internal/pkg/common/appcontext" "github.com/AFASystems/presence/internal/pkg/kafkaclient" "github.com/AFASystems/presence/internal/pkg/model" "github.com/segmentio/kafka-go" @@ -42,7 +43,7 @@ func HandleMQTTMessage(topic string, payload []byte, lookup BeaconLookup, writer if !ok { continue } - adv := model.BeaconAdvertisement{ + adv := appcontext.BeaconAdvertisement{ ID: id, Hostname: hostname, MAC: reading.MAC, diff --git a/internal/pkg/common/appcontext/context.go b/internal/pkg/common/appcontext/context.go index 9c4d98b..47a2e8f 100644 --- a/internal/pkg/common/appcontext/context.go +++ b/internal/pkg/common/appcontext/context.go @@ -5,16 +5,15 @@ import ( "log/slog" "os" - "github.com/AFASystems/presence/internal/pkg/model" "github.com/mitchellh/mapstructure" ) // AppState provides centralized access to application state type AppState struct { - beacons model.BeaconsList - settings model.Settings - beaconEvents model.BeaconEventList - beaconsLookup model.BeaconsLookup + beacons BeaconsList + settings Settings + beaconEvents BeaconEventList + beaconsLookup BeaconsLookup } func getEnv(key, def string) string { @@ -27,10 +26,10 @@ func getEnv(key, def string) string { // NewAppState creates a new application context AppState with default values func NewAppState() *AppState { return &AppState{ - beacons: model.BeaconsList{ - Beacons: make(map[string]model.Beacon), + beacons: BeaconsList{ + Beacons: make(map[string]Beacon), }, - settings: model.Settings{ + settings: Settings{ ID: 1, CurrentAlgorithm: getEnv("ALGORITHM", "filter"), LocationConfidence: 4, @@ -41,29 +40,29 @@ func NewAppState() *AppState { RSSIEnforceThreshold: false, RSSIMinThreshold: 100, }, - beaconEvents: model.BeaconEventList{ - Beacons: make(map[string]model.BeaconEvent), + beaconEvents: BeaconEventList{ + Beacons: make(map[string]BeaconEvent), }, - beaconsLookup: model.BeaconsLookup{ + beaconsLookup: BeaconsLookup{ Lookup: make(map[string]string), }, } } // GetBeacons returns thread-safe access to beacons list -func (m *AppState) GetBeacons() *model.BeaconsList { +func (m *AppState) GetBeacons() *BeaconsList { m.beacons.Lock.RLock() defer m.beacons.Lock.RUnlock() return &m.beacons } // GetSettings returns thread-safe access to settings -func (m *AppState) GetSettings() *model.Settings { +func (m *AppState) GetSettings() *Settings { return &m.settings } // GetBeaconEvents returns thread-safe access to beacon events -func (m *AppState) GetBeaconEvents() *model.BeaconEventList { +func (m *AppState) GetBeaconEvents() *BeaconEventList { m.beaconEvents.Lock.RLock() defer m.beaconEvents.Lock.RUnlock() return &m.beaconEvents @@ -98,7 +97,7 @@ func (m *AppState) BeaconExists(id string) (string, bool) { } // GetBeacon returns a beacon by ID (thread-safe) -func (m *AppState) GetBeacon(id string) (model.Beacon, bool) { +func (m *AppState) GetBeacon(id string) (Beacon, bool) { m.beacons.Lock.RLock() defer m.beacons.Lock.RUnlock() @@ -107,7 +106,7 @@ func (m *AppState) GetBeacon(id string) (model.Beacon, bool) { } // UpdateBeacon updates a beacon in the list (thread-safe) -func (m *AppState) UpdateBeacon(id string, beacon model.Beacon) { +func (m *AppState) UpdateBeacon(id string, beacon Beacon) { m.beacons.Lock.Lock() defer m.beacons.Lock.Unlock() @@ -115,7 +114,7 @@ func (m *AppState) UpdateBeacon(id string, beacon model.Beacon) { } // GetBeaconEvent returns a beacon event by ID (thread-safe) -func (m *AppState) GetBeaconEvent(id string) (model.BeaconEvent, bool) { +func (m *AppState) GetBeaconEvent(id string) (BeaconEvent, bool) { m.beaconEvents.Lock.RLock() defer m.beaconEvents.Lock.RUnlock() @@ -124,7 +123,7 @@ func (m *AppState) GetBeaconEvent(id string) (model.BeaconEvent, bool) { } // UpdateBeaconEvent updates a beacon event in the list (thread-safe) -func (m *AppState) UpdateBeaconEvent(id string, event model.BeaconEvent) { +func (m *AppState) UpdateBeaconEvent(id string, event BeaconEvent) { m.beaconEvents.Lock.Lock() defer m.beaconEvents.Lock.Unlock() @@ -132,11 +131,11 @@ func (m *AppState) UpdateBeaconEvent(id string, event model.BeaconEvent) { } // GetAllBeacons returns a copy of all beacons -func (m *AppState) GetAllBeacons() map[string]model.Beacon { +func (m *AppState) GetAllBeacons() map[string]Beacon { m.beacons.Lock.RLock() defer m.beacons.Lock.RUnlock() - beacons := make(map[string]model.Beacon) + beacons := make(map[string]Beacon) for id, beacon := range m.beacons.Beacons { beacons[id] = beacon } @@ -152,7 +151,7 @@ func (m *AppState) GetBeaconCount() int { } // GetSettingsValue returns current settings as a value -func (m *AppState) GetSettingsValue() model.Settings { +func (m *AppState) GetSettingsValue() Settings { return m.settings } diff --git a/internal/pkg/model/type_methods.go b/internal/pkg/common/appcontext/type_methods.go similarity index 95% rename from internal/pkg/model/type_methods.go rename to internal/pkg/common/appcontext/type_methods.go index e4589bb..7a5e4e2 100644 --- a/internal/pkg/model/type_methods.go +++ b/internal/pkg/common/appcontext/type_methods.go @@ -1,4 +1,4 @@ -package model +package appcontext import ( "crypto/sha256" diff --git a/internal/pkg/common/appcontext/types.go b/internal/pkg/common/appcontext/types.go new file mode 100644 index 0000000..27ef26a --- /dev/null +++ b/internal/pkg/common/appcontext/types.go @@ -0,0 +1,100 @@ +package appcontext + +import "sync" + +// BeaconAdvertisement represents the JSON payload received from beacon advertisements. +type BeaconAdvertisement struct { + ID string + Hostname string `json:"hostname"` + MAC string `json:"mac"` + RSSI int64 `json:"rssi"` + ScanResponse string `json:"is_scan_response"` + Type string `json:"type"` + Data string `json:"data"` + BeaconType string `json:"beacon_type"` + UUID string `json:"uuid"` + Major string `json:"major"` + Minor string `json:"minor"` + TXPower string `json:"tx_power"` + NamespaceID string `json:"namespace"` + InstanceID string `json:"instance_id"` + HSButtonCounter int64 `json:"hb_button_counter"` + HSButtonPrev int64 `json:"hb_button_counter_prev"` + HSBatteryLevel int64 `json:"hb_button_battery"` + HSRandomNonce string `json:"hb_button_random"` + HSButtonMode string `json:"hb_button_mode"` +} + +// BeaconMetric stores signal and distance data for a beacon. +type BeaconMetric struct { + Location string + Distance float64 + RSSI int64 + Timestamp int64 +} + +// Beacon holds all relevant information about a tracked beacon device. +type Beacon struct { + Name string `json:"name"` + ID string `json:"beacon_id"` + BeaconType string `json:"beacon_type"` + BeaconLocation string `json:"beacon_location"` + LastSeen int64 `json:"last_seen"` + IncomingJSON BeaconAdvertisement `json:"incoming_json"` + Distance float64 `json:"distance"` + PreviousLocation string + PreviousConfidentLocation string + ExpiredLocation string + LocationConfidence int64 + LocationHistory []string + BeaconMetrics []BeaconMetric + Location string `json:"location"` + HSButtonCounter int64 `json:"hs_button_counter"` + HSButtonPrev int64 `json:"hs_button_counter_prev"` + HSBattery int64 `json:"hs_button_battery"` + HSRandomNonce string `json:"hs_button_random"` + HSButtonMode string `json:"hs_button_mode"` + Event int `json:"beacon_event"` +} + +type Settings struct { + ID int `gorm:"primaryKey"` // this is always 1 + CurrentAlgorithm string `json:"current_algorithm" mapstructure:"current_algorithm"` + LocationConfidence int64 `json:"location_confidence" mapstructure:"location_confidence"` + LastSeenThreshold int64 `json:"last_seen_threshold" mapstructure:"last_seen_threshold"` + BeaconMetricSize int `json:"beacon_metric_size" mapstructure:"beacon_metric_size"` + HASendInterval int `json:"HA_send_interval" mapstructure:"HA_send_interval"` + HASendChangesOnly bool `json:"HA_send_changes_only" mapstructure:"HA_send_changes_only"` + RSSIEnforceThreshold bool `json:"RSSI_enforce_threshold" mapstructure:"RSSI_enforce_threshold"` + RSSIMinThreshold int64 `json:"RSSI_min_threshold" mapstructure:"RSSI_min_threshold"` +} + +type BeaconEvent struct { + Name string + ID string + Type string + Battery uint32 + Event int + AccX int16 + AccY int16 + AccZ int16 + Temperature uint16 + Heart int16 + BtnPressed bool +} + +// BeaconsList holds all known beacons and their synchronization lock. +type BeaconsList struct { + Beacons map[string]Beacon `json:"beacons"` + Lock sync.RWMutex +} + +type BeaconEventList struct { + Beacons map[string]BeaconEvent + Lock sync.RWMutex +} + +type BeaconsLookup struct { + Lookup map[string]string + Lock sync.RWMutex +} diff --git a/internal/pkg/common/utils/beacons.go b/internal/pkg/common/utils/beacons.go index ce021e4..df75e6c 100644 --- a/internal/pkg/common/utils/beacons.go +++ b/internal/pkg/common/utils/beacons.go @@ -1,6 +1,7 @@ package utils import ( + "github.com/AFASystems/presence/internal/pkg/common/appcontext" "github.com/AFASystems/presence/internal/pkg/model" ) @@ -37,8 +38,8 @@ func RemoveFlagBytes(b []byte) []byte { } // Generate event based on the Beacon type -func LoopADStructures(b []byte, i [][2]int, id string, parserRegistry *model.ParserRegistry) model.BeaconEvent { - be := model.BeaconEvent{} +func LoopADStructures(b []byte, i [][2]int, id string, parserRegistry *model.ParserRegistry) appcontext.BeaconEvent { + be := appcontext.BeaconEvent{} for _, r := range i { ad := b[r[0]:r[1]] if !isValidADStructure(ad) { diff --git a/internal/pkg/common/utils/distance.go b/internal/pkg/common/utils/distance.go index a1a7eb4..4c026bb 100644 --- a/internal/pkg/common/utils/distance.go +++ b/internal/pkg/common/utils/distance.go @@ -4,10 +4,10 @@ import ( "math" "strconv" - "github.com/AFASystems/presence/internal/pkg/model" + "github.com/AFASystems/presence/internal/pkg/common/appcontext" ) -func CalculateDistance(adv model.BeaconAdvertisement) float64 { +func CalculateDistance(adv appcontext.BeaconAdvertisement) float64 { rssi := adv.RSSI power := adv.TXPower ratio := float64(rssi) * (1.0 / float64(twosComp(power))) diff --git a/internal/pkg/controller/settings_controller.go b/internal/pkg/controller/settings_controller.go index 148e839..968af3f 100644 --- a/internal/pkg/controller/settings_controller.go +++ b/internal/pkg/controller/settings_controller.go @@ -7,15 +7,15 @@ import ( "net/http" "github.com/AFASystems/presence/internal/pkg/api/response" + "github.com/AFASystems/presence/internal/pkg/common/appcontext" "github.com/AFASystems/presence/internal/pkg/kafkaclient" - "github.com/AFASystems/presence/internal/pkg/model" "github.com/segmentio/kafka-go" "gorm.io/gorm" ) func SettingsListController(db *gorm.DB, context context.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var settings []model.Settings + var settings []appcontext.Settings if err := db.WithContext(context).Find(&settings).Error; err != nil { response.InternalError(w, "failed to list settings", err) return @@ -34,7 +34,7 @@ func SettingsUpdateController(db *gorm.DB, writer *kafka.Writer, context context slog.Info("updating settings", "updates", updates) - if err := db.WithContext(context).Model(&model.Settings{}).Where("id = ?", 1).Updates(updates).Error; err != nil { + if err := db.WithContext(context).Model(&appcontext.Settings{}).Where("id = ?", 1).Updates(updates).Error; err != nil { response.InternalError(w, "failed to update settings", err) return } diff --git a/internal/pkg/database/database.go b/internal/pkg/database/database.go index bab8b76..70aee1e 100644 --- a/internal/pkg/database/database.go +++ b/internal/pkg/database/database.go @@ -4,6 +4,7 @@ import ( "fmt" "log/slog" + "github.com/AFASystems/presence/internal/pkg/common/appcontext" "github.com/AFASystems/presence/internal/pkg/config" "github.com/AFASystems/presence/internal/pkg/model" "gorm.io/driver/postgres" @@ -25,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{}, model.Settings{}, model.Tracks{}, &model.Alert{}); err != nil { + if err := db.AutoMigrate(&model.Gateway{}, model.Zone{}, model.TrackerZones{}, model.Tracker{}, model.Config{}, appcontext.Settings{}, model.Tracks{}, &model.Alert{}); err != nil { return nil, err } diff --git a/internal/pkg/decoder/process.go b/internal/pkg/decoder/process.go index cd19bee..f1e2e87 100644 --- a/internal/pkg/decoder/process.go +++ b/internal/pkg/decoder/process.go @@ -16,14 +16,14 @@ import ( ) // ProcessIncoming decodes a beacon advertisement and writes the event to the writer if it changed. -func ProcessIncoming(adv model.BeaconAdvertisement, appState *appcontext.AppState, writer *kafka.Writer, registry *model.ParserRegistry) { +func ProcessIncoming(adv appcontext.BeaconAdvertisement, appState *appcontext.AppState, writer *kafka.Writer, registry *model.ParserRegistry) { if err := DecodeBeacon(adv, appState, writer, registry); err != nil { slog.Error("decoding beacon", "err", err, "id", adv.ID) } } // DecodeBeacon hex-decodes the payload, runs the parser registry, dedupes by event hash, and writes to writer. -func DecodeBeacon(adv model.BeaconAdvertisement, appState *appcontext.AppState, writer *kafka.Writer, registry *model.ParserRegistry) error { +func DecodeBeacon(adv appcontext.BeaconAdvertisement, appState *appcontext.AppState, writer *kafka.Writer, registry *model.ParserRegistry) error { beacon := strings.TrimSpace(adv.Data) id := adv.ID if beacon == "" { diff --git a/internal/pkg/kafkaclient/manager.go b/internal/pkg/kafkaclient/manager.go index d68399f..49c1d34 100644 --- a/internal/pkg/kafkaclient/manager.go +++ b/internal/pkg/kafkaclient/manager.go @@ -121,3 +121,23 @@ func (m *KafkaManager) GetWriter(topic string) *kafka.Writer { defer m.kafkaWritersMap.KafkaWritersLock.RUnlock() return m.kafkaWritersMap.KafkaWriters[topic] } + +func (m *KafkaManager) GetReaders() []string { + m.kafkaReadersMap.KafkaReadersLock.RLock() + var readers []string + for key := range m.kafkaReadersMap.KafkaReaders { + readers = append(readers, key) + } + m.kafkaReadersMap.KafkaReadersLock.RUnlock() + return readers +} + +func (m *KafkaManager) GetWriters() []string { + m.kafkaWritersMap.KafkaWritersLock.RLock() + var writers []string + for key := range m.kafkaWritersMap.KafkaWriters { + writers = append(writers, key) + } + m.kafkaWritersMap.KafkaWritersLock.RUnlock() + return writers +} diff --git a/internal/pkg/location/assign.go b/internal/pkg/location/assign.go index c9bf9b1..4df4413 100644 --- a/internal/pkg/location/assign.go +++ b/internal/pkg/location/assign.go @@ -6,12 +6,11 @@ import ( "github.com/AFASystems/presence/internal/pkg/common/appcontext" "github.com/AFASystems/presence/internal/pkg/common/utils" - "github.com/AFASystems/presence/internal/pkg/model" ) // AssignBeaconToList updates app state with a new beacon advertisement: appends a metric // to the beacon's sliding window and updates last seen. -func AssignBeaconToList(adv model.BeaconAdvertisement, appState *appcontext.AppState) { +func AssignBeaconToList(adv appcontext.BeaconAdvertisement, appState *appcontext.AppState) { id := adv.ID now := time.Now().Unix() settings := appState.GetSettingsValue() @@ -23,17 +22,17 @@ func AssignBeaconToList(adv model.BeaconAdvertisement, appState *appcontext.AppS beacon, ok := appState.GetBeacon(id) if !ok { - beacon = model.Beacon{ID: id} + beacon = appcontext.Beacon{ID: id} } beacon.IncomingJSON = adv beacon.LastSeen = now if beacon.BeaconMetrics == nil { - beacon.BeaconMetrics = make([]model.BeaconMetric, 0, settings.BeaconMetricSize) + beacon.BeaconMetrics = make([]appcontext.BeaconMetric, 0, settings.BeaconMetricSize) } - metric := model.BeaconMetric{ + metric := appcontext.BeaconMetric{ Distance: utils.CalculateDistance(adv), Timestamp: now, RSSI: int64(adv.RSSI), diff --git a/internal/pkg/model/health.go b/internal/pkg/model/health.go new file mode 100644 index 0000000..3cf4500 --- /dev/null +++ b/internal/pkg/model/health.go @@ -0,0 +1,71 @@ +package model + +import ( + "encoding/json" + "sync" + "time" + + "github.com/AFASystems/presence/internal/pkg/common/appcontext" + "github.com/AFASystems/presence/internal/pkg/kafkaclient" +) + +type BaseHealth struct { + Lock sync.RWMutex + Uptime time.Duration `json:"uptime"` + ActiveReaders []string `json:"activeReaders"` + ActiveWriters []string `json:"activeWriters"` + ActiveBeacons []string `json:"activeBeacons"` +} + +type DecoderHealth struct { + BaseHealth + // current active configs ? dont know yet how +} + +type LocationHealth struct { + BaseHealth + ActiveSettings []appcontext.Settings `json:"activeSettings"` +} + +type BridgeHealth struct { + BaseHealth +} + +func (b *BaseHealth) GetUptime(startTime time.Time) { + b.Lock.Lock() + b.Uptime = time.Since(startTime) + b.Lock.Unlock() +} + +func (b *BaseHealth) GetActiveReaders(m *kafkaclient.KafkaManager) { + b.Lock.Lock() + b.ActiveReaders = m.GetReaders() + b.Lock.Unlock() +} + +func (b *BaseHealth) GetActiveWriters(m *kafkaclient.KafkaManager) { + b.Lock.Lock() + b.ActiveWriters = m.GetWriters() + b.Lock.Unlock() +} + +func (b *BaseHealth) GetActiveBeacons(m *appcontext.AppState) { + b.Lock.Lock() + beacons := m.GetAllBeacons() + for beacon := range beacons { + b.ActiveBeacons = append(b.ActiveBeacons, beacon) + } + b.Lock.Unlock() +} + +func (d *DecoderHealth) Marshal() ([]byte, error) { + return json.Marshal(d) +} + +func (l *LocationHealth) Marshal() ([]byte, error) { + return json.Marshal(l) +} + +func (b *BridgeHealth) Marshal() ([]byte, error) { + return json.Marshal(b) +} diff --git a/internal/pkg/model/parser.go b/internal/pkg/model/parser.go index 83b5ae8..0d49a9b 100644 --- a/internal/pkg/model/parser.go +++ b/internal/pkg/model/parser.go @@ -6,6 +6,8 @@ import ( "fmt" "log/slog" "sync" + + "github.com/AFASystems/presence/internal/pkg/common/appcontext" ) type ParserConfig struct { @@ -77,9 +79,9 @@ func (p *ParserRegistry) Unregister(name string) { // TODO: change this to be dynamic, maybe event is interface with no predefined properties // or types -func (b *BeaconParser) Parse(name string, ad []byte) (BeaconEvent, bool) { +func (b *BeaconParser) Parse(name string, ad []byte) (appcontext.BeaconEvent, bool) { flag := false - event := BeaconEvent{Type: name} + event := appcontext.BeaconEvent{Type: name} if cfg, ok := b.configs["battery"]; ok { event.Battery = uint32(b.extract(ad, cfg).(uint16)) flag = true diff --git a/internal/pkg/model/settings.go b/internal/pkg/model/settings.go deleted file mode 100644 index 161ff4b..0000000 --- a/internal/pkg/model/settings.go +++ /dev/null @@ -1,13 +0,0 @@ -package model - -type Settings struct { - ID int `gorm:"primaryKey"` // this is always 1 - CurrentAlgorithm string `json:"current_algorithm" mapstructure:"current_algorithm"` - LocationConfidence int64 `json:"location_confidence" mapstructure:"location_confidence"` - LastSeenThreshold int64 `json:"last_seen_threshold" mapstructure:"last_seen_threshold"` - BeaconMetricSize int `json:"beacon_metric_size" mapstructure:"beacon_metric_size"` - HASendInterval int `json:"HA_send_interval" mapstructure:"HA_send_interval"` - HASendChangesOnly bool `json:"HA_send_changes_only" mapstructure:"HA_send_changes_only"` - RSSIEnforceThreshold bool `json:"RSSI_enforce_threshold" mapstructure:"RSSI_enforce_threshold"` - RSSIMinThreshold int64 `json:"RSSI_min_threshold" mapstructure:"RSSI_min_threshold"` -} diff --git a/internal/pkg/model/types.go b/internal/pkg/model/types.go index 780bc6a..c46e9e1 100644 --- a/internal/pkg/model/types.go +++ b/internal/pkg/model/types.go @@ -1,40 +1,5 @@ package model -import ( - "sync" -) - -// BeaconAdvertisement represents the JSON payload received from beacon advertisements. -type BeaconAdvertisement struct { - ID string - Hostname string `json:"hostname"` - MAC string `json:"mac"` - RSSI int64 `json:"rssi"` - ScanResponse string `json:"is_scan_response"` - Type string `json:"type"` - Data string `json:"data"` - BeaconType string `json:"beacon_type"` - UUID string `json:"uuid"` - Major string `json:"major"` - Minor string `json:"minor"` - TXPower string `json:"tx_power"` - NamespaceID string `json:"namespace"` - InstanceID string `json:"instance_id"` - HSButtonCounter int64 `json:"hb_button_counter"` - HSButtonPrev int64 `json:"hb_button_counter_prev"` - HSBatteryLevel int64 `json:"hb_button_battery"` - HSRandomNonce string `json:"hb_button_random"` - HSButtonMode string `json:"hb_button_mode"` -} - -// BeaconMetric stores signal and distance data for a beacon. -type BeaconMetric struct { - Location string - Distance float64 - RSSI int64 - Timestamp int64 -} - // HTTPLocation describes a beacon's state as served over HTTP. type HTTPLocation struct { Method string `json:"method"` @@ -50,80 +15,6 @@ type HTTPLocation struct { MAC string `json:"mac"` } -// Beacon holds all relevant information about a tracked beacon device. -type Beacon struct { - Name string `json:"name"` - ID string `json:"beacon_id"` - BeaconType string `json:"beacon_type"` - BeaconLocation string `json:"beacon_location"` - LastSeen int64 `json:"last_seen"` - IncomingJSON BeaconAdvertisement `json:"incoming_json"` - Distance float64 `json:"distance"` - PreviousLocation string - PreviousConfidentLocation string - ExpiredLocation string - LocationConfidence int64 - LocationHistory []string - BeaconMetrics []BeaconMetric - Location string `json:"location"` - HSButtonCounter int64 `json:"hs_button_counter"` - HSButtonPrev int64 `json:"hs_button_counter_prev"` - HSBattery int64 `json:"hs_button_battery"` - HSRandomNonce string `json:"hs_button_random"` - HSButtonMode string `json:"hs_button_mode"` - Event int `json:"beacon_event"` -} - -type BeaconEvent struct { - Name string - ID string - Type string - Battery uint32 - Event int - AccX int16 - AccY int16 - AccZ int16 - Temperature uint16 - Heart int16 - BtnPressed bool -} - -type HTTPResult struct { - BeaconId string `json:"id"` - Name string `json:"name"` - ID string `json:"MAC"` - Status string `json:"status"` - Model string `json:"model"` - Position string `json:"position"` - Notes string `json:"notes"` - X float32 `json:"x"` - Y float32 `json:"y"` - Zone string `json:"zone"` - Building string `json:"building"` - BeaconType string `json:"type"` - Battery int64 `json:"battery"` - Event int `json:"event"` - Distance float64 `json:"distance"` - LastSeen int64 `json:"timestamp"` - PreviousConfidentLocation string `json:"previous_confident_location"` -} - -// BeaconsList holds all known beacons and their synchronization lock. -type BeaconsList struct { - Beacons map[string]Beacon `json:"beacons"` - Lock sync.RWMutex -} - -type BeaconEventList struct { - Beacons map[string]BeaconEvent - Lock sync.RWMutex -} - -type BeaconsLookup struct { - Lookup map[string]string - Lock sync.RWMutex -} - // RawReading represents an incoming raw sensor reading. type RawReading struct { Timestamp string `json:"timestamp"` diff --git a/location b/location index a61f4a7..0d97725 100755 Binary files a/location and b/location differ diff --git a/server b/server index eb43498..09cf83c 100755 Binary files a/server and b/server differ