From 3eec48381072cc4ac5abda69ed7bf5c8679cf9ca Mon Sep 17 00:00:00 2001 From: Orne Brocaar Date: Thu, 21 May 2020 11:24:22 +0200 Subject: [PATCH] Cleanup Geolocation Server integration. Geolocation is now provided through a LoRa Cloud integration in ChirpStack Application Server. Alternatively, all the meta-data (fine-timestamp, SNR, RSSI) needed for geolocation is already exposed by ChirpStack Application Server so that geolocation through an external service is still a possibility. The advantage of performing geolocation in the Application Server is that it can use a combination of TDOA, RSSI, Wifi, GNSS and potentially other sources for geolocation. For geolocation using Wifi, GNSS, ... the payload must be decrypted first, which can only be done by the Application Server. --- .../cmd/configfile.go | 20 - cmd/chirpstack-network-server/cmd/root_run.go | 38 -- docs/content/install/config.md | 20 - go.mod | 2 +- go.sum | 4 +- internal/api/network_server.go | 86 ++- internal/api/network_server_test.go | 80 ++- .../backend/geolocationserver/geolocation.go | 15 - internal/config/config.go | 7 - internal/storage/device_profile.go | 66 +- internal/storage/device_profile_test.go | 42 +- internal/storage/geoloc_buffer.go | 103 --- internal/storage/geoloc_buffer_test.go | 125 ---- internal/test/test.go | 29 - internal/testsuite/assertions_test.go | 54 -- internal/testsuite/geolocation_test.go | 642 ------------------ internal/testsuite/integration_test.go | 75 -- internal/uplink/data/data.go | 134 ---- .../0027_remove_geoloc_buffer_fields.sql | 13 + 19 files changed, 139 insertions(+), 1416 deletions(-) delete mode 100644 internal/backend/geolocationserver/geolocation.go delete mode 100644 internal/storage/geoloc_buffer.go delete mode 100644 internal/storage/geoloc_buffer_test.go delete mode 100644 internal/testsuite/geolocation_test.go create mode 100644 migrations/0027_remove_geoloc_buffer_fields.sql diff --git a/cmd/chirpstack-network-server/cmd/configfile.go b/cmd/chirpstack-network-server/cmd/configfile.go index ecdde5c4..7e948da4 100644 --- a/cmd/chirpstack-network-server/cmd/configfile.go +++ b/cmd/chirpstack-network-server/cmd/configfile.go @@ -625,26 +625,6 @@ get_downlink_data_delay="{{ .NetworkServer.GetDownlinkDataDelay }}" commands_connection_string="{{ .NetworkServer.Gateway.Backend.AzureIoTHub.CommandsConnectionString }}" - # Geolocation settings. - # - # When set, ChirpStack Network Server will use the configured geolocation server to - # resolve the location of the devices. - [geolocation_server] - # Server. - # - # The hostname:ip of the geolocation service (optional). - server="{{ .GeolocationServer.Server }}" - - # CA certificate used by the API client (optional). - ca_cert="{{ .GeolocationServer.CACert}}" - - # TLS certificate used by the API client (optional). - tls_cert="{{ .GeolocationServer.TLSCert }}" - - # TLS key used by the API client (optional). - tls_key="{{ .GeolocationServer.TLSKey }}" - - # Monitoring settings. # # Note that this replaces the metrics configuration. If a metrics section is diff --git a/cmd/chirpstack-network-server/cmd/root_run.go b/cmd/chirpstack-network-server/cmd/root_run.go index 9ca05c0a..4d6280ec 100644 --- a/cmd/chirpstack-network-server/cmd/root_run.go +++ b/cmd/chirpstack-network-server/cmd/root_run.go @@ -17,7 +17,6 @@ import ( "google.golang.org/grpc/balancer/roundrobin" "google.golang.org/grpc/credentials" - "github.com/brocaar/chirpstack-api/go/v3/geo" "github.com/brocaar/chirpstack-api/go/v3/nc" "github.com/brocaar/chirpstack-network-server/internal/adr" "github.com/brocaar/chirpstack-network-server/internal/api" @@ -28,7 +27,6 @@ import ( "github.com/brocaar/chirpstack-network-server/internal/backend/gateway/azureiothub" "github.com/brocaar/chirpstack-network-server/internal/backend/gateway/gcppubsub" "github.com/brocaar/chirpstack-network-server/internal/backend/gateway/mqtt" - "github.com/brocaar/chirpstack-network-server/internal/backend/geolocationserver" "github.com/brocaar/chirpstack-network-server/internal/backend/joinserver" "github.com/brocaar/chirpstack-network-server/internal/band" "github.com/brocaar/chirpstack-network-server/internal/config" @@ -56,7 +54,6 @@ func run(cmd *cobra.Command, args []string) error { setGatewayBackend, setupApplicationServer, setupADR, - setupGeolocationServer, setupJoinServer, setupNetworkController, setupUplink, @@ -226,41 +223,6 @@ func setupApplicationServer() error { return nil } -func setupGeolocationServer() error { - // TODO: move setup to gelolocation.Setup - if config.C.GeolocationServer.Server == "" { - log.Info("no geolocation-server configured") - return nil - } - - log.WithFields(log.Fields{ - "server": config.C.GeolocationServer.Server, - "ca_cert": config.C.GeolocationServer.CACert, - "tls_cert": config.C.GeolocationServer.TLSCert, - "tls_key": config.C.GeolocationServer.TLSKey, - }).Info("connecting to geolocation-server") - - dialOptions := []grpc.DialOption{ - grpc.WithBalancerName(roundrobin.Name), - } - if config.C.GeolocationServer.TLSCert != "" && config.C.GeolocationServer.TLSKey != "" { - dialOptions = append(dialOptions, grpc.WithTransportCredentials( - mustGetTransportCredentials(config.C.GeolocationServer.TLSCert, config.C.GeolocationServer.TLSKey, config.C.GeolocationServer.CACert, false), - )) - } else { - dialOptions = append(dialOptions, grpc.WithInsecure()) - } - - geoConn, err := grpc.Dial(config.C.GeolocationServer.Server, dialOptions...) - if err != nil { - return errors.Wrap(err, "geolocation-server dial error") - } - - geolocationserver.SetClient(geo.NewGeolocationServerServiceClient(geoConn)) - - return nil -} - func setupJoinServer() error { if err := joinserver.Setup(config.C); err != nil { return errors.Wrap(err, "setup join-server backend error") diff --git a/docs/content/install/config.md b/docs/content/install/config.md index 75b9c156..38b4fc8c 100644 --- a/docs/content/install/config.md +++ b/docs/content/install/config.md @@ -675,26 +675,6 @@ get_downlink_data_delay="100ms" commands_connection_string="" - # Geolocation settings. - # - # When set, ChirpStack Network Server will use the configured geolocation server to - # resolve the location of the devices. - [geolocation_server] - # Server. - # - # The hostname:ip of the geolocation service (optional). - server="" - - # CA certificate used by the API client (optional). - ca_cert="" - - # TLS certificate used by the API client (optional). - tls_cert="" - - # TLS key used by the API client (optional). - tls_key="" - - # Monitoring settings. # # Note that this replaces the metrics configuration. If a metrics section is diff --git a/go.mod b/go.mod index 457b8916..be219a48 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Azure/azure-amqp-common-go v1.1.4 github.com/Azure/azure-service-bus-go v0.9.1 github.com/NickBall/go-aes-key-wrap v0.0.0-20170929221519-1c3aa3e4dfc5 - github.com/brocaar/chirpstack-api/go/v3 v3.5.1 + github.com/brocaar/chirpstack-api/go/v3 v3.6.1 github.com/brocaar/lorawan v0.0.0-20191115102621-6095d473cf60 github.com/eclipse/paho.mqtt.golang v1.2.0 github.com/elazarl/go-bindata-assetfs v1.0.0 diff --git a/go.sum b/go.sum index cd98bf43..3536b59c 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI= github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= -github.com/brocaar/chirpstack-api/go/v3 v3.5.1 h1:/XIDgKS3hzrqJrPqFU+KXtwcZneccCcCU4N4kN/2jAQ= -github.com/brocaar/chirpstack-api/go/v3 v3.5.1/go.mod h1:ex/wqXQaClwDMa2zDN6crp9ZiMGc1GMVQhjxiB+OJcg= +github.com/brocaar/chirpstack-api/go/v3 v3.6.1 h1:piHy2E2om9ah/auNc4Dn3U84CX4t0suUr2ykXrqgxbo= +github.com/brocaar/chirpstack-api/go/v3 v3.6.1/go.mod h1:ex/wqXQaClwDMa2zDN6crp9ZiMGc1GMVQhjxiB+OJcg= github.com/brocaar/lorawan v0.0.0-20191115102621-6095d473cf60 h1:jecx8QFcsUAWZojNIqOZaoAWFwkBbd3VOHZ3kv6FQxE= github.com/brocaar/lorawan v0.0.0-20191115102621-6095d473cf60/go.mod h1:VgyRGAJ/wl1JfqZZmNlCTM8fyaIKF11YvYAGIVtedL8= github.com/caarlos0/ctrlc v1.0.0 h1:2DtF8GSIcajgffDFJzyG15vO+1PuBWOMUdFut7NnXhw= diff --git a/internal/api/network_server.go b/internal/api/network_server.go index 0da35660..81fd9dd1 100644 --- a/internal/api/network_server.go +++ b/internal/api/network_server.go @@ -346,28 +346,26 @@ func (n *NetworkServerAPI) CreateDeviceProfile(ctx context.Context, req *ns.Crea } dp := storage.DeviceProfile{ - ID: dpID, - SupportsClassB: req.DeviceProfile.SupportsClassB, - ClassBTimeout: int(req.DeviceProfile.ClassBTimeout), - PingSlotPeriod: int(req.DeviceProfile.PingSlotPeriod), - PingSlotDR: int(req.DeviceProfile.PingSlotDr), - PingSlotFreq: int(req.DeviceProfile.PingSlotFreq), - SupportsClassC: req.DeviceProfile.SupportsClassC, - ClassCTimeout: int(req.DeviceProfile.ClassCTimeout), - MACVersion: req.DeviceProfile.MacVersion, - RegParamsRevision: req.DeviceProfile.RegParamsRevision, - RXDelay1: int(req.DeviceProfile.RxDelay_1), - RXDROffset1: int(req.DeviceProfile.RxDrOffset_1), - RXDataRate2: int(req.DeviceProfile.RxDatarate_2), - RXFreq2: int(req.DeviceProfile.RxFreq_2), - FactoryPresetFreqs: factoryPresetFreqs, - MaxEIRP: int(req.DeviceProfile.MaxEirp), - MaxDutyCycle: int(req.DeviceProfile.MaxDutyCycle), - SupportsJoin: req.DeviceProfile.SupportsJoin, - Supports32bitFCnt: req.DeviceProfile.Supports_32BitFCnt, - RFRegion: band.Band().Name(), - GeolocBufferTTL: int(req.DeviceProfile.GeolocBufferTtl), - GeolocMinBufferSize: int(req.DeviceProfile.GeolocMinBufferSize), + ID: dpID, + SupportsClassB: req.DeviceProfile.SupportsClassB, + ClassBTimeout: int(req.DeviceProfile.ClassBTimeout), + PingSlotPeriod: int(req.DeviceProfile.PingSlotPeriod), + PingSlotDR: int(req.DeviceProfile.PingSlotDr), + PingSlotFreq: int(req.DeviceProfile.PingSlotFreq), + SupportsClassC: req.DeviceProfile.SupportsClassC, + ClassCTimeout: int(req.DeviceProfile.ClassCTimeout), + MACVersion: req.DeviceProfile.MacVersion, + RegParamsRevision: req.DeviceProfile.RegParamsRevision, + RXDelay1: int(req.DeviceProfile.RxDelay_1), + RXDROffset1: int(req.DeviceProfile.RxDrOffset_1), + RXDataRate2: int(req.DeviceProfile.RxDatarate_2), + RXFreq2: int(req.DeviceProfile.RxFreq_2), + FactoryPresetFreqs: factoryPresetFreqs, + MaxEIRP: int(req.DeviceProfile.MaxEirp), + MaxDutyCycle: int(req.DeviceProfile.MaxDutyCycle), + SupportsJoin: req.DeviceProfile.SupportsJoin, + Supports32bitFCnt: req.DeviceProfile.Supports_32BitFCnt, + RFRegion: band.Band().Name(), } if err := storage.CreateDeviceProfile(ctx, storage.DB(), &dp); err != nil { @@ -396,28 +394,26 @@ func (n *NetworkServerAPI) GetDeviceProfile(ctx context.Context, req *ns.GetDevi resp := ns.GetDeviceProfileResponse{ DeviceProfile: &ns.DeviceProfile{ - Id: dp.ID.Bytes(), - SupportsClassB: dp.SupportsClassB, - ClassBTimeout: uint32(dp.ClassBTimeout), - PingSlotPeriod: uint32(dp.PingSlotPeriod), - PingSlotDr: uint32(dp.PingSlotDR), - PingSlotFreq: uint32(dp.PingSlotFreq), - SupportsClassC: dp.SupportsClassC, - ClassCTimeout: uint32(dp.ClassCTimeout), - MacVersion: dp.MACVersion, - RegParamsRevision: dp.RegParamsRevision, - RxDelay_1: uint32(dp.RXDelay1), - RxDrOffset_1: uint32(dp.RXDROffset1), - RxDatarate_2: uint32(dp.RXDataRate2), - RxFreq_2: uint32(dp.RXFreq2), - FactoryPresetFreqs: factoryPresetFreqs, - MaxEirp: uint32(dp.MaxEIRP), - MaxDutyCycle: uint32(dp.MaxDutyCycle), - SupportsJoin: dp.SupportsJoin, - RfRegion: string(dp.RFRegion), - Supports_32BitFCnt: dp.Supports32bitFCnt, - GeolocBufferTtl: uint32(dp.GeolocBufferTTL), - GeolocMinBufferSize: uint32(dp.GeolocMinBufferSize), + Id: dp.ID.Bytes(), + SupportsClassB: dp.SupportsClassB, + ClassBTimeout: uint32(dp.ClassBTimeout), + PingSlotPeriod: uint32(dp.PingSlotPeriod), + PingSlotDr: uint32(dp.PingSlotDR), + PingSlotFreq: uint32(dp.PingSlotFreq), + SupportsClassC: dp.SupportsClassC, + ClassCTimeout: uint32(dp.ClassCTimeout), + MacVersion: dp.MACVersion, + RegParamsRevision: dp.RegParamsRevision, + RxDelay_1: uint32(dp.RXDelay1), + RxDrOffset_1: uint32(dp.RXDROffset1), + RxDatarate_2: uint32(dp.RXDataRate2), + RxFreq_2: uint32(dp.RXFreq2), + FactoryPresetFreqs: factoryPresetFreqs, + MaxEirp: uint32(dp.MaxEIRP), + MaxDutyCycle: uint32(dp.MaxDutyCycle), + SupportsJoin: dp.SupportsJoin, + RfRegion: string(dp.RFRegion), + Supports_32BitFCnt: dp.Supports32bitFCnt, }, } @@ -473,8 +469,6 @@ func (n *NetworkServerAPI) UpdateDeviceProfile(ctx context.Context, req *ns.Upda dp.SupportsJoin = req.DeviceProfile.SupportsJoin dp.Supports32bitFCnt = req.DeviceProfile.Supports_32BitFCnt dp.RFRegion = band.Band().Name() - dp.GeolocBufferTTL = int(req.DeviceProfile.GeolocBufferTtl) - dp.GeolocMinBufferSize = int(req.DeviceProfile.GeolocMinBufferSize) if err := storage.FlushDeviceProfileCache(ctx, dp.ID); err != nil { return nil, errToRPCError(err) diff --git a/internal/api/network_server_test.go b/internal/api/network_server_test.go index c03e98f7..372cbbc4 100644 --- a/internal/api/network_server_test.go +++ b/internal/api/network_server_test.go @@ -348,26 +348,24 @@ func TestNetworkServerAPI(t *testing.T) { Convey("When calling CreateDeviceProfile", func() { resp, err := api.CreateDeviceProfile(ctx, &ns.CreateDeviceProfileRequest{ DeviceProfile: &ns.DeviceProfile{ - SupportsClassB: true, - ClassBTimeout: 1, - PingSlotPeriod: 2, - PingSlotDr: 3, - PingSlotFreq: 868100000, - SupportsClassC: true, - ClassCTimeout: 4, - MacVersion: "1.0.2", - RegParamsRevision: "B", - RxDelay_1: 5, - RxDrOffset_1: 6, - RxDatarate_2: 7, - RxFreq_2: 868200000, - FactoryPresetFreqs: []uint32{868100000, 868300000, 868500000}, - MaxEirp: 14, - MaxDutyCycle: 1, - SupportsJoin: true, - Supports_32BitFCnt: true, - GeolocBufferTtl: 60, - GeolocMinBufferSize: 3, + SupportsClassB: true, + ClassBTimeout: 1, + PingSlotPeriod: 2, + PingSlotDr: 3, + PingSlotFreq: 868100000, + SupportsClassC: true, + ClassCTimeout: 4, + MacVersion: "1.0.2", + RegParamsRevision: "B", + RxDelay_1: 5, + RxDrOffset_1: 6, + RxDatarate_2: 7, + RxFreq_2: 868200000, + FactoryPresetFreqs: []uint32{868100000, 868300000, 868500000}, + MaxEirp: 14, + MaxDutyCycle: 1, + SupportsJoin: true, + Supports_32BitFCnt: true, }, }) So(err, ShouldBeNil) @@ -380,28 +378,26 @@ func TestNetworkServerAPI(t *testing.T) { }) So(err, ShouldBeNil) So(getResp.DeviceProfile, ShouldResemble, &ns.DeviceProfile{ - Id: resp.Id, - SupportsClassB: true, - ClassBTimeout: 1, - PingSlotPeriod: 2, - PingSlotDr: 3, - PingSlotFreq: 868100000, - SupportsClassC: true, - ClassCTimeout: 4, - MacVersion: "1.0.2", - RegParamsRevision: "B", - RxDelay_1: 5, - RxDrOffset_1: 6, - RxDatarate_2: 7, - RxFreq_2: 868200000, - FactoryPresetFreqs: []uint32{868100000, 868300000, 868500000}, - MaxEirp: 14, - MaxDutyCycle: 1, - SupportsJoin: true, - RfRegion: "EU868", // set by the api - Supports_32BitFCnt: true, - GeolocBufferTtl: 60, - GeolocMinBufferSize: 3, + Id: resp.Id, + SupportsClassB: true, + ClassBTimeout: 1, + PingSlotPeriod: 2, + PingSlotDr: 3, + PingSlotFreq: 868100000, + SupportsClassC: true, + ClassCTimeout: 4, + MacVersion: "1.0.2", + RegParamsRevision: "B", + RxDelay_1: 5, + RxDrOffset_1: 6, + RxDatarate_2: 7, + RxFreq_2: 868200000, + FactoryPresetFreqs: []uint32{868100000, 868300000, 868500000}, + MaxEirp: 14, + MaxDutyCycle: 1, + SupportsJoin: true, + RfRegion: "EU868", // set by the api + Supports_32BitFCnt: true, }) }) }) diff --git a/internal/backend/geolocationserver/geolocation.go b/internal/backend/geolocationserver/geolocation.go deleted file mode 100644 index e1908485..00000000 --- a/internal/backend/geolocationserver/geolocation.go +++ /dev/null @@ -1,15 +0,0 @@ -package geolocationserver - -import "github.com/brocaar/chirpstack-api/go/v3/geo" - -var client geo.GeolocationServerServiceClient - -// SetClient sets the given geolocation-server client. -func SetClient(c geo.GeolocationServerServiceClient) { - client = c -} - -// Client returns the geolocation-server client. -func Client() geo.GeolocationServerServiceClient { - return client -} diff --git a/internal/config/config.go b/internal/config/config.go index f5118e04..1b5b6a3e 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -146,13 +146,6 @@ type Config struct { } `mapstructure:"gateway"` } `mapstructure:"network_server"` - GeolocationServer struct { - Server string `mapstructure:"server"` - CACert string `mapstructure:"ca_cert"` - TLSCert string `mapstructure:"tls_cert"` - TLSKey string `mapstructure:"tls_key"` - } `mapstructure:"geolocation_server"` - JoinServer struct { ResolveJoinEUI bool `mapstructure:"resolve_join_eui"` ResolveDomainSuffix string `mapstructure:"resolve_domain_suffix"` diff --git a/internal/storage/device_profile.go b/internal/storage/device_profile.go index d0b02894..ce56e8be 100644 --- a/internal/storage/device_profile.go +++ b/internal/storage/device_profile.go @@ -23,30 +23,28 @@ const ( // DeviceProfile defines the backend.DeviceProfile with some extra meta-data type DeviceProfile struct { - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` - ID uuid.UUID `db:"device_profile_id"` - SupportsClassB bool `db:"supports_class_b"` - ClassBTimeout int `db:"class_b_timeout"` // Unit: seconds - PingSlotPeriod int `db:"ping_slot_period"` - PingSlotDR int `db:"ping_slot_dr"` - PingSlotFreq int `db:"ping_slot_freq"` // in Hz - SupportsClassC bool `db:"supports_class_c"` - ClassCTimeout int `db:"class_c_timeout"` // Unit: seconds - MACVersion string `db:"mac_version"` // Example: "1.0.2" [LW102] - RegParamsRevision string `db:"reg_params_revision"` // Example: "B" [RP102B] - RXDelay1 int `db:"rx_delay_1"` - RXDROffset1 int `db:"rx_dr_offset_1"` - RXDataRate2 int `db:"rx_data_rate_2"` // Unit: bits-per-second - RXFreq2 int `db:"rx_freq_2"` // In Hz - FactoryPresetFreqs []int `db:"factory_preset_freqs"` // In Hz - MaxEIRP int `db:"max_eirp"` // In dBm - MaxDutyCycle int `db:"max_duty_cycle"` // Example: 10 indicates 10% - SupportsJoin bool `db:"supports_join"` - RFRegion string `db:"rf_region"` - Supports32bitFCnt bool `db:"supports_32bit_fcnt"` - GeolocBufferTTL int `db:"geoloc_buffer_ttl"` - GeolocMinBufferSize int `db:"geoloc_min_buffer_size"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` + ID uuid.UUID `db:"device_profile_id"` + SupportsClassB bool `db:"supports_class_b"` + ClassBTimeout int `db:"class_b_timeout"` // Unit: seconds + PingSlotPeriod int `db:"ping_slot_period"` + PingSlotDR int `db:"ping_slot_dr"` + PingSlotFreq int `db:"ping_slot_freq"` // in Hz + SupportsClassC bool `db:"supports_class_c"` + ClassCTimeout int `db:"class_c_timeout"` // Unit: seconds + MACVersion string `db:"mac_version"` // Example: "1.0.2" [LW102] + RegParamsRevision string `db:"reg_params_revision"` // Example: "B" [RP102B] + RXDelay1 int `db:"rx_delay_1"` + RXDROffset1 int `db:"rx_dr_offset_1"` + RXDataRate2 int `db:"rx_data_rate_2"` // Unit: bits-per-second + RXFreq2 int `db:"rx_freq_2"` // In Hz + FactoryPresetFreqs []int `db:"factory_preset_freqs"` // In Hz + MaxEIRP int `db:"max_eirp"` // In dBm + MaxDutyCycle int `db:"max_duty_cycle"` // Example: 10 indicates 10% + SupportsJoin bool `db:"supports_join"` + RFRegion string `db:"rf_region"` + Supports32bitFCnt bool `db:"supports_32bit_fcnt"` } // CreateDeviceProfile creates the given device-profile. @@ -88,10 +86,8 @@ func CreateDeviceProfile(ctx context.Context, db sqlx.Execer, dp *DeviceProfile) max_duty_cycle, supports_join, rf_region, - supports_32bit_fcnt, - geoloc_buffer_ttl, - geoloc_min_buffer_size - ) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24)`, + supports_32bit_fcnt + ) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)`, dp.CreatedAt, dp.UpdatedAt, dp.ID, @@ -114,8 +110,6 @@ func CreateDeviceProfile(ctx context.Context, db sqlx.Execer, dp *DeviceProfile) dp.SupportsJoin, dp.RFRegion, dp.Supports32bitFCnt, - dp.GeolocBufferTTL, - dp.GeolocMinBufferSize, ) if err != nil { return handlePSQLError(err, "insert error") @@ -239,9 +233,7 @@ func GetDeviceProfile(ctx context.Context, db sqlx.Queryer, id uuid.UUID) (Devic max_duty_cycle, supports_join, rf_region, - supports_32bit_fcnt, - geoloc_buffer_ttl, - geoloc_min_buffer_size + supports_32bit_fcnt from device_profile where device_profile_id = $1 @@ -272,8 +264,6 @@ func GetDeviceProfile(ctx context.Context, db sqlx.Queryer, id uuid.UUID) (Devic &dp.SupportsJoin, &dp.RFRegion, &dp.Supports32bitFCnt, - &dp.GeolocBufferTTL, - &dp.GeolocMinBufferSize, ) if err != nil { return dp, handlePSQLError(err, "select error") @@ -312,9 +302,7 @@ func UpdateDeviceProfile(ctx context.Context, db sqlx.Execer, dp *DeviceProfile) max_duty_cycle = $18, supports_join = $19, rf_region = $20, - supports_32bit_fcnt = $21, - geoloc_buffer_ttl = $22, - geoloc_min_buffer_size = $23 + supports_32bit_fcnt = $21 where device_profile_id = $1`, dp.ID, @@ -338,8 +326,6 @@ func UpdateDeviceProfile(ctx context.Context, db sqlx.Execer, dp *DeviceProfile) dp.SupportsJoin, dp.RFRegion, dp.Supports32bitFCnt, - dp.GeolocBufferTTL, - dp.GeolocMinBufferSize, ) if err != nil { return handlePSQLError(err, "update error") diff --git a/internal/storage/device_profile_test.go b/internal/storage/device_profile_test.go index 47f3758d..70ed1109 100644 --- a/internal/storage/device_profile_test.go +++ b/internal/storage/device_profile_test.go @@ -24,27 +24,25 @@ func TestDeviceProfile(t *testing.T) { Convey("When creating a device-profile", func() { dp := DeviceProfile{ - SupportsClassB: true, - ClassBTimeout: 1, - PingSlotPeriod: 2, - PingSlotDR: 3, - PingSlotFreq: 868100000, - SupportsClassC: true, - ClassCTimeout: 4, - MACVersion: "1.0.2", - RegParamsRevision: "B", - RXDelay1: 5, - RXDROffset1: 6, - RXDataRate2: 7, - RXFreq2: 868200000, - FactoryPresetFreqs: []int{868400000, 868500000, 868700000}, - MaxEIRP: 17, - MaxDutyCycle: 10, - SupportsJoin: true, - RFRegion: "EU868", - Supports32bitFCnt: true, - GeolocBufferTTL: 10, - GeolocMinBufferSize: 3, + SupportsClassB: true, + ClassBTimeout: 1, + PingSlotPeriod: 2, + PingSlotDR: 3, + PingSlotFreq: 868100000, + SupportsClassC: true, + ClassCTimeout: 4, + MACVersion: "1.0.2", + RegParamsRevision: "B", + RXDelay1: 5, + RXDROffset1: 6, + RXDataRate2: 7, + RXFreq2: 868200000, + FactoryPresetFreqs: []int{868400000, 868500000, 868700000}, + MaxEIRP: 17, + MaxDutyCycle: 10, + SupportsJoin: true, + RFRegion: "EU868", + Supports32bitFCnt: true, } So(CreateDeviceProfile(context.Background(), DB(), &dp), ShouldBeNil) @@ -106,8 +104,6 @@ func TestDeviceProfile(t *testing.T) { dp.SupportsJoin = false dp.RFRegion = "US902" dp.Supports32bitFCnt = false - dp.GeolocBufferTTL = 20 - dp.GeolocMinBufferSize = 4 So(UpdateDeviceProfile(context.Background(), DB(), &dp), ShouldBeNil) dp.UpdatedAt = dp.UpdatedAt.UTC().Truncate(time.Millisecond) diff --git a/internal/storage/geoloc_buffer.go b/internal/storage/geoloc_buffer.go deleted file mode 100644 index f9e18275..00000000 --- a/internal/storage/geoloc_buffer.go +++ /dev/null @@ -1,103 +0,0 @@ -package storage - -import ( - "context" - "fmt" - "time" - - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes" - "github.com/pkg/errors" - - "github.com/brocaar/chirpstack-api/go/v3/geo" - "github.com/brocaar/lorawan" -) - -const ( - geolocBufferKeyTempl = "lora:ns:device:%s:geoloc:buffer" -) - -// SaveGeolocBuffer saves the given items in the geolocation buffer. -// It overwrites the previous buffer to make sure that expired items do not -// stay in the buffer as the TTL is set on the key, not on the items. -func SaveGeolocBuffer(ctx context.Context, devEUI lorawan.EUI64, items []*geo.FrameRXInfo, ttl time.Duration) error { - // nothing to do - if ttl == 0 || len(items) == 0 { - return nil - } - - key := fmt.Sprintf(geolocBufferKeyTempl, devEUI) - - pipe := RedisClient().TxPipeline() - - pipe.Del(key) - for _, item := range items { - b, err := proto.Marshal(item) - if err != nil { - return errors.Wrap(err, "protobuf marshal error") - } - - pipe.RPush(key, b) - } - pipe.PExpire(key, ttl) - - if _, err := pipe.Exec(); err != nil { - return errors.Wrap(err, "redis exec error") - } - - return nil -} - -// GetGeolocBuffer returns the geolocation buffer. Items that exceed the -// given TTL are not returned. -func GetGeolocBuffer(ctx context.Context, devEUI lorawan.EUI64, ttl time.Duration) ([]*geo.FrameRXInfo, error) { - // nothing to do - if ttl == 0 { - return nil, nil - } - - key := fmt.Sprintf(geolocBufferKeyTempl, devEUI) - resp, err := RedisClient().LRange(key, 0, -1).Result() - if err != nil { - return nil, errors.Wrap(err, "read buffer error") - } - - out := make([]*geo.FrameRXInfo, 0, len(resp)) - - for _, b := range resp { - var item geo.FrameRXInfo - if err := proto.Unmarshal([]byte(b), &item); err != nil { - return nil, errors.Wrap(err, "protobuf unmarshal error") - } - - add := true - - for _, rxInfo := range item.RxInfo { - // Ignore frames without time which could happen when a gateway - // for example lost its gps fix, ... - // Avoid that a missing Time results in an error in the next step. - if rxInfo.Time == nil { - add = false - break - } - - ts, err := ptypes.Timestamp(rxInfo.Time) - if err != nil { - return nil, errors.Wrap(err, "get timestamp error") - } - - // Ignore items before TTL as the TTL is set on the key of the buffer, - // not on the item. - if time.Now().Sub(ts) > ttl { - add = false - break - } - } - - if add { - out = append(out, &item) - } - } - - return out, nil -} diff --git a/internal/storage/geoloc_buffer_test.go b/internal/storage/geoloc_buffer_test.go deleted file mode 100644 index 54508d53..00000000 --- a/internal/storage/geoloc_buffer_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package storage - -import ( - "context" - "encoding/json" - "testing" - "time" - - "github.com/brocaar/chirpstack-api/go/v3/geo" - "github.com/brocaar/chirpstack-api/go/v3/gw" - "github.com/brocaar/lorawan" - "github.com/golang/protobuf/ptypes" - "github.com/stretchr/testify/require" -) - -func (ts *StorageTestSuite) TestGeolocBuffer() { - now, _ := ptypes.TimestampProto(time.Now()) - tenMinAgo, _ := ptypes.TimestampProto(time.Now().Add(-10 * time.Minute)) - - tests := []struct { - Name string - Items []*geo.FrameRXInfo - DevEUI lorawan.EUI64 - AddTTL time.Duration - GetTTL time.Duration - ExpectedItems []*geo.FrameRXInfo - }{ - { - Name: "add one item to queue - ttl 0", - Items: []*geo.FrameRXInfo{ - { - RxInfo: []*gw.UplinkRXInfo{ - { - Time: now, - }, - }, - }, - }, - }, - { - Name: "add one item to queue", - Items: []*geo.FrameRXInfo{ - { - RxInfo: []*gw.UplinkRXInfo{ - { - Time: now, - }, - }, - }, - }, - ExpectedItems: []*geo.FrameRXInfo{ - { - RxInfo: []*gw.UplinkRXInfo{ - { - Time: now, - }, - }, - }, - }, - AddTTL: time.Minute, - GetTTL: time.Minute, - }, - { - Name: "add three to queue, one expired", - Items: []*geo.FrameRXInfo{ - { - RxInfo: []*gw.UplinkRXInfo{ - { - Time: now, - }, - }, - }, - { - RxInfo: []*gw.UplinkRXInfo{ - { - Time: now, - }, - }, - }, - { - RxInfo: []*gw.UplinkRXInfo{ - { - Time: tenMinAgo, - }, - }, - }, - }, - ExpectedItems: []*geo.FrameRXInfo{ - { - RxInfo: []*gw.UplinkRXInfo{ - { - Time: now, - }, - }, - }, - { - RxInfo: []*gw.UplinkRXInfo{ - { - Time: now, - }, - }, - }, - }, - AddTTL: time.Minute, - GetTTL: time.Minute, - }, - } - - for _, tst := range tests { - ts.T().Run(tst.Name, func(t *testing.T) { - RedisClient().FlushAll() - assert := require.New(t) - - assert.NoError(SaveGeolocBuffer(context.Background(), tst.DevEUI, tst.Items, tst.AddTTL)) - - resp, err := GetGeolocBuffer(context.Background(), tst.DevEUI, tst.GetTTL) - assert.NoError(err) - - aa, _ := json.Marshal(tst.ExpectedItems) - bb, _ := json.Marshal(resp) - - assert.Equal(string(aa), string(bb)) - }) - } -} diff --git a/internal/test/test.go b/internal/test/test.go index 72e076b1..2a6cf375 100644 --- a/internal/test/test.go +++ b/internal/test/test.go @@ -13,7 +13,6 @@ import ( "google.golang.org/grpc" "github.com/brocaar/chirpstack-api/go/v3/as" - "github.com/brocaar/chirpstack-api/go/v3/geo" "github.com/brocaar/chirpstack-api/go/v3/gw" "github.com/brocaar/chirpstack-api/go/v3/nc" "github.com/brocaar/chirpstack-network-server/internal/api/client/asclient" @@ -314,31 +313,3 @@ func (t *NetworkControllerClient) HandleRejectedUplinkFrameSet(ctx context.Conte t.HandleRejectedUplinkFrameSetChan <- *in return &empty.Empty{}, nil } - -// GeolocationClient is a geolocation client for testing. -type GeolocationClient struct { - ResolveTDOAChan chan geo.ResolveTDOARequest - ResolveMultiFrameTDOAChan chan geo.ResolveMultiFrameTDOARequest - ResolveTDOAResponse geo.ResolveTDOAResponse - ResolveMultiFrameTDOAResponse geo.ResolveMultiFrameTDOAResponse -} - -// NewGeolocationClient creates a new GeolocationClient. -func NewGeolocationClient() *GeolocationClient { - return &GeolocationClient{ - ResolveTDOAChan: make(chan geo.ResolveTDOARequest, 100), - ResolveMultiFrameTDOAChan: make(chan geo.ResolveMultiFrameTDOARequest, 100), - } -} - -// ResolveTDOA method. -func (g *GeolocationClient) ResolveTDOA(ctx context.Context, in *geo.ResolveTDOARequest, opts ...grpc.CallOption) (*geo.ResolveTDOAResponse, error) { - g.ResolveTDOAChan <- *in - return &g.ResolveTDOAResponse, nil -} - -// ResolveMultiFrameTDOA method. -func (g *GeolocationClient) ResolveMultiFrameTDOA(ctx context.Context, in *geo.ResolveMultiFrameTDOARequest, opts ...grpc.CallOption) (*geo.ResolveMultiFrameTDOAResponse, error) { - g.ResolveMultiFrameTDOAChan <- *in - return &g.ResolveMultiFrameTDOAResponse, nil -} diff --git a/internal/testsuite/assertions_test.go b/internal/testsuite/assertions_test.go index d215af5b..5b0f4011 100644 --- a/internal/testsuite/assertions_test.go +++ b/internal/testsuite/assertions_test.go @@ -3,7 +3,6 @@ package testsuite import ( "context" "encoding/binary" - "sort" "time" "github.com/gofrs/uuid" @@ -11,7 +10,6 @@ import ( "github.com/stretchr/testify/require" "github.com/brocaar/chirpstack-api/go/v3/as" - "github.com/brocaar/chirpstack-api/go/v3/geo" "github.com/brocaar/chirpstack-api/go/v3/gw" "github.com/brocaar/chirpstack-api/go/v3/nc" "github.com/brocaar/chirpstack-network-server/internal/downlink/ack" @@ -379,58 +377,6 @@ func AssertASSetDeviceStatusRequest(req as.SetDeviceStatusRequest) Assertion { } } -// AssertASSetDeviceLocationRequests asserts the set device-location request. -func AssertASSetDeviceLocationRequest(req as.SetDeviceLocationRequest) Assertion { - return func(assert *require.Assertions, ts *IntegrationTestSuite) { - r := <-ts.ASClient.SetDeviceLocationChan - - // we assume that we can sort on the first byte of each uplink_id - sort.Slice(r.UplinkIds, func(i, j int) bool { - return r.UplinkIds[i][0] < r.UplinkIds[j][0] - }) - - if !proto.Equal(&r, &req) { - assert.Equal(req, r) - } - } -} - -// AssertNoASSetDeviceLocationRequests asserts that there is no set device-location request. -func AssertNoASSetDeviceLocationRequest() Assertion { - return func(assert *require.Assertions, ts *IntegrationTestSuite) { - time.Sleep(100 * time.Millisecond) - select { - case <-ts.ASClient.SetDeviceLocationChan: - assert.Fail("unexpected set device-location request") - default: - } - } -} - -// AssertResolveTDOARequest asserts the ResolveTDOARequest. -func AssertResolveTDOARequest(req geo.ResolveTDOARequest) Assertion { - return func(assert *require.Assertions, ts *IntegrationTestSuite) { - r := <-ts.GeoClient.ResolveTDOAChan - sort.Sort(byGatewayID(r.FrameRxInfo.RxInfo)) - if !proto.Equal(&r, &req) { - assert.Equal(req, r) - } - } -} - -// AssertResolveMultiFrameTDOARequest asserts the ResolveMultiFrameTDOARequest. -func AssertResolveMultiFrameTDOARequest(req geo.ResolveMultiFrameTDOARequest) Assertion { - return func(assert *require.Assertions, ts *IntegrationTestSuite) { - r := <-ts.GeoClient.ResolveMultiFrameTDOAChan - for i := range r.FrameRxInfoSet { - sort.Sort(byGatewayID(r.FrameRxInfoSet[i].RxInfo)) - } - if !proto.Equal(&r, &req) { - assert.Equal(req, r) - } - } -} - type byGatewayID []*gw.UplinkRXInfo func (s byGatewayID) Len() int { diff --git a/internal/testsuite/geolocation_test.go b/internal/testsuite/geolocation_test.go deleted file mode 100644 index dee97a48..00000000 --- a/internal/testsuite/geolocation_test.go +++ /dev/null @@ -1,642 +0,0 @@ -package testsuite - -import ( - "testing" - "time" - - "github.com/golang/protobuf/ptypes" - "github.com/golang/protobuf/ptypes/timestamp" - - "github.com/stretchr/testify/suite" - - "github.com/brocaar/chirpstack-api/go/v3/as" - "github.com/brocaar/chirpstack-api/go/v3/common" - "github.com/brocaar/chirpstack-api/go/v3/geo" - "github.com/brocaar/chirpstack-api/go/v3/gw" - "github.com/brocaar/chirpstack-network-server/internal/storage" - "github.com/brocaar/lorawan" -) - -type GeolocationTestSuite struct { - IntegrationTestSuite -} - -func (ts *GeolocationTestSuite) SetupTest() { - ts.IntegrationTestSuite.SetupTest() - - ts.CreateGateway(storage.Gateway{GatewayID: lorawan.EUI64{1, 1, 1, 1, 1, 1, 1, 1}, Location: storage.GPSPoint{Latitude: 1.1, Longitude: 1.1}, Altitude: 1.1}) - ts.CreateGateway(storage.Gateway{GatewayID: lorawan.EUI64{1, 1, 1, 1, 1, 1, 1, 2}, Location: storage.GPSPoint{Latitude: 2.1, Longitude: 2.1}, Altitude: 2.1}) - ts.CreateGateway(storage.Gateway{GatewayID: lorawan.EUI64{1, 1, 1, 1, 1, 1, 1, 3}, Location: storage.GPSPoint{Latitude: 3.1, Longitude: 3.1}, Altitude: 3.1}) - ts.CreateDevice(storage.Device{DevEUI: lorawan.EUI64{1, 2, 3, 4, 5, 6, 7, 8}}) - ts.CreateDeviceSession(storage.DeviceSession{ReferenceAltitude: 5.6}) -} - -func (ts *GeolocationTestSuite) TestGeolocation() { - now := time.Now() - nowProto, _ := ptypes.TimestampProto(now) - - tests := []GeolocationTest{ - { - Name: "one gateway", - NwkGeoLoc: true, - RXInfo: []*gw.UplinkRXInfo{ - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 1}, - UplinkId: []byte{1}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 1, - }, - }, - }, - }, - }, - Assert: []Assertion{ - AssertNoASSetDeviceLocationRequest(), - }, - }, - { - Name: "two gateways", - NwkGeoLoc: true, - RXInfo: []*gw.UplinkRXInfo{ - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 1}, - UplinkId: []byte{1}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 1, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 2}, - UplinkId: []byte{2}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 2, - }, - }, - }, - }, - }, - Assert: []Assertion{ - AssertNoASSetDeviceLocationRequest(), - }, - }, - - { - Name: "three gateways", - NwkGeoLoc: true, - RXInfo: []*gw.UplinkRXInfo{ - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 1}, - UplinkId: []byte{1}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 1, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 2}, - UplinkId: []byte{2}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 2, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 3}, - UplinkId: []byte{3}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 3, - }, - }, - }, - }, - }, - ResolveTDOAResponse: geo.ResolveTDOAResponse{ - Result: &geo.ResolveResult{ - Location: &common.Location{ - Latitude: 1.123, - Longitude: 2.123, - Altitude: 3.123, - Source: common.LocationSource_GEO_RESOLVER, - }, - }, - }, - Assert: []Assertion{ - AssertResolveTDOARequest(geo.ResolveTDOARequest{ - DevEui: ts.DeviceSession.DevEUI[:], - DeviceReferenceAltitude: 5.6, - FrameRxInfo: &geo.FrameRXInfo{ - RxInfo: []*gw.UplinkRXInfo{ - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 1}, - UplinkId: []byte{1}, - Location: &common.Location{ - Latitude: 1.1, - Longitude: 1.1, - Altitude: 1.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 1, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 2}, - UplinkId: []byte{2}, - Location: &common.Location{ - Latitude: 2.1, - Longitude: 2.1, - Altitude: 2.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 2, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 3}, - UplinkId: []byte{3}, - Location: &common.Location{ - Latitude: 3.1, - Longitude: 3.1, - Altitude: 3.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 3, - }, - }, - }, - }, - }, - }, - }), - AssertASSetDeviceLocationRequest(as.SetDeviceLocationRequest{ - DevEui: ts.DeviceSession.DevEUI[:], - Location: &common.Location{ - Latitude: 1.123, - Longitude: 2.123, - Altitude: 3.123, - Source: common.LocationSource_GEO_RESOLVER, - }, - UplinkIds: [][]byte{ - {1}, - {2}, - {3}, - }, - }), - }, - }, - { - Name: "three gateways NwkGeoLoc disabled", - NwkGeoLoc: false, - RXInfo: []*gw.UplinkRXInfo{ - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 1}, - UplinkId: []byte{1}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 1, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 2}, - UplinkId: []byte{2}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 2, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 3}, - UplinkId: []byte{3}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 3, - }, - }, - }, - }, - }, - ResolveTDOAResponse: geo.ResolveTDOAResponse{ - Result: &geo.ResolveResult{ - Location: &common.Location{ - Latitude: 1.123, - Longitude: 2.123, - Altitude: 3.123, - Source: common.LocationSource_GEO_RESOLVER, - }, - }, - }, - Assert: []Assertion{ - AssertNoASSetDeviceLocationRequest(), - }, - }, - { - Name: "three gateways not enough fine-timestamp data", - NwkGeoLoc: true, - RXInfo: []*gw.UplinkRXInfo{ - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 1}, - UplinkId: []byte{1}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 1, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 2}, - UplinkId: []byte{2}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 2, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 3}, - }, - }, - ResolveTDOAResponse: geo.ResolveTDOAResponse{ - Result: &geo.ResolveResult{ - Location: &common.Location{ - Latitude: 1.123, - Longitude: 2.123, - Altitude: 3.123, - Source: common.LocationSource_GEO_RESOLVER, - }, - }, - }, - Assert: []Assertion{ - AssertNoASSetDeviceLocationRequest(), - }, - }, - { - Name: "three gateways + required 2 frames in buffer (have 1)", - NwkGeoLoc: true, - RXInfo: []*gw.UplinkRXInfo{ - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 1}, - UplinkId: []byte{1}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 1, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 2}, - UplinkId: []byte{2}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 2, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 3}, - UplinkId: []byte{3}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 3, - }, - }, - }, - }, - }, - ResolveMultiFrameTDOAResponse: geo.ResolveMultiFrameTDOAResponse{ - Result: &geo.ResolveResult{ - Location: &common.Location{ - Latitude: 1.123, - Longitude: 2.123, - Altitude: 3.123, - Source: common.LocationSource_GEO_RESOLVER, - }, - }, - }, - GeolocBufferTTL: time.Minute, - GeolocMinBufferSize: 2, - Assert: []Assertion{ - AssertNoASSetDeviceLocationRequest(), - }, - }, - { - Name: "three gateways + required 2 frames in buffer (have 2)", - NwkGeoLoc: true, - RXInfo: []*gw.UplinkRXInfo{ - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 1}, - UplinkId: []byte{1}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 1, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 2}, - UplinkId: []byte{2}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 2, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 3}, - UplinkId: []byte{3}, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 3, - }, - }, - }, - }, - }, - GeolocBufferItems: []*geo.FrameRXInfo{ - { - RxInfo: []*gw.UplinkRXInfo{ - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 1}, - UplinkId: []byte{4}, - Time: nowProto, - Location: &common.Location{ - Latitude: 1.1, - Longitude: 1.1, - Altitude: 1.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 1, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 2}, - UplinkId: []byte{5}, - Time: nowProto, - Location: &common.Location{ - Latitude: 2.1, - Longitude: 2.1, - Altitude: 2.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 2, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 3}, - UplinkId: []byte{6}, - Time: nowProto, - Location: &common.Location{ - Latitude: 3.1, - Longitude: 3.1, - Altitude: 3.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 3, - }, - }, - }, - }, - }, - }, - }, - ResolveMultiFrameTDOAResponse: geo.ResolveMultiFrameTDOAResponse{ - Result: &geo.ResolveResult{ - Location: &common.Location{ - Latitude: 1.123, - Longitude: 2.123, - Altitude: 3.123, - Source: common.LocationSource_GEO_RESOLVER, - }, - }, - }, - GeolocBufferTTL: time.Minute, - GeolocMinBufferSize: 2, - Assert: []Assertion{ - AssertResolveMultiFrameTDOARequest(geo.ResolveMultiFrameTDOARequest{ - DevEui: ts.Device.DevEUI[:], - FrameRxInfoSet: []*geo.FrameRXInfo{ - { - RxInfo: []*gw.UplinkRXInfo{ - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 1}, - UplinkId: []byte{4}, - Time: nowProto, - Location: &common.Location{ - Latitude: 1.1, - Longitude: 1.1, - Altitude: 1.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 1, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 2}, - UplinkId: []byte{5}, - Time: nowProto, - Location: &common.Location{ - Latitude: 2.1, - Longitude: 2.1, - Altitude: 2.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 2, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 3}, - UplinkId: []byte{6}, - Time: nowProto, - Location: &common.Location{ - Latitude: 3.1, - Longitude: 3.1, - Altitude: 3.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 3, - }, - }, - }, - }, - }, - }, - { - RxInfo: []*gw.UplinkRXInfo{ - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 1}, - UplinkId: []byte{1}, - Location: &common.Location{ - Latitude: 1.1, - Longitude: 1.1, - Altitude: 1.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 1, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 2}, - UplinkId: []byte{2}, - Location: &common.Location{ - Latitude: 2.1, - Longitude: 2.1, - Altitude: 2.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 2, - }, - }, - }, - }, - { - GatewayId: []byte{1, 1, 1, 1, 1, 1, 1, 3}, - UplinkId: []byte{3}, - Location: &common.Location{ - Latitude: 3.1, - Longitude: 3.1, - Altitude: 3.1, - }, - FineTimestampType: gw.FineTimestampType_PLAIN, - FineTimestamp: &gw.UplinkRXInfo_PlainFineTimestamp{ - PlainFineTimestamp: &gw.PlainFineTimestamp{ - Time: ×tamp.Timestamp{ - Nanos: 3, - }, - }, - }, - }, - }, - }, - }, - DeviceReferenceAltitude: 5.6, - }), - AssertASSetDeviceLocationRequest(as.SetDeviceLocationRequest{ - DevEui: ts.DeviceSession.DevEUI[:], - Location: &common.Location{ - Latitude: 1.123, - Longitude: 2.123, - Altitude: 3.123, - Source: common.LocationSource_GEO_RESOLVER, - }, - UplinkIds: [][]byte{ - {1}, - {2}, - {3}, - {4}, - {5}, - {6}, - }, - }), - }, - }, - } - - for i, tst := range tests { - ts.T().Run(tst.Name, func(t *testing.T) { - ts.AssertGeolocationTest(t, uint32(i), tst) - }) - } -} - -func TestGeolocation(t *testing.T) { - suite.Run(t, new(GeolocationTestSuite)) -} diff --git a/internal/testsuite/integration_test.go b/internal/testsuite/integration_test.go index 00dac1eb..337ddb75 100644 --- a/internal/testsuite/integration_test.go +++ b/internal/testsuite/integration_test.go @@ -2,29 +2,24 @@ package testsuite import ( "context" - "sync" "testing" - "time" "github.com/gofrs/uuid" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/brocaar/chirpstack-api/go/v3/common" - "github.com/brocaar/chirpstack-api/go/v3/geo" "github.com/brocaar/chirpstack-api/go/v3/gw" "github.com/brocaar/chirpstack-api/go/v3/ns" "github.com/brocaar/chirpstack-network-server/internal/api" "github.com/brocaar/chirpstack-network-server/internal/backend/applicationserver" "github.com/brocaar/chirpstack-network-server/internal/backend/controller" "github.com/brocaar/chirpstack-network-server/internal/backend/gateway" - "github.com/brocaar/chirpstack-network-server/internal/backend/geolocationserver" "github.com/brocaar/chirpstack-network-server/internal/backend/joinserver" jstest "github.com/brocaar/chirpstack-network-server/internal/backend/joinserver/testclient" "github.com/brocaar/chirpstack-network-server/internal/band" "github.com/brocaar/chirpstack-network-server/internal/downlink" "github.com/brocaar/chirpstack-network-server/internal/downlink/ack" - "github.com/brocaar/chirpstack-network-server/internal/helpers" "github.com/brocaar/chirpstack-network-server/internal/storage" "github.com/brocaar/chirpstack-network-server/internal/test" "github.com/brocaar/chirpstack-network-server/internal/uplink" @@ -135,21 +130,6 @@ type DownlinkTXAckTest struct { ExpectedError error } -// GeolocationTest is the structure for a geolocation test. -type GeolocationTest struct { - Name string - BeforeFunc func(*GeolocationTest) error - NwkGeoLoc bool - RXInfo []*gw.UplinkRXInfo - GeolocBufferTTL time.Duration - GeolocMinBufferSize int - GeolocBufferItems []*geo.FrameRXInfo - ResolveTDOAResponse geo.ResolveTDOAResponse - ResolveMultiFrameTDOAResponse geo.ResolveMultiFrameTDOAResponse - - Assert []Assertion -} - // IntegrationTestSuite provides a test-suite for integration-testing // uplink scenarios. type IntegrationTestSuite struct { @@ -159,7 +139,6 @@ type IntegrationTestSuite struct { ASClient *test.ApplicationClient JSClient *jstest.JoinServerClient GWBackend *test.GatewayBackend - GeoClient *test.GeolocationClient NCClient *test.NetworkControllerClient NSAPI ns.NetworkServerServiceServer @@ -206,9 +185,6 @@ func (ts *IntegrationTestSuite) FlushClients() { ts.NCClient = test.NewNetworkControllerClient() controller.SetClient(ts.NCClient) - ts.GeoClient = test.NewGeolocationClient() - geolocationserver.SetClient(ts.GeoClient) - ts.NSAPI = api.NewNetworkServerAPI() } @@ -681,57 +657,6 @@ func (ts *IntegrationTestSuite) AssertDownlinkTXAckTest(t *testing.T, tst Downli } } -// AssertGeolocationTest asserts the given geolocation test. -func (ts *IntegrationTestSuite) AssertGeolocationTest(t *testing.T, fCnt uint32, tst GeolocationTest) { - assert := require.New(t) - - storage.RedisClient().FlushAll() - - ts.FlushClients() - ts.initConfig() - - if tst.BeforeFunc != nil { - assert.NoError(tst.BeforeFunc(&tst)) - } - - ts.DeviceSession.FCntUp = uint32(fCnt) - assert.NoError(storage.SaveDeviceSession(context.Background(), *ts.DeviceSession)) - - ts.GeoClient.ResolveTDOAResponse = tst.ResolveTDOAResponse - ts.GeoClient.ResolveMultiFrameTDOAResponse = tst.ResolveMultiFrameTDOAResponse - - ts.ServiceProfile.NwkGeoLoc = tst.NwkGeoLoc - assert.NoError(storage.UpdateServiceProfile(context.Background(), storage.DB(), ts.ServiceProfile)) - - ts.DeviceProfile.GeolocBufferTTL = int(tst.GeolocBufferTTL / time.Second) - ts.DeviceProfile.GeolocMinBufferSize = tst.GeolocMinBufferSize - assert.NoError(storage.UpdateDeviceProfile(context.Background(), storage.DB(), ts.DeviceProfile)) - - storage.SaveGeolocBuffer(context.Background(), ts.Device.DevEUI, tst.GeolocBufferItems, tst.GeolocBufferTTL) - - txInfo := gw.UplinkTXInfo{ - Frequency: 868100000, - } - assert.NoError(helpers.SetUplinkTXInfoDataRate(&txInfo, 3, band.Band())) - - var wg sync.WaitGroup - for j := range tst.RXInfo { - uf := ts.GetUplinkFrameForFRMPayload(*tst.RXInfo[j], txInfo, lorawan.UnconfirmedDataUp, 10, []byte{1, 2, 3, 4}) - wg.Add(1) - go func(assert *require.Assertions, uf gw.UplinkFrame) { - err := uplink.HandleUplinkFrame(context.Background(), uf) - assert.NoError(err) - wg.Done() - }(assert, uf) - } - - // run assertions - for _, a := range tst.Assert { - a(assert, ts) - } - wg.Wait() -} - func (ts *IntegrationTestSuite) initConfig() { conf := test.GetConfig() diff --git a/internal/uplink/data/data.go b/internal/uplink/data/data.go index e94e7bc4..0ab12230 100644 --- a/internal/uplink/data/data.go +++ b/internal/uplink/data/data.go @@ -10,12 +10,9 @@ import ( "github.com/brocaar/chirpstack-api/go/v3/as" "github.com/brocaar/chirpstack-api/go/v3/common" - "github.com/brocaar/chirpstack-api/go/v3/geo" - "github.com/brocaar/chirpstack-api/go/v3/gw" "github.com/brocaar/chirpstack-api/go/v3/nc" "github.com/brocaar/chirpstack-network-server/internal/backend/applicationserver" "github.com/brocaar/chirpstack-network-server/internal/backend/controller" - "github.com/brocaar/chirpstack-network-server/internal/backend/geolocationserver" "github.com/brocaar/chirpstack-network-server/internal/band" "github.com/brocaar/chirpstack-network-server/internal/config" datadown "github.com/brocaar/chirpstack-network-server/internal/downlink/data" @@ -44,7 +41,6 @@ var tasks = []func(*dataContext) error{ getDeviceProfile, getServiceProfile, getApplicationServerClientForDataUp, - resolveDeviceLocation, setADR, setUplinkDataRate, setBeaconLocked, @@ -306,136 +302,6 @@ func getApplicationServerClientForDataUp(ctx *dataContext) error { return nil } -func resolveDeviceLocation(ctx *dataContext) error { - // Determine if geolocation is enabled in the service-profile. - if !ctx.ServiceProfile.NwkGeoLoc { - log.WithFields(log.Fields{ - "ctx_id": ctx.ctx.Value(logging.ContextIDKey), - "dev_eui": ctx.DeviceSession.DevEUI, - }).Debug("skipping geolocation, it is disabled by the service-profile") - return nil - } - - // Determine if a geolocation server is configured. - if geolocationserver.Client() == nil { - log.WithFields(log.Fields{ - "ctx_id": ctx.ctx.Value(logging.ContextIDKey), - "dev_eui": ctx.DeviceSession.DevEUI, - }).Debug("skipping geolocation, no client configured") - return nil - } - - // Read the geolocation buffer (when TTL=0, this returns an empty slice without db operation). - buffer, err := storage.GetGeolocBuffer(ctx.ctx, ctx.DeviceSession.DevEUI, time.Duration(ctx.DeviceProfile.GeolocBufferTTL)*time.Second) - if err != nil { - fmt.Println("error", err) - return errors.Wrap(err, "get geoloc buffer error") - } - - // Filter out the rx-info with fine-timestamp and if there is enough - // meta-data (at least 3 gateways), add it to the buffer. - var rxInfoWithFineTimestamp []*gw.UplinkRXInfo - for i := range ctx.RXPacket.RXInfoSet { - if ctx.RXPacket.RXInfoSet[i].FineTimestampType == gw.FineTimestampType_PLAIN { - rxInfoWithFineTimestamp = append(rxInfoWithFineTimestamp, ctx.RXPacket.RXInfoSet[i]) - } - } - if len(rxInfoWithFineTimestamp) >= 3 { - buffer = append(buffer, &geo.FrameRXInfo{ - RxInfo: rxInfoWithFineTimestamp, - }) - } - - // Save the buffer when there are > 0 items. - if len(buffer) != 0 { - if err := storage.SaveGeolocBuffer(ctx.ctx, ctx.DeviceSession.DevEUI, buffer, time.Duration(ctx.DeviceProfile.GeolocBufferTTL)*time.Second); err != nil { - return errors.Wrap(err, "save geoloc buffer error") - } - } - - // Return if the buffer is empty or when there are less frames in the buffer - // than configured in the device-profile. - if len(buffer) == 0 || len(buffer) < ctx.DeviceProfile.GeolocMinBufferSize { - log.WithFields(log.Fields{ - "dev_eui": ctx.DeviceSession.DevEUI, - "ctx_id": ctx.ctx.Value(logging.ContextIDKey), - }).Debug("skipping geolocation, not enough gateway meta-data or buffer too small") - return nil - } - - // perform the actual geolocation in a separate goroutine - go func(devEUI lorawan.EUI64, referenceAlt float64, geoClient geo.GeolocationServerServiceClient, asClient as.ApplicationServerServiceClient, frames []*geo.FrameRXInfo) { - var result *geo.ResolveResult - - // Single-frame geolocation. - if len(frames) == 1 { - resp, err := geoClient.ResolveTDOA(ctx.ctx, &geo.ResolveTDOARequest{ - DevEui: devEUI[:], - FrameRxInfo: frames[0], - DeviceReferenceAltitude: referenceAlt, - }) - if err != nil { - log.WithFields(log.Fields{ - "ctx_id": ctx.ctx.Value(logging.ContextIDKey), - "dev_eui": devEUI, - }).WithError(err).Error("resolve tdoa error") - return - } - - result = resp.Result - } - - // Multi-frame geolocation. - if len(frames) > 1 { - resp, err := geoClient.ResolveMultiFrameTDOA(ctx.ctx, &geo.ResolveMultiFrameTDOARequest{ - DevEui: devEUI[:], - FrameRxInfoSet: frames, - DeviceReferenceAltitude: referenceAlt, - }) - if err != nil { - log.WithFields(log.Fields{ - "ctx_id": ctx.ctx.Value(logging.ContextIDKey), - "dev_eui": devEUI, - }).WithError(err).Error("resolve multi-frame tdoa error") - return - } - - result = resp.Result - } - - if result == nil || result.Location == nil { - log.WithFields(log.Fields{ - "ctx_id": ctx.ctx.Value(logging.ContextIDKey), - "dev_eui": devEUI, - }).Error("geolocation-server result or result.location must not be nil") - return - } - - uplink_ids := [][]byte{} - for i := range frames { - for j := range frames[i].RxInfo { - uplink_ids = append(uplink_ids, frames[i].RxInfo[j].UplinkId) - } - } - - _, err = asClient.SetDeviceLocation(ctx.ctx, &as.SetDeviceLocationRequest{ - DevEui: devEUI[:], - Location: result.Location, - UplinkIds: uplink_ids, - }) - - if err != nil { - log.WithFields(log.Fields{ - "ctx_id": ctx.ctx.Value(logging.ContextIDKey), - "dev_eui": devEUI, - }).WithError(err).Error("set device-location error") - } - - }(ctx.DeviceSession.DevEUI, ctx.DeviceSession.ReferenceAltitude, geolocationserver.Client(), ctx.ApplicationServerClient, buffer) - - return nil -} - func decryptFOptsMACCommands(ctx *dataContext) error { if ctx.DeviceSession.GetMACVersion() == lorawan.LoRaWAN1_0 { if err := ctx.RXPacket.PHYPayload.DecodeFOptsToMACCommands(); err != nil { diff --git a/migrations/0027_remove_geoloc_buffer_fields.sql b/migrations/0027_remove_geoloc_buffer_fields.sql new file mode 100644 index 00000000..41f7cd78 --- /dev/null +++ b/migrations/0027_remove_geoloc_buffer_fields.sql @@ -0,0 +1,13 @@ +-- +migrate Up +alter table device_profile + drop column geoloc_buffer_ttl, + drop column geoloc_min_buffer_size; + +-- +migrate Down +alter table device_profile + add column geoloc_buffer_ttl integer not null default 0, + add column geoloc_min_buffer_size integer not null default 0; + +alter table device_profile + alter column geoloc_buffer_ttl drop default, + alter column geoloc_min_buffer_size drop default;