Detects DJI drones using the ANTSDR E200 SDR and publishes DroneID data over ZMQ for integration with DroneID, DragonSync, Kismet, and TAK/CoT systems.
Supports both legacy and new AntSDR firmware, including O4 encrypted drone detection (DJI Mini 5, etc.).
| Protocol | Examples | Data Available |
|---|---|---|
| O2/O3 (unencrypted) | Mini 2, Mini 3 Pro, Air 2S, Mavic 3 | Serial, model, drone/pilot/home GPS, altitude, speed, RSSI |
| O4 (encrypted) | Mini 5, future models | Hash ID, frequency, RSSI |
| O4 + DragonScope | Mini 5, future models | Serial, drone/pilot/home GPS, altitude, speed, RSSI (requires DragonScope) |
| Device | IP Address |
|---|---|
| AntSDR E200 | 172.31.100.2 (WarDragon Pro default) or 192.168.1.10 (stock) |
| Host/WarDragon | 172.31.100.1 or 192.168.1.9 |
These settings only need to be done once per AntSDR.
bash
sudo tio /dev/ttyUSB0Power cycle the AntSDR — you should see boot messages scrolling. If you don't see any output, you may be on the wrong serial port (e.g., if a Sonoff or other USB device is also connected). Exit with Ctrl+T then Q and try:
bash
sudo tio /dev/ttyUSB1
Then power cycle the AntSDR again.
Login as root / analog
Copy-paste all variables at once:
bash
fw_setenv ipaddr_eth 172.31.100.2
fw_setenv tcp_serverip 172.31.100.1
fw_setenv tcp_serverport 52002
fw_setenv gain_mode fast_attack
fw_setenv heart_beate_time 30
fw_setenv api_host 172.31.100.1
fw_setenv request_time 1
fw_setenv auth_secret placeholder
fw_setenv token_secret placeholder
fw_setenv device_serial antsdr_e200
fw_setenv device_mode auto
reboot
After reboot, verify the settings saved:
bash
fw_printenv ipaddr_eth tcp_serverip tcp_serverport gain_mode heart_beate_time api_host request_time auth_secret token_secret device_serial device_mode
Power off the AntSDR, disconnect the console cable, flip the switch back to SD mode, reconnect the cable, and power on
Note: The AntSDR may need the power/console cable disconnected and reconnected when switching between QSPI and SD mode in order to fully reboot.
| Variable | Value | Description |
|---|---|---|
ipaddr_eth |
172.31.100.2 |
AntSDR IP address |
tcp_serverip |
172.31.100.1 |
Your host/WarDragon IP (where dji_receiver.py runs) |
tcp_serverport |
52002 |
TCP port (must match --listen-port) |
gain_mode |
fast_attack |
AD9361 AGC mode for drone detection |
heart_beate_time |
30 |
Heartbeat interval in seconds (keeps TCP connection alive) |
api_host |
172.31.100.1 |
WarDragon IP (where DragonScope proxy listens on port 80) |
request_time |
1 |
Seconds between O4 telemetry updates (default 30, lower = faster GPS) |
auth_secret |
placeholder |
Required by firmware (any value) |
token_secret |
placeholder |
Required by firmware (any value) |
device_serial |
antsdr_e200 |
Device identifier |
device_mode |
auto |
Frequency mode (auto hops 5.8 GHz channels) |
Once booted with the new firmware (SD mode), SSH access is root/1.
Note: The firmware defaults to 192.168.1.10 if ipaddr_eth is not set. All other variables above have no defaults and must be configured per device.
python3 dji_receiver.py -d
This listens on port 52002 for new firmware connections and publishes drone data on ZMQ port 4221.
Use --mode legacy to connect to old firmware on port 41030, or --mode dual for both.
-d, --debug Enable debug output
--mode MODE legacy, new, or dual (default: new)
--antsdr-ip IP AntSDR IP for legacy mode (default: 172.31.100.2)
--antsdr-port PORT AntSDR port for legacy mode (default: 41030)
--listen-port PORT TCP listen port for new firmware (default: 52002)
--udp-port PORT UDP listen port (default: 52002, set 0 to disable)
Environment variables (override defaults):
- ANTSDR_IP — AntSDR IP for legacy mode
- ANTSDR_PORT — AntSDR port for legacy mode
- ANTSDR_LISTEN_PORT — TCP listen port for new firmware
- ANTSDR_UDP_LISTEN_PORT — UDP listen port
| Port | Protocol | Direction | Purpose |
|---|---|---|---|
| 41030 | TCP | inbound (legacy) | Connect to legacy firmware AntSDR |
| 52002 | TCP | inbound (new) | Accept new-firmware AntSDR connections |
| 52002 | UDP | inbound | Receive forwarded frames (alternative transport) |
| 4221 | ZMQ TCP | outbound (XPUB) | Publish parsed drone data to subscribers |
| 4225 | ZMQ TCP | inbound (SUB) | Subscribe to WarDragon monitor for sensor GPS |
TCP and UDP can share port 52002 — the kernel keeps protocols separate.
AntSDR E200 → dji_receiver.py (:4221 ZMQ) → zmq_decoder.py (:4224 ZMQ) → DragonSync → CoT/TAK/MQTT
bash
python3 zmq_decoder.py --dji 127.0.0.1:4221kismet_cap_antsdr_droneid --source antsdr-droneid:host=<ANTSDR_IP>,port=41030 --connect localhost:3501 --tcp
Requires nightly Kismet builds. Only works with legacy firmware — the Kismet capture source (kismet_cap_antsdr_droneid) expects the legacy binary frame protocol on port 41030. The new firmware (drone_dji_rid_decode) uses a different text CSV protocol over a reversed TCP connection, which the Kismet capture source does not currently support.
drone_dji_rid_decode)fw_setenv tcp_serverip / tcp_serverportdone_dji_release)O4 drones (Mini 5, etc.) broadcast encrypted DroneID. The receiver can detect them and provide:
- Hash ID — unique per session (e.g., drone-alert-9dc89f97)
- Frequency — detection frequency with hopping pattern
- RSSI — signal strength for proximity estimation
Position data is not available from the receiver alone for O4 drones.
Important: DJI drones only broadcast DroneID when motors are spinning. Power-on alone only activates the OcuSync control link.
The DragonScope firmware (build_sdimg_drone_o4_dragonscope.zip, provided
to kit customers) installs on the AntSDR the same way as the public O4
firmware in this repo: extract the zip contents to the SD card root,
insert into the AntSDR with the boot switch in SD mode, and power on.
Two differences from the public firmware are visible to operators:
First-boot env auto-configuration. The DragonScope firmware
sets all required fw_setenv variables on first boot, so the
tio / serial-console setup steps in
AntSDR Configuration are
skipped. SSH access is available immediately after the first boot
completes (default: ssh root@172.31.100.2, password 1).
UDP transport for detections. Decoded drone frames are sent to
the WarDragon over UDP at ${udp_dest_ip}:${udp_dest_port}
(default 172.31.100.1:52002). dji_receiver.py listens on both
TCP and UDP 52002 by default, so the same receiver works with
either firmware — no flags or code changes.
| Variable | DragonScope default | Public firmware default | Purpose |
|---|---|---|---|
ipaddr_eth |
172.31.100.2 |
unset — set manually | AntSDR IP |
tcp_serverip |
127.0.0.1 |
unset — set manually | Legacy TCP destination (unused on kit) |
tcp_serverport |
52002 |
unset — set manually | Legacy TCP port (unused on kit) |
udp_dest_ip |
172.31.100.1 |
n/a | WarDragon IP for telemetry |
udp_dest_port |
52002 |
n/a | UDP port (matches dji_receiver) |
gain_mode |
fast_attack |
unset — set manually | AD9361 AGC mode |
heart_beate_time |
30 |
unset — set manually | Heartbeat interval |
api_host |
172.31.100.1 |
unset — set manually | DragonScope proxy host (WarDragon) |
request_time |
1 |
unset — set manually | O4 telemetry refresh (seconds) |
auth_secret |
placeholder |
unset — set manually | Required-fill |
token_secret |
placeholder |
unset — set manually | Required-fill |
device_serial |
dragonsdr |
unset — set manually | Device identifier |
device_mode |
auto |
unset — set manually | Frequency mode (5.8 GHz hop) |
To verify the values that were set, SSH in and run:
fw_printenv ipaddr_eth tcp_serverip tcp_serverport udp_dest_ip udp_dest_port \
gain_mode heart_beate_time api_host request_time \
auth_secret token_secret device_serial device_mode
To override any of these after first boot, use fw_setenv:
fw_setenv udp_dest_ip 192.168.1.50
fw_setenv ipaddr_eth 192.168.1.10
reboot
The first-boot init only runs once per device (marked by
/mnt/jffs2/.dragonscope_initialized_v2), so manual customization
persists across reboots.
DragonScope provides full O4 telemetry — serial number, drone GPS, pilot position, home point, altitude, and speed. When configured, O4 drones appear in dji_receiver with the same data as O2/O3.
Requirements: - An O4-capable AntSDR firmware (provided separately — not the same as the firmware zips in this repo) - A DragonScope license key and config file (provided separately) - An internet connection on the WarDragon
O2/O3 drones are unaffected and continue to work fully offline. DragonScope runs as a service on your WarDragon and starts automatically. Without a license key configured, it runs in detection-only mode — O4 drones still appear as drone-alert-{hash} but without position data. Once a key is added, full telemetry activates within 30 seconds with no restart needed.
To obtain the DragonScope firmware and a license key, contact us.
If you already have this repo cloned on your WarDragon:
cd /home/dragon/WarDragon/antsdr_dji_droneid
git pull
Place your dragonscope.cfg (provided separately with your license key) in the same directory:
cp /path/to/dragonscope.cfg /home/dragon/WarDragon/antsdr_dji_droneid/
Install both services:
sudo cp dji-receiver.service dragonscope.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl restart dji-receiver
sudo systemctl enable dragonscope
sudo systemctl start dragonscope
Verify DragonScope is running:
curl http://localhost/health
# {"status": "ok", "licensed": true}
Ensure api_host on the AntSDR points to the WarDragon IP (see AntSDR Configuration above). No --proxy flag is needed in dji_receiver.
| File | Description |
|---|---|
dragonscope.py |
O4 telemetry proxy (runs on WarDragon, listens on port 80) |
dragonscope.cfg |
Configuration (endpoint URL + license key, provided separately) |
dragonscope.service |
systemd unit file |
A systemd service file for dji_receiver.py is included in this repo. To install it on your host (e.g. WarDragon kit):
sudo cp dji-receiver.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable dji-receiver
sudo systemctl start dji-receiver
Check status and logs:
sudo systemctl status dji-receiver
journalctl -u dji-receiver -f
# Stop the drone detection daemon on the AntSDR
./service_controller.sh stop
# Start it again
./service_controller.sh start
The script auto-detects old vs new firmware and stops/starts the correct processes. On both firmware versions, the init chain is S55drone → droneangle.sh → daemon binary. The watchdog in droneangle.sh respawns the daemon every second, so all three processes must be killed for a clean stop.
bash
fw_setenv ipaddr_eth NEW_IP_ADDRESSWhen changing the AntSDR IP, also update your host interface static IP, the --antsdr-ip flag or ANTSDR_IP env var, and any Kismet references.
pyzmqThe use of this firmware and software may be subject to regulations in your region. Ensure compliance with local laws regarding wireless communication and drone detection.
$ claude mcp add antsdr_dji_droneid \
-- python -m otcore.mcp_server <graph>