Control and monitor multiple RTL-SDR command line tools from the comfort of your web browser.
Find a file
2026-01-14 12:36:38 -05:00
public Upload files to "public" 2026-01-14 12:11:11 -05:00
package.json Upload files to "/" 2026-01-14 12:10:33 -05:00
README.md Update README.md 2026-01-14 12:36:38 -05:00
screenshot.png Upload files to "/" 2026-01-14 12:18:29 -05:00
server.js Upload files to "/" 2026-01-14 12:10:33 -05:00

📡 SDR-Commander

A modern web-based control panel for managing RTL-SDR dongles on headless Linux servers. Switch between multiple radio modes, decode pager messages, capture sensor data, and stream raw IQ samples—all from your browser.

screenshot

Features

  • Multi-Mode Operation — Seamlessly switch between pager decode, RTL_433, and RTL_TCP modes
  • Real-Time WebSocket Updates — Live data streaming to your browser
  • Persistent SQLite Database — All decoded messages and sensor readings are stored
  • Telegram Notifications — Get pager alerts with flexible whitelist/blacklist filtering
  • Modern Web UI — Clean, responsive interface with dark mode aesthetics

Operating Modes

Mode Description Tools Used
📟 Pager Decode Decodes POCSAG pager messages (fire/EMS/hospital) rtl_fm + multimon-ng
🌡️ RTL_433 Decode Scans 433 MHz for weather stations, sensors, TPMS rtl_433
📶 RTL_TCP Streams raw IQ data over network for remote SDR apps rtl_tcp

Note: The SDR dongle can only run one mode at a time. Switching modes automatically stops the previous service.

Requirements

Hardware

  • RTL-SDR USB dongle (RTL2832U-based)

Software

  • OS: Debian/Ubuntu Linux (tested on Debian Trixie)
  • Node.js: 18+
  • RTL-SDR tools: rtl_fm, rtl_tcp
  • Decoders: multimon-ng, rtl_433

Install Dependencies (Debian/Ubuntu)

sudo apt install rtl-sdr multimon-ng rtl-433

Installation

# Clone the repository
git clone https://git.wardnet.me/kurtis/SDR-Commander.git

# Install Node.js dependencies
npm install

# Start the server
npm start

The control panel will be available at http://your-server-ip:3000

Configuration

Configuration is stored in config.json (created automatically on first run):

{
  "pager": {
    "frequency": "152240000",
    "gain": 40,
    "sampleRate": 22050
  },
  "telegram": {
    "enabled": false,
    "botToken": "",
    "chatId": "",
    "topicId": "",
    "whitelist": {
      "capcodes": [],
      "types": [],
      "protocols": []
    },
    "blacklist": {
      "capcodes": [],
      "types": [],
      "protocols": []
    }
  }
}

Telegram Notifications

  1. Create a bot with @BotFather on Telegram
  2. Get your Chat ID (use @userinfobot)
  3. Enter credentials in Settings tab or edit config.json
  4. Optionally configure whitelist/blacklist to filter notifications

Systemd Services

For production use, set up systemd services for automatic startup:

/etc/systemd/system/sdr-control.service

[Unit]
Description=SDR Control Panel
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/path/to/sdr-control
ExecStart=/usr/bin/node server.js
Restart=on-failure

[Install]
WantedBy=multi-user.target
sudo systemctl enable sdr-control
sudo systemctl start sdr-control

API Endpoints

Endpoint Method Description
/api/status GET Current mode and service status
/api/mode/:mode POST Switch mode (pager, 433, tcp, stop)
/api/config GET/POST Read/update configuration
/api/pager GET Fetch pager messages (with pagination)
/api/sensors GET Fetch sensor readings (with pagination)
/api/debug GET System debug information
/api/telegram/test POST Send test notification

WebSocket

Connect to /ws for real-time updates:

  • { type: 'pager', data: {...} } — New pager message
  • { type: 'sensor', data: {...} } — New sensor reading
  • { type: 'log', data: {...} } — Debug log entry

Project Structure

sdr-control/
├── server.js          # Express + WebSocket server
├── config.json        # Runtime configuration (auto-generated)
├── sdr_data.db        # SQLite database
├── package.json
└── public/
    ├── index.html     # Main UI
    ├── app.js         # Frontend JavaScript
    └── styles.css     # Styling

Database Schema

Pager Messages

Column Type Description
id INTEGER Primary key
timestamp DATETIME Receive time
capcode TEXT Pager address
protocol TEXT POCSAG512/1200/2400
type TEXT alpha/numeric
message TEXT Decoded content
frequency TEXT Receive frequency

Sensor Data

Column Type Description
id INTEGER Primary key
timestamp DATETIME Receive time
model TEXT Device model
sensor_id TEXT Device ID
temperature REAL Temperature reading
humidity REAL Humidity percentage
battery TEXT Battery status

Tech Stack

  • Backend: Node.js, Express, WebSocket (ws)
  • Database: SQLite (better-sqlite3)
  • Frontend: Vanilla HTML/CSS/JS
  • SDR Tools: rtl_fm, multimon-ng, rtl_433, rtl_tcp

Built for headless SDR servers 🛰️