Install
openclaw skills install rtl-sdr-fm-rds-recorderRecord broadcast FM stations from an RTL-SDR using a reliable IQ-capture workflow with offline WBFM demodulation, RDS station-name extraction, and automatic...
openclaw skills install rtl-sdr-fm-rds-recorderUse this skill for reliable broadcast FM recording from an RTL-SDR. The preferred workflow is IQ capture with rtl_sdr, RDS station-name extraction, offline WBFM demodulation, and MP3 export. This skill currently targets Linux environments and should be treated as Linux-only.
--check to confirm the RTL-SDR is available and reachable before promising the skill is ready to use.redsea is installed and reachable, either from PATH or from the expected local fallback path, before promising full RDS-ready behavior.redsea is missing, rebuild or reinstall it before running --decode-rds or any staged recording flow that depends on station naming.scripts/fm_iq_pipeline.py for recording.references/pipeline-notes.md for setup-specific caveats.--record --freq, using the same --out-dir for both steps.MEDIA:... token in the same message; send the file attachment as its own message. If one reply contains multiple MEDIA:... tokens, put each token on its own line.This skill is Linux-only and is only fully ready to use when these tools are present.
rtl_sdrrtl_fmrtl_powerffmpegpython3numpyscipyredseaIf redsea is missing, the recording pipeline may still work, but RDS station-name extraction and final file naming will fall back to UnknownStation. If scipy is missing, recording and demodulation are unavailable; --check and --scan-fm still work. The script first tries redsea from PATH, then falls back to the expected local path.
Run --check first:
python3 scripts/fm_iq_pipeline.py --check
--check returns JSON. If a tool reports available: false, inspect probeMessage first; it contains the first useful line from the probe stderr/stdout. probeReturnCode is also included for probe-based checks when available.
Scan FM broadcast band first:
python3 scripts/fm_iq_pipeline.py --scan-fm --gain 19.7 --out-dir ./session
Decode RDS for one selected station and cache the resulting station name for later recording. For station naming, the resolver only uses ps and partial_ps; pi is kept only as auxiliary/debug evidence, and other decoded RDS fields are intentionally ignored for naming:
python3 scripts/fm_iq_pipeline.py --decode-rds --freq 98.7812 --gain 19.7 --out-dir ./session
If --decode-rds returns UnknownStation, inspect rds-debug-<freq>.json, especially rtlFmStderrFirstLine, for diagnostics.
Record one station using the cached result from the earlier decode step. Use the same --out-dir value:
python3 scripts/fm_iq_pipeline.py --record --freq 98.7812 --gain 19.7 --out-dir ./session
For longer recordings, pass --duration 300 (5 minutes):
python3 scripts/fm_iq_pipeline.py --record --freq 98.7812 --gain 19.7 --duration 300 --out-dir ./session
By default, --record captures a short 10-second sample. Treat that as a station sample rather than a full-length recording unless you explicitly provide a longer --duration.
By default, output is written to ./output relative to the current working directory. For staged workflows, prefer passing an explicit shared --out-dir value such as ./session.
By default, successful recording keeps the MP3 and metadata JSON, but removes intermediate .bin and .wav files. Use --keep-intermediate when you need those artifacts for debugging or analysis.
--check prints a JSON object keyed by tool name.--scan-fm prints a JSON array sorted by signal strength (strongest first). Each element includes stationName, frequencyMHz, meanDb, and aboveNoise.--decode-rds prints a JSON array with one element containing frequencyMHz and stationName.--record prints the path to the produced MP3 file as plain text.MEDIA:... token so the platform treats it as an actual attachment.MEDIA:... tokens, put each token on its own line.Examples:
[{"stationName": "UnknownStation", "frequencyMHz": 98.7812, "meanDb": -28.5, "aboveNoise": 14.2}]
[{"frequencyMHz": 98.7812, "stationName": "TROJKA"}]
./session/TROJKA-98.7812-20260409-143022.mp3
--scan-fm takes about 30 seconds by default.--decode-rds can take up to about 20 seconds, but may finish earlier when early-exit conditions are met.--record takes roughly the requested --duration plus demodulation and MP3 encoding overhead.These are examples of natural-language requests the assistant may receive. The assistant should interpret them as orchestration on top of this skill's atomic commands.
Example request:
Scan the entire broadcast FM band, go through all detected stations, extract the station name for each one, record audio, and send me all resulting MP3 files.
Expected orchestration:
--check--scan-fm --gain <dB> --out-dir ./session--decode-rds --freq <MHz> --gain <dB> --out-dir ./session--record --freq <MHz> --gain <dB> --out-dir ./sessionExample request:
Scan the broadcast FM band, take the 5 strongest stations, extract their station names, record audio for them, and send me the MP3 files.
Expected orchestration:
--check--scan-fm --gain <dB> --out-dir ./session--decode-rds --freq <MHz> --gain <dB> --out-dir ./session--record --freq <MHz> --gain <dB> --out-dir ./sessionExample request:
Record 90.9688 MHz from the broadcast FM band and label the file with the station name.
Expected orchestration:
--check--decode-rds --freq 90.9688 --gain <dB> --out-dir ./session--record --freq 90.9688 --gain <dB> --out-dir ./sessionThe script should:
--scan-fm mode, save scan results and return frequency candidates only--decode-rds --freq mode, try to extract the RDS station name and save it to a per-frequency cache file rds-<Frequency>.json plus a diagnostic file rds-debug-<Frequency>.json--record --freq mode, produce MP3 and metadata JSON (intermediate IQ and WAV are removed by default; pass --keep-intermediate to retain them)--record --freq must use the cached result from the earlier decode step for station naming and must not run a second independent RDS naming pass--decode-rds --freq and --record --freq must use the same --out-dir value when staged naming consistency matters--out-dir, --record --freq falls back to UnknownStation<StationName>-<Frequency>-<RecordingTimeStart>.mp3Read references/pipeline-notes.md when:
redsea location or environment setup is in doubtscripts/fm_iq_pipeline.py — main working FM + RDS pipeline orchestrationscripts/fm_config.py — shared DSP, scan, timeout, and path constantsscripts/rds_observation.py — RDS evidence collection and station-name sanitizing helpersscripts/station_identity.py — station identity resolver and candidate selection policyscripts/station_identity_debug.py — debug/report generation for RDS identity decisionsreferences/pipeline-notes.md — setup-specific notes, naming, caveats, and examples