⚡ Get a node online in ~10–15 minutes → Start Here
Detections from nodes already running on the network:
See drones flying near you in real time - most people never see Remote ID unless they build something like this.
Nodes are already running in the US, Germany, and Canada - and growing daily.
DroneAware Network is a community-built, open Remote ID detection network. The goal is to create a distributed, real-time view of drone activity with low-cost sensors - where the value isn't just the software, but the shared detection network everyone contributes to.
Run one command and start detecting drones around you, from a few hundred yards to miles away depending on your setup::
curl -fsSL https://github.com/fduflyer/DroneAware-Node-Releases/releases/latest/download/install.sh | sudo bashNo Linux experience needed — if you can plug in a USB device, you can run this.
Your new DroneAware node will listen for FAA-mandated Remote ID broadcasts from drones flying in your area and forward them to the DroneAware Network, where they appear on a live map at droneaware.io.
Once connected, you'll also get real-time email alerts anytime your node(s) detect a drone. You can also go back and view all of your detections by date and time to watch a replay of their flight paths.
| Item | Notes |
|---|---|
| Raspberry Pi 4 (1 GB or more) | 2 GB+ recommended if running other software |
| MicroSD card (16 GB+, Class 10) | Samsung Endurance or SanDisk High Endurance preferred |
| USB Bluetooth adapter | Sena UD100 (newer variants with Bluetooth 4.0+ only) or any CSR/Cambridge Silicon Radio USB dongle. Older UD100 variants (G01, G02, G03 and similar) are Bluetooth Classic (BT 2.0/2.1) only and will not work. If unsure which version you have, the Pi's built-in Bluetooth works out of the box at shorter range. |
| WiFi adapter (required) | Alfa AWUS036N (Ralink RT3070 chipset, 2.4 GHz) |
| 5V/3A USB-C power supply | Official Raspberry Pi PSU recommended |
| Ethernet cable or WiFi credentials | For initial setup |
Why a USB Bluetooth adapter? The Pi's built-in Bluetooth works, but its antenna is inside the case. A USB dongle with an external antenna has significantly better range. The Sena UD100 / CSR chipset is confirmed working and widely available for under $20.
Why the Alfa WiFi adapter? The Alfa AWUS036N supports monitor mode, which is required to capture Wi-Fi Remote ID beacon frames (the 802.11 transport used by many newer drones). The Pi's built-in WiFi cannot be put into monitor mode reliably.
DroneAware nodes run two background services that continuously scan for drone Remote ID broadcasts:
BLE Feeder (droneaware-ble)
Listens for Bluetooth Low Energy advertisements carrying Remote ID service data
(UUID 0xFFFA, ASTM F3411). When a drone broadcast is detected, the raw 25-byte
ODID message is decoded locally (drone ID, position, speed, operator location)
and forwarded to the DroneAware server in batches.
WiFi Feeder (droneaware-wifi)
Places the Alfa adapter into monitor mode and hops across 2.4 GHz channels
(1–11) looking for 802.11 beacon frames carrying vendor-specific Remote ID
payloads (OUI FA:0B:BC, ASTM F3411) and Wi-Fi NAN action frames (OUI 50:6F:9A).
Detected payloads are forwarded to the server alongside MAC address and RSSI.
Data Flow
Drone (Remote ID broadcast)
→ Pi USB BT/WiFi adapter (raw capture)
→ ble_feeder / wifi_feeder (batch over HTTPS)
→ api.droneaware.io (decode + store)
→ droneaware.io (live map)
Both services start automatically at boot, restart on crash, and send a
heartbeat to the server every 60 seconds so the dashboard shows the node as
online. Detections are forwarded to the DroneAware server in real time and also
written to a local ring buffer (/run/droneaware/detections.jsonl) stored in
RAM — the last 60 minutes of detections are kept on the Pi and purged
automatically. Nothing is written to the SD card.
What data is collected? Only data broadcast publicly by the drones themselves via FAA-mandated Remote ID transmissions. Remote ID is an open broadcast equivalent to a drone's tail number visible on a radar screen. No private communications, networks, or personal devices are accessed. Your node's GPS coordinates are stored on the DroneAware server to correctly place detections on the map.
- Download Raspberry Pi Imager on your computer.
- Click Choose OS → Raspberry Pi OS (other) → Raspberry Pi OS Lite (64-bit).
- Click the gear icon (Advanced Options) and configure:
- Set hostname: e.g.
droneaware-node - Enable SSH and set a username/password
- Optional but recommended: enter your WiFi credentials here to avoid needing an Ethernet cable
- Set hostname: e.g.
- Select your SD card and click Write.
- Insert the SD card, plug in your USB Bluetooth adapter, connect power.
- Wait 60–90 seconds for the Pi to boot.
- SSH into the Pi:
Then switch to root:
ssh <your-username>@<pi-ip-address>
sudo -i
Finding your Pi's IP address: check your router's device list, or if you set a hostname try
ssh droneaware-node.local.
Run this single command:
curl -fsSL https://github.com/fduflyer/DroneAware-Node-Releases/releases/latest/download/install.sh | sudo bashThe installer will:
-
Display the DroneAware Feeder Node Contributor Agreement — you must type
yesto accept before installation proceeds. By accepting, you agree to the terms governing data ownership and network participation. See LICENSE for full terms. -
Prompt for a node nickname — a short name to identify this sensor on the DroneAware network (e.g.
my-garage,rooftop-east). -
Auto-detect your USB WiFi adapter — the installer finds the external adapter automatically. If none is found, it will exit with instructions.
-
Install system packages and download binaries from the latest release.
-
Enroll the node — you will be prompted to open droneaware.io/nodes, log in, click Add Node, and paste the enrollment token shown. The node is immediately active on your account — no separate claim step required.
At the end of installation the installer displays:
╔══════════════════════════════════════════════════════════════════════╗
║ Installation Complete! ║
║ Node ID : my-garage ║
╠══════════════════════════════════════════════════════════════════════╣
║ Your node is enrolled and active on the DroneAware network. ║
║ View it at: https://droneaware.io/nodes ║
╚══════════════════════════════════════════════════════════════════════╝
Log into droneaware.io/nodes to see your node on the live map and access:
- Detection history and alerts
- Remote node management
- Network contribution statistics
# Check service status
sudo systemctl status droneaware-ble
sudo systemctl status droneaware-wifi
# Watch live detection logs
sudo journalctl -u droneaware-ble -f
sudo journalctl -u droneaware-wifi -f
# Edit node config (location, server URL, etc.)
sudo nano /opt/droneaware/config.env
sudo systemctl restart droneaware-ble droneaware-wifi
# Start feeders manually (they start automatically on next reboot)
sudo systemctl start droneaware-ble droneaware-wifi
# To upgrade an existing node
sudo droneaware updateEvery detection is also broadcast as a JSON line over UDP to
255.255.255.255:9999 on your local network. Any device on the same LAN can
consume detections in real time without any data leaving your network.
Listen from any machine on your LAN:
nc -luk 9999Or in Python:
import socket, json
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', 9999))
while True:
print(json.loads(s.recv(4096)))Each record looks like:
{"t":1745000000.0,"mac":"fa:0b:bc:12:34:56","radio":"wifi_beacon","rssi":-68,"type":"Location/Vector","lat":40.7128,"lon":-74.0060,"alt":120.5,"speed":8.25,"hdg":270.0,"id":null}The same detections are also saved to /run/droneaware/detections.jsonl on the
Pi — a rolling 60-minute window stored entirely in RAM (no SD card writes,
cleared on reboot). You can tail it directly:
tail -f /run/droneaware/detections.jsonlLocal Web UI (v1.4.0+) — works offline (v1.4.5+):
If you installed the optional Web UI (sudo droneaware install-webui),
point any LAN device at http://<pi-ip>:5000/ for a live detection map.
The Web UI runs entirely on the Pi — no internet connectivity to
droneaware.io required.
From v1.4.5+, the Web UI also bundles a world-overview basemap inside the binary, so the map renders cleanly even when the browser can't reach CartoDB. Online operators get full street-level detail from CartoDB; offline operators get a recognizable country / state context with drone markers correctly positioned. The fallback is automatic — Leaflet detects failed tile loads and switches sources without a refresh.
HTTP API (v1.4.0+): The Web UI service exposes a small read-only JSON / SSE API on the same port (5000) — often easier to consume than UDP for Home Assistant, Node-RED, Homebridge, or any HTTP-aware automation tool. Unlike UDP, you also get a full snapshot of recent state on connect.
Endpoints (all GET, no auth, LAN-accessible):
| Endpoint | Returns |
|---|---|
/api/detections |
JSON snapshot of all currently tracked drones |
/api/status |
Node telemetry (version, uptime, load, home location, buffer stats) |
/events |
Server-Sent Events stream — real-time push of each new detection |
Top-level object:
| Field | Type | Notes |
|---|---|---|
macs |
array | One entry per tracked drone (see below) |
total_events |
int | Raw events held across all drones |
mac_count |
int | Number of currently tracked drones |
buffer_bytes |
int | Ring buffer bytes in use |
buffer_max |
int | Configured max bytes |
buffer_pct |
int | 0–100 |
snapshot_at |
float | Unix seconds at snapshot build time |
Each macs[] entry:
| Field | Type | Notes |
|---|---|---|
mac |
string | MAC address, e.g. "fa:0b:bc:12:34:56" |
latest |
object | Merged ASTM fields (table below) |
first_seen |
float | Unix seconds — first event for this drone |
last_seen |
float | Unix seconds — most recent event |
age_sec |
float | Seconds since last_seen |
event_count |
int | Raw events held for this drone |
trail |
array of [lat, lon] |
Last 60 unique positions, chronological |
The latest object — any field may be null until the relevant ASTM
message type is received:
| Field | Type | Range / units | Source |
|---|---|---|---|
t |
float | Unix seconds | Broadcast time of most recent event |
id |
string | hex | UAS-ID — from Basic ID message |
lat |
float | [-90, 90] degrees, WGS84 | Location/Vector message |
lon |
float | [-180, 180] degrees, WGS84 | Location/Vector message |
alt |
float | meters, geodetic (WGS84) | Location/Vector message |
speed |
float | m/s, ground speed | Location/Vector message |
hdg |
float | [0, 360) degrees, compass | Location/Vector message |
rssi |
int | dBm (negative, e.g. -68) |
Capture-time signal strength |
radio |
string | "wifi_beacon", "wifi_nan", "ble" |
Capture transport |
type |
string | ASTM message type | e.g. "Basic ID", "Location/Vector", "System" |
operator_lat |
float | [-90, 90] degrees, WGS84 | System message |
operator_lon |
float | [-180, 180] degrees, WGS84 | System message |
| Field | Type | Notes |
|---|---|---|
version |
string | Node firmware version, e.g. "1.4.0" |
uptime_s |
int | Seconds since web_ui started |
cpu_temp_c |
float | null | Pi CPU temperature; null on non-Pi hardware |
load_1m / load_5m / load_15m |
float | null | Unix load averages |
sse_clients |
int | Active SSE subscribers |
home |
object | null | {"lat": float, "lon": float, "source": string} |
node_id |
string | NODE_ID from config.env |
mac_count |
int | Currently tracked drones |
event_count |
int | Total events in buffer |
buffer_bytes / buffer_max / buffer_pct |
int | Ring buffer stats |
Each message is a single decoded detection — the same wire format as a
UDP broadcast record (see UDP section above). Same field types as the
latest object table; aggregate fields (mac_count, event_count, etc.)
do not appear on individual events. SSE framing is:
data: {"t":1745000000.0,"mac":"fa:0b:bc:12:34:56","radio":"wifi_beacon","rssi":-68,"type":"Location/Vector","lat":40.7128,"lon":-74.0060,"alt":120.5,"speed":8.25,"hdg":270.0,"id":null}\n
\n
Keep-alive comment (: keep-alive) is emitted every 15 seconds of
silence to prevent proxies/browsers from timing out the connection.
Snapshot:
curl http://<pi-ip>:5000/api/detections | jq .Live stream in Python:
import requests, json
r = requests.get("http://<pi-ip>:5000/events", stream=True)
for line in r.iter_lines():
if line.startswith(b"data: "):
print(json.loads(line[6:]))Or simply tail it from the shell:
curl -N http://<pi-ip>:5000/eventsThe API is read-only — there are no POST/PUT endpoints, so it cannot
be used to inject detections or change node configuration. Bound to
0.0.0.0:5000 with no authentication; treat it like any other LAN
service.
Privacy note: Your node's precise GPS coordinates are never publicly visible. The DroneAware map displays only a 2-mile detection ring around your node — your exact location is kept private.
Not seeing any detections and want to confirm your node is working? Run the built-in test command:
sudo droneaware testThis transmits a 60-second sanctioned test flight from your WiFi adapter. Your node captures it, decodes it, and forwards it to the server — the same path a real drone detection takes. A test marker will appear on the Live map within 30 seconds — visible only to you when signed in to the account that owns the node.
Rate limits: 3-minute cooldown between tests, 5 per hour.
Check availability without transmitting:
sudo droneaware test --dry-runTest detections are tagged server-side and never appear on the public live map or anyone else's dashboard.
"USB WiFi adapter required" — installer exits immediately The installer requires a USB WiFi adapter to be present. Connect your Alfa AWUS036N (or compatible monitor-mode adapter) before running the installer, then run it again.
The BLE feeder starts but shows 0 detections This is normal — there may simply be no drones broadcasting Remote ID nearby. Remote ID is only required for drones registered after September 2023, and most recreational fliers are not yet compliant. Detection depends entirely on local drone activity.
WiFi feeder fails to start or keeps restarting
sudo journalctl -u droneaware-wifi -n 50Common causes:
- USB WiFi adapter not plugged in or not detected (
ip link show) - Adapter does not support monitor mode (must be Ralink RT3070 or compatible)
- Another process (NetworkManager) has taken control of the interface — the installer configures NM to ignore the adapter, but a reinstall of NM may revert this
BLE feeder fails to start or reports a BLE error on startup Your Bluetooth adapter may not support BLE. The Sena UD100 product line spans multiple generations — older variants (including the G01, G02, and G03) are Bluetooth Classic (BT 2.0/2.1) only and will not work for Remote ID, which requires BLE advertising. Newer UD100 variants with Bluetooth 4.0+ are BLE-capable and will work.
Confirm what you have by running:
hciconfig -a | grep "LMP Version"LMP Version: 2.0 or 2.1 = Bluetooth Classic only, won't work.
LMP Version: 4.0 or higher = BLE capable, should work.
If your adapter isn't BLE-capable, you can use the Pi's built-in Bluetooth instead — it supports BLE out of the box on all Pi 4 models, just with shorter range than an external dongle.
The BLE feeder keeps restarting
sudo journalctl -u droneaware-ble -n 50Common causes:
- USB Bluetooth adapter not detected — run
hciconfig -ato confirm the Pi sees it; unplug and replug the dongle if not - Adapter MAC in
config.envdoesn't match the installed adapter — updateBLE_ADAPTER_MACin/opt/droneaware/config.envand restart
"No internet connection" during install
- Ethernet: check the cable and that your router assigned an IP
(
ip addr show eth0) - WiFi: verify your credentials are correct, then reboot and try again
I need to change my node's location Log into droneaware.io/nodes, select your node, and update its location there. Node location is managed server-side.
| Path | Purpose |
|---|---|
/usr/local/bin/ble_feeder |
BLE Remote ID feeder binary |
/usr/local/bin/wifi_feeder |
WiFi Remote ID feeder binary |
/usr/local/bin/droneaware-bt-select |
Boot-time Bluetooth adapter selector |
/opt/droneaware/config.env |
Node configuration (ID, location, adapters) |
/etc/droneaware/token |
Node credential (written at enrollment) |
/etc/systemd/system/droneaware-ble.service |
BLE feeder systemd unit |
/etc/systemd/system/droneaware-wifi.service |
WiFi feeder systemd unit |
/etc/systemd/system/droneaware-bt-select.service |
BT selector systemd unit |
DroneAware Network is an open project and forks are welcome. If you're building on this or experimenting, we'd love to hear what you're working on — especially around detection accuracy, range improvements, or new visualization approaches.
The real power of this project is the shared detection network. If you're running nodes, consider feeding data into the main DroneAware Network so detections benefit everyone.
Join the community on Discord: discord.gg/J4ZHpdgzeb
Already a FlightAware or ADS-B feeder? See the upgrade guide →
Have an idea or improvement? Open an issue or start a discussion — we're actively building.
Every DroneAware Node binary is built in GitHub Actions and cryptographically signed via Sigstore. You can independently verify that any release binary was built from the published source code in a known, controlled environment — not on someone's laptop.
This matters because the Contributor Agreement commits the feeder software to a specific scope of data collection (Section 3.1). Attestation lets you confirm that the binary running on your node actually implements those guarantees.
To verify a binary you downloaded from a release:
gh attestation verify ble_feeder --owner fduflyer
gh attestation verify wifi_feeder --owner fduflyer
A successful verification confirms the binary was built by GitHub Actions from a specific source commit in this repository.
Requires the GitHub CLI and a free GitHub account:
macOS: brew install gh && gh auth login
Debian / Ubuntu / Pi OS: sudo apt install gh && gh auth login
- Website: droneaware.io
- GitHub: github.com/fduflyer/DroneAware-Node-Releases
Copyright (c) 2026 DroneAware, LLC. Use of this software is subject to the terms of the DroneAware Feeder Node Software License. See LICENSE for details.


