Skip to content

[FEATURE] Automatic GPS geolocation for sensor provisioning #270

Description

@GiZano

Description

Currently all ESP32 sensors are provisioned with latitude=0.0, longitude=0.0 and assigned to the "Unknown Region" fallback zone. This means the Event Map screen shows all sensors clustered at the Gulf of Guinea (0°N 0°E) and automatic PostGIS zone assignment via ST_Contains cannot function correctly. For a global sensor network to be meaningful, each device needs accurate geographic coordinates without requiring manual database intervention after every deployment.
This feature implements a hybrid geolocation strategy: automatic best-effort coordinate estimation via WiFi MAC fingerprinting at provisioning time, with a manual override path available through the mobile app for precision corrections.

Guidelines

Before submitting, please verify:

  • This feature does not duplicate an existing open issue
  • The feature spans Backend, IoT, and Frontend layers with clear justification for each
  • Acceptance criteria are defined in the Task list below

Proposed Solution

Layer 1 — IoT Firmware

During the provisioning handshake (POST /devices/register), the ESP32 performs a WiFi scan using WiFi.scanNetworks() and includes the discovered BSSIDs and signal strengths in the registration payload. This requires no user interaction and adds negligible overhead to the one-time provisioning flow.
Updated provisioning payload:

{
  "public_key_hex": "...",
  "mac_address": "AA:BB:CC:DD:EE:FF",
  "enrollment_token": "...",
  "wifi_scan": [
    {"bssid": "11:22:33:44:55:66", "rssi": -65},
    {"bssid": "AA:BB:CC:DD:EE:FF", "rssi": -72}
  ]
}

Layer 2 — Backend Geolocation

The POST /devices/register endpoint forwards the WiFi scan data to the Mozilla Location Services (MLS) API — free, no billing required, no API key needed for basic usage. MLS returns an estimated latitude, longitude, and accuracy radius in meters. The backend stores the coordinates and triggers the PostGIS ST_Contains zone assignment query.
If MLS returns an error or low-confidence result (accuracy > 5000m), the backend falls back to "Unknown Region" and flags the sensor as needs_location_review = True for manual correction via the mobile app.
MLS request format:

{
  "wifiAccessPoints": [
    {"macAddress": "11:22:33:44:55:66", "signalStrength": -65}
  ]
}

Layer 3 — Frontend Manual Override

Add a sensor detail screen (accessible by tapping a marker on the Event Map) allowing an administrator to manually pin a sensor to a specific location. The screen shows the current coordinates and an interactive map picker. On save, it calls a new PATCH /misurators/{id} endpoint to update the coordinates and re-run zone assignment.

Alternatives Considered

  • Mobile app passes GPS during WiFi captive portal: Rejected as primary solution — requires the user to be physically present at the sensor location during setup and adds captive portal UI complexity to the firmware. Kept as a future enhancement for precision-critical deployments.
  • Google Maps Geolocation API: Rejected — requires billing setup and introduces a paid external dependency to a safety-critical provisioning flow. Mozilla Location Services provides equivalent accuracy for zone-level geolocation at zero cost.
  • Hardcoded GPS coordinates in firmware config: Rejected — requires reflashing the device for every redeployment and does not scale to a global network.

Task List

IoT

  • Add WiFi.scanNetworks() call to the provisioning sequence in main.cpp
  • Serialize BSSID and RSSI array into the POST /devices/register JSON payload
  • Update DeviceRegisterRequest Pydantic schema to accept optional wifi_scan array

Backend

  • Add wifi_scan optional field to DeviceRegisterRequest schema in schemas.py
  • Implement async Mozilla Location Services call in register_device endpoint
  • Add needs_location_review boolean column to Misurator model
  • Implement PostGIS ST_Contains zone assignment query ordered by polygon area ascending (most specific zone first)
  • Add PATCH /misurators/{id} endpoint for manual coordinate and zone override
  • Fall back gracefully to "Unknown Region" if MLS returns low confidence or errors

Frontend

  • [ ]Add sensor detail screen accessible from Event Map marker tap
  • Display current coordinates, zone assignment, and needs_location_review flag
  • Implement interactive map coordinate picker for manual override
  • Call PATCH /misurators/{id} on save and invalidate TanStack Query cache for sensor list

Metadata

Metadata

Assignees

No one assigned

    Labels

    IoTImprovements, additions or fixes to IoT elementsarchitectureImprovements, additions or fixes to architecturebackendImprovements, additions or fixes to backend elementsenhancementNew feature or requestfrontendImprovements, additions or fixes to frontend elements

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions