moxon-frame-generator
simple generator for 3D-printed frames for a moxon rectangle antenna
Next-Gen GUI-based WiFi and Bluetooth Analyzer for Linux
git clone https://github.com/ghostop14/sparrow-wifi.gitghostop14/sparrow-wifiSparrow-WiFi is a 2.4 GHz and 5 GHz WiFi and Bluetooth spectral awareness tool for Linux. It integrates WiFi scanning, Bluetooth Low Energy and Classic discovery, software-defined radio spectrum analysis (HackRF, Ubertooth), GPS tracking, FAA RemoteID drone detection, drone/rover-mounted remote operations, and ECS 8.17 indexing into Elasticsearch or OpenSearch into a single platform. Written entirely in Python 3.
The project includes four components that work standalone or together:
| Component | Interface | Purpose |
|---|---|---|
| Sparrow-WiFi | PyQt5 desktop GUI | WiFi/BT scanning, spectrum analysis, source tracking, wardriving |
| Sparrow Agent | Headless HTTP server | Remote scanning, drone/rover deployments, third-party integration |
| Sparrow DroneID | Web-based (browser) | FAA RemoteID drone detection via WiFi and Bluetooth LE |
| Sparrow Elastic Bridge | Headless CLI service | ECS 8.17 indexing of WiFi/BT observations into Elasticsearch / OpenSearch |
The Sparrow Agent and Sparrow DroneID expose JSON REST APIs that allow other applications to query scan results, trigger scans, retrieve drone detections, and integrate wireless/drone awareness into their own workflows. The Elastic Bridge consumes the agent's REST API and ships ECS 8.17 documents with bundled Kibana dashboards.
This release covers three significant improvements over the prior version:
/wireless/networks/<iface> simultaneously, the agent previously kicked off N redundant iw scan calls that serialized on the per-interface lock, multiplying scan latency by the number of clients. The first request is now the "leader" that actually scans; concurrent requests wait on a threading.Event and share the leader's result. Also includes lock-creation TOCTOU fix and exception-safety on per-interface locks.droneid.* namespace), and a multi-device responsive web UI. See the Sparrow DroneID section below.sparrow-elastic.py bridge has been rewritten to produce ECS 8.17 documents (was ECS 1.5), now supports both Elasticsearch 8.x and OpenSearch 2.x, bootstraps composable index templates with ILM/ISM lifecycle policies and rollover write aliases automatically, performs OUI vendor enrichment and rule-based device classification (with optional Fingerbank fingerprinting), and ships four bundled Kibana dashboards plus six legacy-preserved visualizations. The legacy ECS 1.5 bridge is preserved at legacy/sparrow-elastic.py. See Elasticsearch / OpenSearch Integration.The original Sparrow application provides a comprehensive GUI-based replacement for tools like inSSIDer and LinSSID, with capabilities well beyond basic scanning:
sparrowwifiagent.py) for distributed scanning, drone/rover-mounted operations, and Raspberry Pi deploymentsiw scan outputA standalone web-based drone detection and tracking system that decodes FAA-mandated Remote Identification (RemoteID) broadcasts. Runs as a Python HTTP server with a browser-based UI accessible from any device on the network.
Web UI runs at http://localhost:8097 once started. See Installation below for setup, and the API reference for programmatic access.
In addition to Slack webhooks, Sparrow DroneID can POST each fired alert to a generic external alert-ingest endpoint. The channel is disabled by default; configure it in Settings → Alerts → API-Based Alerting:
http://MY_API_HOST:PORT/API_ROOTAuthorization: Bearer ... header; masked in the UI once storedrule.category: "test", serial TEST-0000) so the receiver can be exercised end-to-end without waiting for a real droneSparrow DroneID makes two calls against the configured root URL:
| Verb | Path | Purpose |
|---|---|---|
POST |
{root}/v1/alerts/verify |
Credential check — body {"domain": "<configured>"}. Receiver should reply 200 {"status":"ok"} on success, 401 on bad token. |
POST |
{root}/v1/alerts |
Fire an alert — body is the JSON below. Receiver should reply 201 {"alert_id":"..."} on success. 503 responses are retried with exponential backoff (3 retries); 4xx aborts without retry. A 200 {"status":"dropped"} indicates the domain is disabled upstream. |
Both calls send Authorization: Bearer <token> and Content-Type: application/json.
{
"domain": "<configured>",
"alert": {
"message": "<human-readable text identical to the Slack body>",
"observer": {
"name": "<operator_name or 'Sparrow DroneID'>",
"type": "drone-sensor",
"geo": {"location": {"lat": 0.0, "lon": 0.0}}
},
"rule": {"name": "<alert type label>", "category": "drone_detection"},
"event": {
"severity": 40,
"category": "network",
"action": "new_drone"
},
"labels": {
"serial": "<drone serial>",
"vendor": "<resolved vendor>",
"ua_type": "<UA type display name>",
"alert_type": "new_drone | altitude_max | speed_max | signal_lost"
},
"source": {"geo": {"location": {"lat": 0.0, "lon": 0.0}}},
"details": {
"operator_id": "...", "registration_id": "...", "self_id_text": "...",
"mac_address": "...", "protocol": "...", "rssi": -68,
"range_m": 1234.5, "bearing_deg": 215.0, "bearing_cardinal": "SW",
"speed_mps": 5.2, "direction_deg": 240.0,
"altitude_m_agl": 42.0, "detail": "..."
}
}
}
observer.geo.location is included when the receiver has a GPS fix; source.geo.location is included when the drone is broadcasting a position. Severity follows the ECS convention (lower = more urgent): warnings (new_drone, altitude_max, speed_max) are 40, informational events (signal_lost) are 70. Friendly-tagged drones do not fire alerts when the operator-side "Alert on Friendly drones" toggle is off, so they do not hit this endpoint either.
Synthetic test alerts emitted by the Send Test Message button use rule.category: "test", event.action: "test", event.severity: 70, and serial TEST-0000 so the receiver can recognise and exclude them from operational dashboards.
| Requirement | Sparrow-WiFi (GUI) | Sparrow DroneID (Web) |
|---|---|---|
| OS | Ubuntu 20.04+, Kali 2020.3+, Debian 11+ | Ubuntu 20.04+, Kali, Debian 11+, Raspberry Pi OS |
| Python | 3.8+ | 3.8+ |
| Root | Required (iw scan) | Required (monitor mode, BLE) |
| WiFi adapter | Any with iw support |
Monitor-mode capable (e.g., rtl8812au, Intel AX200) |
| Bluetooth | Optional (hci adapter, Ubertooth) | Optional (any BLE-capable adapter for RemoteID) |
| GPS | Optional (gpsd) | Optional (gpsd or static coordinates) |
| Display | X11/Wayland desktop | Headless OK (web browser on any device) |
git clone https://github.com/ghostop14/sparrow-wifi cd sparrow-wifi
System packages (Ubuntu 22.04+ / Debian 12+ / Kali rolling):
sudo apt install python3-pip python3-pyqt5 python3-pyqt5.qtchart \
gpsd gpsd-clients python3-tk python3-setuptools
Kali users: PyQt5, PyQtChart, and aircrack-ng (for the Falcon plugin) are typically pre-installed. You'll mostly just need
gpsd,gpsd-clients, and the Python deps below.
Python dependencies — choose either approach:
Option A: System-wide install with --break-system-packages — simplest, fits how the GUI/agent get launched (root-owned scripts):
# Modern systems (Ubuntu 24.04+, Kali rolling 2023+, Debian 12+) require this # flag because Python is marked externally-managed (PEP 668). Sparrow runs as # root anyway, so system-wide install is consistent with how it executes. sudo pip3 install --break-system-packages -r requirements.txt
Option B: Virtual environment — isolated, no system pip warnings, preferred by some operators:
python3 -m venv venv source venv/bin/activate pip install -r requirements.txt # Run with sudo using the venv interpreter: sudo venv/bin/python3 ./sparrow-wifi.py
Either way, run:
sudo ./sparrow-wifi.py
cd sparrow-droneid # System tools — tcpdump for WiFi monitor mode, bluez for BLE RemoteID sudo apt install tcpdump bluez # Python dependencies — pick one of: sudo pip3 install --break-system-packages -r sparrow_droneid/requirements.txt # or: python3 -m venv venv && source venv/bin/activate && pip install -r sparrow_droneid/requirements.txt # Run (either entry point works): sudo python3 sparrow_droneid/app.py # or: sudo python3 -m sparrow_droneid
Open http://localhost:8097 in a browser. Configure the monitor interface and GPS in Settings, then click Start.
sudo pip3 install --break-system-packages -r requirements-elastic.txt # or via venv as above
See Elasticsearch / OpenSearch Integration below.
Most WiFi adapters work for basic scanning. Sparrow-WiFi supports multiple interface enumeration backends (iw, iwconfig, nmcli) so it works on systems that may not have iw installed (e.g., RHEL/Fedora with NetworkManager only).
For monitor mode (required by Sparrow DroneID and the Falcon plugin), adapter and driver support varies:
iw phy <phy> info | grep monitor or iwconfig <iface> to verify capabilitiesFor Sparrow DroneID specifically, the adapter must deliver raw 802.11 frames in monitor mode. Some Intel adapters report monitor mode as supported but silently drop frames at the firmware level. The application detects this and warns you.
Sparrow-WiFi supports several Bluetooth scanning modes:
| Mode | Hardware | What You See |
|---|---|---|
| BLE advertisement scan | Standard BT adapter | LE devices that are actively advertising |
| Promiscuous scan | Ubertooth One + Blue Hydra | All BLE and Classic BT devices in range |
| iBeacon advertising | Standard BT adapter | Advertise your own iBeacons |
| RemoteID scan | Standard BT adapter | FAA-compliant drone identification (Sparrow DroneID only) |
A standard built-in or USB Bluetooth adapter is sufficient for BLE advertisement scanning and RemoteID drone detection. Test your adapter with bluetoothctl scan on.
For full promiscuous discovery of both Classic and BLE devices, you'll need an Ubertooth One and Blue Hydra installed into /opt/bluetooth/blue_hydra. This is optional and not required for basic BLE or RemoteID scanning.
Real-time spectral overlays on top of WiFi channel views:
ubertooth-specan-uihackrf_sweepBoth applications use gpsd for GPS. Quick setup:
# Install sudo apt install gpsd gpsd-clients # Test with a USB GPS receiver sudo gpsd -D 2 -N /dev/ttyUSB0 # Verify xgps # or: cgps -s
For production, configure /etc/default/gpsd with your device path and restart the service.
Sparrow DroneID also supports static coordinates (configured in Settings) for fixed-site installations without a GPS receiver.
The Sparrow agent (sparrowwifiagent.py) is a headless HTTP server that exposes all of Sparrow's WiFi and Bluetooth scanning capabilities as a JSON-based REST API. This is how the Sparrow-WiFi GUI communicates with remote sensors, but the API is open for any application to use.
Use cases:
Sparrow DroneID has its own REST API as well (API reference), providing programmatic access to drone detections, alert management, geozones, and system configuration.
sudo ./sparrowwifiagent.py
Listens on port 8020 by default. Key options:
| Flag | Purpose |
|---|---|
--port PORT |
HTTP listen port |
--allowedips IP1,IP2 |
Restrict client connections |
--staticcoord LAT,LON,ALT |
Use fixed GPS coordinates |
--mavlinkgps 3dr |
Pull GPS from Solo 3DR drone |
--recordinterface IFACE |
Auto-record on startup (headless) |
--userpileds |
Use Raspberry Pi LEDs for status |
--sendannounce |
UDP broadcast for agent discovery |
See --help for the full list.
# List wireless interfaces the agent can scan curl http://sensor:8020/wireless/interfaces # Trigger a WiFi scan and pull results (multiple concurrent callers # get coalesced into a single iw scan; first caller is the leader) curl http://sensor:8020/wireless/networks/wlan0 # Filter to specific frequencies curl "http://sensor:8020/wireless/networks/wlan0?frequencies=2412,2437,2462" # Query GPS status curl http://sensor:8020/gps/status # Start a Bluetooth Low Energy advertisement scan curl http://sensor:8020/bluetooth/discoverystarta # Pull current BT discovery results curl http://sensor:8020/bluetooth/discoverystatus
For Sparrow DroneID, see the dedicated API reference.
Production note: the agent listens on all interfaces by default. For deployments outside a trusted network, use
--allowedipsto restrict callers, run behind a reverse proxy with TLS, or bind to a private interface only.
Advanced wireless penetration testing integration. Provides point-and-click access to:
wpapcap2john)# Kali users: aircrack-ng + JTR are usually pre-installed. # Ubuntu / Debian / Raspberry Pi OS: sudo apt install aircrack-ng john
Verify airmon-ng, airodump-ng, and wpapcap2john are on your PATH after install.
Active penetration testing is subject to legal regulations. It is your responsibility to obtain appropriate authorization before using these tools.
The sparrow_elastic package provides an ECS 8.17 bridge that polls the Sparrow WiFi agent and bulk-indexes WiFi and Bluetooth observations into Elasticsearch 8.x or OpenSearch 2.x. It bootstraps composable index templates, ILM/ISM lifecycle policies, and rollover write aliases automatically; performs OUI vendor enrichment and rule-based device classification (with optional Fingerbank fingerprinting); and ships pre-built Kibana dashboards.
# 1. Start the remote agent (it provides scan data via HTTP)
sudo ./sparrowwifiagent.py
# 2. Install bridge dependencies
sudo pip3 install --break-system-packages -r requirements-elastic.txt
# 3. Run the bridge
./sparrow-elastic.py --elasticserver http://user:pass@host:9200 --wifiinterface wlan1
# 4. (Optional) Import the bundled Kibana dashboards
python3 install_dashboards.py --kibana-url http://kibana:5601 \
--username elastic --password '<password>'
Credential hygiene: embedding
user:pass@in--elasticserveris convenient but the URL becomes visible inps,journalctl, and shell history. For production, use--username/--passwordflags, environment variables (SPARROW_ES_USERNAME,SPARROW_ES_PASSWORD), or theEnvironmentFile=pattern in the included systemd unit example.
Sparrow* viz so old muscle memory keeps workingmanuf, BT SIG company IDs, service UUIDs, GAP appearance values, and Apple Continuity subtype tables, with a 30/90-day self-refresh background threadFor full operator documentation (engine selection, auth modes, dashboard import, reference data, complete CLI reference) see sparrow_elastic/README.md.
Sample configuration files are in the repo root and init.d_scripts/:
sparrow-elastic.conf.example — INI-style config with all supported keyssparrow-elastic.env.example — shell-format env file for systemd deploymentsinit.d_scripts/sparrow-elastic.service.example — systemd unit templateThe pre-2026 bridge wrote ECS 1.5 documents into operator-named indices via --wifiindex / --btindex. The new bridge writes ECS 8.17 documents into rollover-managed write aliases (default sparrow-wifi / sparrow-bt).
The legacy script is preserved at legacy/sparrow-elastic.py alongside its .txt template and ILM policy files. Running it still requires the legacy environment (manual template + ILM setup).
Flag changes (with backwards compatibility):
| Legacy flag | New flag | Notes |
|---|---|---|
--wifiindex NAME |
--wifi-alias NAME |
Legacy spelling still accepted as a deprecated alias. |
--btindex NAME |
--bt-alias NAME |
Legacy spelling still accepted as a deprecated alias. |
--dont-create-indices |
unchanged | Skips bootstrap. |
--elasticserver, --sparrowagent, --sparrowport, --wifiinterface, --scandelay |
unchanged |
A legacy invocation like:
./sparrow-elastic.py --elasticserver=http://user:pass@host:9200 \
--wifiinterface=wlan1 \
--wifiindex=sparrowwifi-home \
--btindex=sparrowbt-home
still parses and runs — but the bridge now refuses to write into a pre-existing index whose mapping doesn't carry the ECS 8.17 schema marker, exiting with three remediation options (use a different alias, wipe and re-bootstrap, or run the legacy bridge). For a clean install, just drop --wifiindex / --btindex and accept the new defaults.
The remote agent can be deployed on a Raspberry Pi mounted on a drone or rover for mobile wireless surveying. Tested on a Solo 3DR drone with GPS integration via MAVLink.
# On the Pi: auto-start, pull drone GPS, record to local files sudo python3 ./sparrowwifiagent.py --userpileds --sendannounce --mavlinkgps 3dr --recordinterface wlan0
LED indicators (Raspberry Pi):
Recordings can be retrieved via the Sparrow-WiFi GUI's agent management interface.
dtoverlay=disable-wifi to /boot/firmware/config.txt on Bookworm and later, or /boot/config.txt on older releasessudo pip3 install --break-system-packages -r requirements.txt (or use a venv as in the Installation section)sparrow-wifi/
sparrow-wifi.py # Desktop GUI entry point
sparrowwifiagent.py # Headless remote agent
sparrow-elastic.py # Elasticsearch / OpenSearch bridge (ECS 8.17)
install_dashboards.py # One-shot Kibana dashboard installer
requirements.txt # Python dependencies (GUI)
requirements-elastic.txt # Python dependencies (Elasticsearch bridge)
wirelessengine.py # WiFi scan engine (iw)
sparrowbluetooth.py # Bluetooth scan engine
sparrowhackrf.py # HackRF spectrum engine
sparrowmap.py # Map generation
plugins/ # Falcon and other plugins
sparrow_elastic/ # ES/OS bridge package
*.py # Client abstraction, document builder, classifier...
templates/ # Composable index templates (ES + OS variants)
policies/ # ILM (ES) and ISM (OS) lifecycle policy JSON
dashboards/ # Kibana NDJSON: 5 dashboards + legacy-preserved
data/ # Bundled reference data (manuf, BT SIG, classifier rules)
README.md # Full bridge operator documentation
legacy/ # Pre-2026 ECS 1.5 bridge, frozen for reference
sparrow-elastic.py # Legacy bridge (still runnable)
sparrow_elastic_*.txt # Legacy index templates and ILM policy
sparrow-droneid/ # DroneID web application
sparrow_droneid/
app.py # Entry point (sudo python3 app.py)
__main__.py # Allows: sudo python3 -m sparrow_droneid
requirements.txt # Python dependencies (DroneID)
backend/ # API server, capture engine, database
frontend/ # HTML, JS, CSS (served by backend)
sparrow_drone_id_api.md # REST API reference
This project is licensed under the terms included in the repository. See the LICENSE file for details.
more like this
simple generator for 3D-printed frames for a moxon rectangle antenna
Software for a Wordclock based on ESP8266 and Neopixel LEDs with PONG, TETRIS, SNAKE game modes
search projects, people, and tags