add ibeacon scan code to c3nav.js and endpoint
This commit is contained in:
parent
a62017f3a2
commit
31c7dad72f
5 changed files with 82 additions and 26 deletions
|
@ -25,7 +25,7 @@ from c3nav.mapdata.models import GraphEdge, LocationGroup
|
|||
from c3nav.mapdata.models.access import AccessPermission
|
||||
from c3nav.mapdata.models.geometry.space import ObstacleGroup
|
||||
from c3nav.mapdata.models.theme import ThemeLocationGroupBackgroundColor, ThemeObstacleGroupBackgroundColor
|
||||
from c3nav.routing.schemas import LocateRequestPeerSchema
|
||||
from c3nav.routing.schemas import LocateRequestWifiPeerSchema
|
||||
|
||||
|
||||
class EditorFormBase(I18nModelFormMixin, ModelForm):
|
||||
|
@ -340,7 +340,7 @@ class EditorFormBase(I18nModelFormMixin, ModelForm):
|
|||
item['rssi'] = item['level']
|
||||
del item['level']
|
||||
try:
|
||||
LocateRequestPeerSchema.model_validate(item)
|
||||
LocateRequestWifiPeerSchema.model_validate(item)
|
||||
except PydanticValidationError as e:
|
||||
raise ValidationError(str(e))
|
||||
scan_data.append(item)
|
||||
|
|
|
@ -11,14 +11,17 @@ from c3nav.mapdata.models.access import AccessPermission
|
|||
from c3nav.mapdata.schemas.models import CustomLocationSchema
|
||||
from c3nav.mapdata.utils.cache.stats import increment_cache_key
|
||||
from c3nav.routing.locator import Locator
|
||||
from c3nav.routing.schemas import BSSIDSchema, LocateRequestPeerSchema
|
||||
from c3nav.routing.schemas import BSSIDSchema, LocateRequestWifiPeerSchema, LocateRequestIBeaconPeerSchema
|
||||
|
||||
positioning_api_router = APIRouter(tags=["positioning"])
|
||||
|
||||
|
||||
class LocateRequestSchema(BaseSchema):
|
||||
peers: list[LocateRequestPeerSchema] = APIField(
|
||||
title="list of visible/measured location beacons",
|
||||
wifi_peers: list[LocateRequestWifiPeerSchema] = APIField(
|
||||
title="list of visible/measured wifi location beacons",
|
||||
)
|
||||
ibeacon_peers: list[LocateRequestIBeaconPeerSchema] = APIField(
|
||||
title="list of visible/measured location iBeacons",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ from c3nav.mapdata.models import MapUpdate, Space
|
|||
from c3nav.mapdata.models.geometry.space import RangingBeacon
|
||||
from c3nav.mapdata.utils.locations import CustomLocation
|
||||
from c3nav.routing.router import Router
|
||||
from c3nav.routing.schemas import LocateRequestPeerSchema
|
||||
from c3nav.routing.schemas import LocateRequestWifiPeerSchema
|
||||
|
||||
try:
|
||||
from asgiref.local import Local as LocalContext
|
||||
|
@ -146,7 +146,7 @@ class Locator:
|
|||
cls.cached.data = cls.load_nocache(update)
|
||||
return cls.cached.data
|
||||
|
||||
def convert_raw_scan_data(self, raw_scan_data: list[LocateRequestPeerSchema]) -> ScanData:
|
||||
def convert_raw_scan_data(self, raw_scan_data: list[LocateRequestWifiPeerSchema]) -> ScanData:
|
||||
return self.convert_scan(raw_scan_data, create_peers=False)
|
||||
|
||||
def get_xyz(self, address: BSSID) -> tuple[int, int, int] | None:
|
||||
|
@ -160,7 +160,7 @@ class Locator:
|
|||
peer: peer.xyz for peer in self.peers[:len(self.xyz)]
|
||||
}
|
||||
|
||||
def locate(self, raw_scan_data: list[LocateRequestPeerSchema], permissions=None):
|
||||
def locate(self, raw_scan_data: list[LocateRequestWifiPeerSchema], permissions=None):
|
||||
scan_data = self.convert_raw_scan_data(raw_scan_data)
|
||||
if not scan_data:
|
||||
return None
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
from typing import Annotated, Union
|
||||
from uuid import UUID
|
||||
|
||||
from annotated_types import Lt
|
||||
from pydantic import Field as APIField
|
||||
from pydantic import NegativeInt, PositiveInt
|
||||
from pydantic.types import NonNegativeInt, PositiveFloat, NonNegativeFloat
|
||||
|
||||
from c3nav.api.schema import BaseSchema
|
||||
from c3nav.api.utils import NonEmptyStr
|
||||
|
@ -9,7 +12,7 @@ from c3nav.api.utils import NonEmptyStr
|
|||
BSSIDSchema = Annotated[str, APIField(pattern=r"^[a-z0-9]{2}(:[a-z0-9]{2}){5}$", title="BSSID")]
|
||||
|
||||
|
||||
class LocateRequestPeerSchema(BaseSchema):
|
||||
class LocateRequestWifiPeerSchema(BaseSchema):
|
||||
bssid: BSSIDSchema = APIField(
|
||||
title="BSSID",
|
||||
description="BSSID of the peer",
|
||||
|
@ -61,3 +64,23 @@ class LocateRequestPeerSchema(BaseSchema):
|
|||
description="standard deviation of measurements in meters",
|
||||
example=1.23
|
||||
)
|
||||
|
||||
|
||||
class LocateRequestIBeaconPeerSchema(BaseSchema):
|
||||
uuid: UUID = APIField(
|
||||
title="UUID",
|
||||
description="UUID of the iBeacon",
|
||||
example="a142621a-2f42-09b3-245b-e1ac6356e9b0",
|
||||
)
|
||||
major: Annotated[NonNegativeInt, Lt(2 ** 16)] = APIField(
|
||||
title="major value of the iBeacon",
|
||||
)
|
||||
minor: Annotated[NonNegativeInt, Lt(2 ** 16)] = APIField(
|
||||
title="minor value of the iBeacon",
|
||||
)
|
||||
distance: NonNegativeFloat = APIField(
|
||||
title="determined iBeacon distance",
|
||||
)
|
||||
last_seen_ago: NonNegativeInt = APIField(
|
||||
title="how many milliseconds ago this beacon was last seen"
|
||||
)
|
||||
|
|
|
@ -258,6 +258,7 @@ c3nav = {
|
|||
|
||||
if (window.mobileclient) {
|
||||
c3nav.startWifiScanning();
|
||||
c3nav.startBLEScanning();
|
||||
}
|
||||
|
||||
c3nav.init_completed = true;
|
||||
|
@ -1830,19 +1831,19 @@ c3nav = {
|
|||
}
|
||||
},
|
||||
|
||||
_no_wifi_count: 0,
|
||||
startBLEScanning: function() {
|
||||
if (mobileclient.registerBeaconUuid) {
|
||||
mobileclient.registerBeaconUuid("a142621a-2f42-09b3-245b-e1ac6356e9b0");
|
||||
}
|
||||
},
|
||||
|
||||
_last_scan: 0,
|
||||
_last_wifi_peers: [],
|
||||
_last_ibeacon_peers: [],
|
||||
_no_scan_count: 0,
|
||||
_wifi_scan_results: function(peers) {
|
||||
peers = JSON.parse(peers);
|
||||
|
||||
if (peers.length) {
|
||||
c3nav._hasLocationPermission = true;
|
||||
} else {
|
||||
c3nav.hasLocationPermission(true);
|
||||
}
|
||||
|
||||
var now = Date.now();
|
||||
if (now-4000 < c3nav._last_wifi_scan) return;
|
||||
|
||||
if (c3nav.ssids) {
|
||||
peers = peers.filter(peer => c3nav.ssids.includes(peer.ssid));
|
||||
}
|
||||
|
@ -1857,28 +1858,53 @@ c3nav = {
|
|||
delete peer.rtt;
|
||||
}
|
||||
}
|
||||
c3nav._last_wifi_peers = peers;
|
||||
c3nav._after_scan_results();
|
||||
},
|
||||
_ibeacon_scan_results: function(peers) {
|
||||
peers = JSON.parse(peers);
|
||||
c3nav._last_ibeacon_peers = peers;
|
||||
c3nav._after_scan_results();
|
||||
},
|
||||
_after_scan_results: function() {
|
||||
has_peers = c3nav._last_wifi_peers.length || c3nav._last_ibeacon_peers.length;
|
||||
if (has_peers) {
|
||||
c3nav._hasLocationPermission = true;
|
||||
} else {
|
||||
c3nav.hasLocationPermission(true);
|
||||
}
|
||||
|
||||
var now = Date.now();
|
||||
if (now-4000 < c3nav._last_scan) return;
|
||||
|
||||
if (!peers.length) {
|
||||
if (!has_peers) {
|
||||
if (!c3nav._hasLocationPermission) {
|
||||
c3nav._set_user_location(null);
|
||||
} else {
|
||||
if (c3nav._no_wifi_count > 5) {
|
||||
c3nav._no_wifi_count = 0;
|
||||
if (c3nav._no_scan_count > 5) {
|
||||
c3nav._no_scan_count = 0;
|
||||
c3nav._set_user_location(null);
|
||||
} else {
|
||||
c3nav._no_wifi_count++;
|
||||
c3nav._no_scan_count++;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
c3nav._no_wifi_count = 0;
|
||||
c3nav._no_scan_count = 0;
|
||||
|
||||
c3nav_api.post('positioning/locate/', {peers})
|
||||
let ibeacon_peers = c3nav._last_ibeacon_peers.map(p => ({...p}));
|
||||
for (let peer of ibeacon_peers) {
|
||||
peer.last_seen_ago = Math.max(0, now - peer.last_seen);
|
||||
}
|
||||
|
||||
c3nav_api.post('positioning/locate/', {
|
||||
wifi_peers: c3nav._last_wifi_peers,
|
||||
ibeacon_peers: ibeacon_peers,
|
||||
})
|
||||
.then(data => c3nav._set_user_location(data.location))
|
||||
.catch(() => {
|
||||
c3nav._set_user_location(null);
|
||||
c3nav._last_wifi_scan = Date.now() + 20000
|
||||
c3nav._last_scan = Date.now() + 20000
|
||||
});
|
||||
},
|
||||
_current_user_location: null,
|
||||
|
@ -2027,6 +2053,10 @@ function nearby_stations_available() {
|
|||
c3nav._wifi_scan_results(mobileclient.getNearbyStations());
|
||||
}
|
||||
|
||||
function ibeacon_results_available() {
|
||||
c3nav._ibeacon_scan_results(mobileclient.getNearbyBeacons());
|
||||
}
|
||||
|
||||
function openInModal(location) {
|
||||
c3nav.open_modal();
|
||||
$.get(location, c3nav._modal_loaded).fail(c3nav._modal_error);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue