π 1st Place Winner - EDTH Switzerland 2025
Built in 43 hours by Alexander MarinΕ‘ek, UroΕ‘ Hudomalj, Marko Hudomalj & Paul Brittain.
A distributed system for triangulating RF signal sources using multiple sensors and edge computing hubs.
This project was built from scratch over a weekend for EDTH Switzerland 2025. It demonstrates core RF triangulation functionality but is not production-ready. Significant work would be required for deployment in real-world environments.
What's Implemented:
- Core RF triangulation algorithm using RSSI measurements
- Database connection pooling with pgxpool
- Basic REST API with versioning (v1)
- MQTT ingestion with batch processing
- Graceful shutdown handling
- Basic middleware (logging, recovery, timeouts, CORS)
- Health check endpoints
- Local and GPS coordinate transformations
What's NOT Implemented:
- No authentication, authorization, or TLS
- No production observability (metrics, structured logging, tracing)
- No database migrations or automated schema management
- No tests (unit, integration, or load testing)
- Single hub only (no hub-to-hub mesh networking)
- Simplified RF model (no multipath or signal quality filtering)
- Environment variables only (no secrets management)
- CORS allows all origins
An edge device that:
- Manages a set of sensors (e.g., drones with RF receivers)
- Receives sensor data via MQTT
- Performs local triangulation
- Exposes a REST API for control and data access
A single mission where sensors are launched from a specific origin point:
- Origin is fixed at deploy time (reference point for all positions)
- Hub can relocate while sensors are deployed
- Sensors can be recalled and redeployed from a new location
# Start TimescaleDB + PostGIS, MQTT broker, and Adminer
make docker-up
# Verify services
docker compose ps# Install dependencies and build
make deps
make build
# Run a single hub
make run
# Or with custom settings
HUB_ID=hub-01 PATHLOSS_N=3.5 make run# Update hub position (co-located with sensor 1)
curl -X PUT http://localhost:8080/api/v1/hub/position \
-H "Content-Type: application/json" \
-d '{"lat": 47.487194, "lon": 8.706972}'
# Deploy sensors
curl -X POST http://localhost:8080/api/v1/hub/deploy \
-H "Content-Type: application/json" \
-d '{
"notes": "Outdoor hackathon parking lot demo"
}'Note: Sensor positions are configured via environment variable or sensors.json file (see Configuration section below).
# Install mosquitto-clients if needed
# Ubuntu: apt install mosquitto-clients
# Mac: brew install mosquitto
chmod +x scripts/simulate_sensors.sh
./scripts/simulate_sensors.sh hub-01# Get hub status
curl http://localhost:8080/api/v1/hub
# Get sensor positions
curl http://localhost:8080/api/v1/hub/sensors
# Get triangulated positions
curl http://localhost:8080/api/v1/deployments/active/positions/latest
# Recall sensors
curl -X POST http://localhost:8080/api/v1/hub/recall
## API Reference
### Hub Management
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/hub` | Get hub status |
| PUT | `/api/v1/hub/position` | Update hub position |
| POST | `/api/v1/hub/deploy` | Create new deployment |
| POST | `/api/v1/hub/recall` | End current deployment |
| GET | `/api/v1/hub/sensors` | Get sensor positions |
### Deployment Data
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/deployments/active` | Get active deployment |
| GET | `/api/v1/deployments/active/positions` | Get triangulated positions |
| GET | `/api/v1/deployments/active/positions/latest` | Get latest position per MAC |
| GET | `/api/v1/deployments/active/detections` | Get raw detections |
## Debugging
### With Delve
Run the hub with Delve debugger in headless mode:
```bash
# Start the hub with debugger listening on port 2345
make debug
# Or for hub-01 with specific settings
make debug-hub-1Create .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Hub",
"type": "go",
"request": "attach",
"mode": "remote",
"remotePath": "${workspaceFolder}",
"port": 2345,
"host": "localhost",
"showLog": true
}
]
}Usage:
- Start the debugger:
make debug-hub-1 - In VSCode, press F5 or Run > Start Debugging
- Select "Attach to Hub"
- Set breakpoints and debug!
Note: Install Delve if not already installed:
go install github.com/go-delve/delve/cmd/dlv@latest| Variable | Default | Description |
|---|---|---|
HUB_ID |
hub-01 |
Unique hub identifier |
HUB_NAME |
Hub 01 |
Human-readable name |
DATABASE_URL |
postgresql://... |
PostgreSQL connection string |
MQTT_BROKER |
tcp://localhost:1883 |
MQTT broker address |
API_LISTEN_ADDR |
:8080 |
API server listen address |
PATHLOSS_N |
3.0 |
Path loss exponent (2.5 outdoor, 3.0-4.0 indoor) |
TX_POWER |
-40.0 |
Expected RSSI at 1 meter |
SENSOR_POSITIONS |
JSON array of sensor positions (see below) |
Sensor positions can be configured in three ways (priority order):
1. Environment Variable (Highest Priority)
export SENSOR_POSITIONS='[{"sensor_index":1,"local_x":0,"local_y":0,"lat":47.487194,"lon":8.706972},{"sensor_index":2,"local_x":33.5,"local_y":3.09,"lat":47.487222,"lon":8.707472},{"sensor_index":3,"local_x":2.09,"local_y":18.53,"lat":47.487361,"lon":8.706999}]'2. Configuration File
Create sensors.json in the working directory:
[
{
"sensor_index": 1,
"local_x": 0,
"local_y": 0,
"lat": 47.487194,
"lon": 8.706972
},
{
"sensor_index": 2,
"local_x": 33.5,
"local_y": 3.09,
"lat": 47.487222,
"lon": 8.707472
},
{
"sensor_index": 3,
"local_x": 2.09,
"local_y": 18.53,
"lat": 47.487361,
"lon": 8.706999
}
]3. Default Fallback If neither is provided, uses hardcoded default positions.
See sensors.json.example for a template.
rftrack/
βββ cmd/
β βββ hub/ # Main hub application
βββ pkg/
β βββ models/ # Domain models
β βββ coords/ # Coordinate transforms, triangulation, fusion
β βββ database/ # Repository layer
β βββ hub/ # Hub service (business logic)
βββ scripts/
β βββ simulate_sensors.sh
βββ docker-compose.yml # Infrastructure (DB, MQTT)
βββ init.sql # Database schema
βββ Makefile
βββ go.work # Go workspace
For hackathon demos in an indoor hall:
- Measure the room dimensions and sensor positions
- Configure sensor positions in
sensors.jsonwith actual GPS coordinates - Tune RF parameters for indoor environment:
# Higher path loss for indoor multipath
PATHLOSS_N=3.5 TX_POWER=-35 make runΒ© 2025 Paul Brittain