Skip to content

Latest commit

 

History

144 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DroneAware Node — Setup Guide

⚡ Get a node online in ~10–15 minutes → Start Here

Detections from nodes already running on the network:

DroneAware_Screenshot1

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 bash

No 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.

DroneAware_Screenshot2

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.

DroneAware Screenshot2


What You Need

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.

Which WiFi adapter

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.

Two adapters

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.


How It Works

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.


Quick Start

Step 1 — Flash the SD Card

  1. Download Raspberry Pi Imager on your computer.
  2. Click Choose OS → Raspberry Pi OS (other) → Raspberry Pi OS Lite (64-bit).
  3. 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
  4. Select your SD card and click Write.

Step 2 — Boot the Pi

  1. Insert the SD card, plug in your USB Bluetooth adapter, connect power.
  2. Wait 60–90 seconds for the Pi to boot.
  3. SSH into the Pi:
    ssh <your-username>@<pi-ip-address>
    Then switch to root:
    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.

Step 3 — Run the Installer

Run this single command:

curl -fsSL https://github.com/fduflyer/DroneAware-Node-Releases/releases/latest/download/install.sh | sudo bash

The installer will:

  1. Display the DroneAware Feeder Node Contributor Agreement — you must type yes to accept before installation proceeds. By accepting, you agree to the terms governing data ownership and network participation. See LICENSE for full terms.

  2. Prompt for a node nickname — a short name to identify this sensor on the DroneAware network (e.g. my-garage, rooftop-east).

  3. Auto-detect your USB WiFi adapter — the installer finds the external adapter automatically. If none is found, it will exit with instructions.

  4. Install system packages and download binaries from the latest release.

  5. 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.

Step 4 — Confirm Your Node is Live

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

Useful Commands

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-diagnose

status 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 refresh
Driving 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-5g

sudo droneaware status reports the right ones without you having to know which mode the node is in.


Local / Offline Use

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 9999

Or 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.jsonl

Local 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

/api/detections response shape

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

/api/status response shape

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

/events SSE stream

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.


Examples

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/events

The 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.


Testing Your Node

Not seeing any detections and want to confirm your node is working? Run the built-in test command:

sudo droneaware test

This 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-run

Test detections are tagged server-side and never appear on the public live map or anyone else's dashboard.


Troubleshooting

"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 logs

Common 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 50

Common causes:

  • USB Bluetooth adapter not detected — run hciconfig -a to confirm the Pi sees it; unplug and replug the dongle if not
  • Adapter MAC in config.env doesn't match the installed adapter — update BLE_ADAPTER_MAC in /opt/droneaware/config.env and 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.


Node File Locations

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

Contributing & Direction

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.


Verifying Binary Attestation

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


Support


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.

About

DroneAware Node Releases repository

Resources

Security policy

Stars

348 stars

Watchers

8 watching

Forks

Releases

Packages

Used by

Contributors

Languages