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:
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
Backend
Frontend
Description
Currently all ESP32 sensors are provisioned with
latitude=0.0,longitude=0.0and 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 viaST_Containscannot 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:
Proposed Solution
Layer 1 — IoT Firmware
During the provisioning handshake (
POST /devices/register), the ESP32 performs a WiFi scan usingWiFi.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
Task List
IoT
WiFi.scanNetworks()call to the provisioning sequence in main.cppPOST /devices/register JSONpayloadDeviceRegisterRequestPydantic schema to accept optionalwifi_scanarrayBackend
wifi_scanoptional field toDeviceRegisterRequestschema in schemas.pyregister_device endpointneeds_location_reviewboolean column toMisuratormodelST_Containszone assignment query ordered by polygon area ascending (most specific zone first)/misurators/{id}endpoint for manual coordinate and zone overrideFrontend
/misurators/{id}on save and invalidate TanStack Query cache for sensor list