2024-12-28 15:57:16 +01:00
|
|
|
from typing import Literal
|
2024-12-28 14:59:09 +01:00
|
|
|
|
|
|
|
import requests
|
|
|
|
from django.conf import settings
|
|
|
|
from django.core.management.base import BaseCommand
|
|
|
|
from pydantic import BaseModel
|
2024-12-28 15:57:16 +01:00
|
|
|
from pydantic.type_adapter import TypeAdapter
|
|
|
|
from pydantic_extra_types.mac_address import MacAddress
|
2024-12-28 14:59:09 +01:00
|
|
|
from shapely import distance
|
2024-12-28 15:57:16 +01:00
|
|
|
from shapely.geometry import shape, Point
|
2024-12-28 14:59:09 +01:00
|
|
|
|
2024-12-28 15:57:16 +01:00
|
|
|
from c3nav.api.schema import PointSchema
|
|
|
|
from c3nav.mapdata.models import MapUpdate, Level
|
2024-12-28 14:59:09 +01:00
|
|
|
from c3nav.mapdata.models.geometry.space import RangingBeacon
|
|
|
|
from c3nav.mapdata.utils.cache.changes import changed_geometries
|
|
|
|
from c3nav.mapdata.utils.geometry import unwrap_geom
|
2024-12-28 15:57:16 +01:00
|
|
|
from c3nav.mapdata.utils.importer import PointImportHelper
|
2024-12-28 14:59:09 +01:00
|
|
|
|
|
|
|
|
2024-12-28 15:57:16 +01:00
|
|
|
class PocImportItemProperties(BaseModel):
|
|
|
|
level: str
|
|
|
|
mac: MacAddress
|
|
|
|
name: str
|
|
|
|
|
|
|
|
|
|
|
|
class PocImportItem(BaseModel):
|
2024-12-28 14:59:09 +01:00
|
|
|
"""
|
|
|
|
Something imported from the NOC
|
|
|
|
"""
|
2024-12-28 16:06:03 +01:00
|
|
|
type: Literal["Feature"] = "Feature"
|
2024-12-28 15:57:16 +01:00
|
|
|
geometry: PointSchema
|
|
|
|
properties: PocImportItemProperties
|
2024-12-28 14:59:09 +01:00
|
|
|
|
|
|
|
|
|
|
|
class Command(BaseCommand):
|
|
|
|
help = 'import APs from noc'
|
|
|
|
|
|
|
|
def handle(self, *args, **options):
|
2024-12-28 16:06:03 +01:00
|
|
|
r = requests.get(settings.POC_API_BASE+"/antenna-locations", headers={'ApiKey': settings.POC_API_SECRET})
|
2024-12-28 14:59:09 +01:00
|
|
|
r.raise_for_status()
|
2024-12-28 15:57:16 +01:00
|
|
|
items = TypeAdapter(list[PocImportItem]).validate_python(r.json())
|
2024-12-28 14:59:09 +01:00
|
|
|
|
|
|
|
with MapUpdate.lock():
|
|
|
|
changed_geometries.reset()
|
|
|
|
self.do_import(items)
|
|
|
|
MapUpdate.objects.create(type='importnoc')
|
|
|
|
|
2024-12-28 15:57:16 +01:00
|
|
|
def do_import(self, items: list[PocImportItem]):
|
|
|
|
import_helper = PointImportHelper()
|
2024-12-28 14:59:09 +01:00
|
|
|
|
|
|
|
beacons_so_far: dict[str, RangingBeacon] = {
|
2024-12-28 15:57:16 +01:00
|
|
|
**{m.import_tag: m for m in RangingBeacon.objects.filter(import_tag__startswith="poc:",
|
|
|
|
beacon_type=RangingBeacon.BeaconType.DECT)},
|
2024-12-28 14:59:09 +01:00
|
|
|
}
|
|
|
|
|
2024-12-28 15:57:16 +01:00
|
|
|
levels_by_level_index = {str(level.level_index): level for level in Level.objects.all()}
|
2024-12-28 14:59:09 +01:00
|
|
|
|
2024-12-28 15:57:16 +01:00
|
|
|
for item in items:
|
|
|
|
import_tag = f"poc:{item.properties.name}"
|
2024-12-28 14:59:09 +01:00
|
|
|
|
|
|
|
# determine geometry
|
2024-12-28 16:06:03 +01:00
|
|
|
level_id = levels_by_level_index[item.properties.level].pk
|
2024-12-28 14:59:09 +01:00
|
|
|
|
2024-12-28 15:57:16 +01:00
|
|
|
point: Point = shape(item.geometry.model_dump()) # nowa
|
2024-12-28 14:59:09 +01:00
|
|
|
|
2024-12-28 15:57:16 +01:00
|
|
|
new_space, point = import_helper.get_point_and_space(
|
|
|
|
level_id=level_id,
|
|
|
|
point=point,
|
|
|
|
name=item.properties.name,
|
|
|
|
)
|
|
|
|
|
|
|
|
if new_space is None:
|
|
|
|
continue
|
2024-12-28 14:59:09 +01:00
|
|
|
|
|
|
|
# find existing location
|
|
|
|
result = beacons_so_far.pop(import_tag, None)
|
|
|
|
|
|
|
|
# build resulting object
|
|
|
|
altitude_quest = True
|
|
|
|
if not result:
|
2024-12-28 17:58:28 +01:00
|
|
|
result = RangingBeacon(import_tag=import_tag, beacon_type=RangingBeacon.BeaconType.DECT)
|
2024-12-28 14:59:09 +01:00
|
|
|
else:
|
2024-12-28 15:57:16 +01:00
|
|
|
if result.space == new_space and distance(unwrap_geom(result.geometry), point) < 0.03:
|
2024-12-28 14:59:09 +01:00
|
|
|
continue
|
2024-12-28 15:57:16 +01:00
|
|
|
if result.space == new_space and distance(unwrap_geom(result.geometry), point) < 0.20:
|
2024-12-28 14:59:09 +01:00
|
|
|
altitude_quest = False
|
|
|
|
|
2024-12-28 15:57:16 +01:00
|
|
|
result.ap_name = item.properties.name
|
|
|
|
result.addresses = [item.properties.mac.lower()]
|
2024-12-28 14:59:09 +01:00
|
|
|
result.space = new_space
|
2024-12-28 15:57:16 +01:00
|
|
|
result.geometry = point
|
2024-12-28 14:59:09 +01:00
|
|
|
result.altitude = 0
|
|
|
|
if altitude_quest:
|
|
|
|
result.altitude_quest = True
|
|
|
|
result.save()
|
|
|
|
|
|
|
|
for import_tag, location in beacons_so_far.items():
|
|
|
|
location.delete()
|
|
|
|
print(f"NOTE: {import_tag} was deleted")
|