⚡ 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 AWUS036ACS (RTL8811AU) or Panda AC600 (MT7610U). Both are dual-band — see the table below, and note that 2.4 GHz-only adapters cannot see a large share of drones. |
| Second WiFi adapter (recommended) | A second dual-band adapter lets the node sweep 5 GHz about seven times faster. See Two adapters below. |
| 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 a USB WiFi adapter? It has to support monitor mode, which is required to capture Wi-Fi Remote ID beacon frames. The Pi's built-in WiFi cannot be put into monitor mode reliably, and is used for your network connection instead.
Two things matter: whether it does 5 GHz at all, and how fast it changes channel. The node sweeps a lot of channels, so a slow adapter spends much of its time deaf while retuning. These figures are measured on our own bench, same test and same code path:
| Adapter | Chipset | Channel change | Notes |
|---|---|---|---|
| Alfa AWUS036ACS | RTL8811AU | 22 ms | Fastest we've measured. The best choice for the 5 GHz sweep. |
| Panda AC600 | MT7610U | 111 ms | Inexpensive and works well. |
| Alfa AWUS036ACM | MT7612U | 1007 ms | Dual-band, but 45x slower to change channel than the ACS. Usable, noticeably worse. |
| Alfa AWUS036N | RT3070 | — | 2.4 GHz only. Cannot see any drone broadcasting on 5 GHz. |
The ACS reports as Realtek 8812AU/8821AU in lsusb and loads the
rtw88_8821au driver. That is not a different adapter — the USB ID and the
driver are shared across Realtek's 88xx family. Alfa have confirmed the silicon
is the RTL8811AU.
The spread between adapters is larger than anything you can fix in software. In a side-by-side test, identical code on the ACM captured 51% of a drone's broadcasts where the MT7610U captured 72%. Nothing in the marketing or the chipset name tells you this.
If you already own an AWUS036N it still works, and it will still see most DJI aircraft. It simply cannot see the 5 GHz ones.
The node supports a pair, and it is a substantial upgrade. One adapter works 2.4 GHz while the other sweeps 5 GHz, so neither has to cover for the other:
| Setup | Time to sweep the whole 5 GHz band |
|---|---|
| Two adapters | ~21 seconds |
| One adapter | ~2.5 minutes |
A short overflight can easily finish inside 2.5 minutes, so a single-adapter
node will miss aircraft that a pair catches. Both are supported and the
installer configures whichever it finds — plug in a second dual-band adapter
and run sudo droneaware refresh.
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 USB adapter into monitor mode and sweeps both bands 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 the channel, MAC address and
RSSI.
A compliant aircraft broadcasts on channel 6 or 149 regardless of which channel its video link uses, so those get the longest visits. It is only allowed to broadcast elsewhere if it raises its rate to at least five times a second — which means the rest of the band is cheap to cover, because a brief visit to a fast channel still yields several chances to hear something. The sweep covers 2.4 GHz plus 21 channels across 5 GHz, including the radar-detection channels between 52 and 144 where non-DJI aircraft turn out to spend much of their time.
When the node hears a drone it stops sweeping and holds that channel for as long as the aircraft keeps transmitting.
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.
The Bluetooth radio has to listen to every nearby advertisement in order to find
the Remote ID ones — that is how Bluetooth scanning works, and it is what your
phone does constantly. Anything that is not Remote ID is discarded immediately:
no address, no device name, and no content is read, stored, logged or
transmitted. The node keeps a running count of advertisements, and nothing
else about them, purely so it can tell "my Bluetooth radio is working and the
sky is quiet" apart from "my Bluetooth radio has stopped working". That count
never leaves your node — sudo droneaware status shows it to you, and the
server is told only whether the radio is alive. 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
Use the droneaware command rather than driving the services directly — it
knows how your node is put together, so the same command works whether you
have one WiFi adapter or two.
# How is my node doing? Services, firmware, and which radio is on
# which channel right now
sudo droneaware status
# Watch detections as they arrive (add "ble" for the Bluetooth feeder)
sudo droneaware logs
sudo droneaware logs ble
# Upgrade to the latest release
sudo droneaware update
# After changing hardware — added an adapter, swapped a USB port, new GPS
sudo droneaware refresh
# Two adapters? Exchange which one works 2.4 GHz and which sweeps 5 GHz
sudo droneaware swap
sudo droneaware swap --auto # hand the choice back to the node
# Transmit a sanctioned 60-second test flight and confirm your node sees it
sudo droneaware test
# Read-only GPS health check
sudo droneaware gps-diagnosestatus answers the question people ask most — which adapter is doing what,
and where it is tuned at this moment:
Radios:
wlan0 brcmfmac managed ch40 network uplink
wlan1 rt2800usb monitor ch6 2.4 GHz feeder
wlan2 mt76x2u monitor ch124 5 GHz feeder
Run it twice a few seconds apart and you will see the 5 GHz radio move — that
is the sweep working. An adapter listed as unused is plugged in but not
assigned to anything.
swap exists because the node's own choice, while consistent, is arbitrary
from your point of view — it orders adapters by MAC address, which says
nothing about which radio is the better sweeper. The sweeping adapter changes
channel around 21 times a cycle, so putting the faster one there is worth real
detection performance. It refuses to move a 2.4 GHz-only adapter onto the
5 GHz role, and the choice survives updates and reboots until you release it
or the hardware changes.
refresh is the one people miss. The node works out which adapter serves
which band at install time, so if you add or move hardware afterwards, run it
to bring the configuration back in line — otherwise a newly added adapter sits
unused.
Changing settings — location, server URL, scan tuning:
sudo nano /opt/droneaware/config.env
sudo droneaware refreshDriving the services directly
Rarely needed, but the unit names depend on how many WiFi adapters you have:
# Bluetooth feeder — same on every node
sudo systemctl status droneaware-ble
# WiFi, one adapter
sudo systemctl status droneaware-wifi
# WiFi, two adapters — the single-adapter unit is not used
sudo systemctl status droneaware-wifi-2g
sudo systemctl status droneaware-wifi-5gsudo droneaware status reports the right ones without you having to know
which mode the node is in.
Every 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 a monitor-mode capable adapter before running the installer, then run it again. See Which WiFi adapter above.
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 droneaware logsCommon causes:
- USB WiFi adapter not plugged in or not detected (
ip link show) - Adapter does not support monitor mode (see Which WiFi adapter above)
- 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 unit (single-adapter nodes) |
/etc/systemd/system/droneaware-wifi-2g.service…-5g.service |
WiFi feeder units (two-adapter nodes) |
/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.


