istrain 559caead36 istrain-public: from-scratch build of a passive RF train detector
Public community release. The complete working system — DSP + decoders (scripts/),
web dashboard + API (dashboard/), container stack (docker/), config templates (config/) —
plus APOCALYPSE-EDITION.md, the full build guide for a human or a coding agent. GPLv3
(PyEOT dependency). Scrubbed of all secrets, internal IPs, hostnames, and location detail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 23:19:16 -04:00

istrain — a passive RF train detector you can build

Is a train blocking the crossing? istrain answers that by listening — passively, on public railroad radio frequencies — to the transmitters every train carries: the crew/dispatch voice and trackside defect detectors on 160162 MHz, and the End-of-Train and Head-of-Train telemetry on 457.9375 / 452.9375 MHz. It decodes the End-of-Train brake-pressure and motion data, transcribes the voice, and fuses it all into one live verdict.

Live instance: istrain.jhestyr.net

It's built on a couple of ~US$30 RTL-SDR dongles, some wire, and an always-on Linux box running Docker. No transmitting, no license needed to receive in the US, no railroad cooperation — the trains announce themselves; you just get set up to hear them. It works at any North American crossing because the EOT/HOT frequencies are continent-wide and the voice channel plans are public — you change one config file for your location.

This repository is the complete, working system — the DSP, the decoders, the web dashboard, and the container definitions — shared so anyone (or any coding agent) can build one from scratch and learn from it.


→ Start here: APOCALYPSE-EDITION.md

The full from-scratch build guide: hardware shopping list, operating-system setup, freeing the dongles from the TV driver, researching your crossing's channels, bringing up the container stack step by step, transcription, and the hard-won tuning lessons. It's written to be read straight through by a human or handed to an LLM coding agent pointed at this repo.

What's here

Path What it is
APOCALYPSE-EDITION.md the complete build guide (read this first)
scripts/ the signal engine + decoders — stdlib Python + NumPy only
scripts/iq_hop.py, iq_channelize.py the retune-in-place 452⇄457 hop and the sub-channel splitter (the mission radio)
scripts/eot/ the two-pass FFSK End-of-Train decoder (drift-tolerant; validates via vendored PyEOT)
scripts/bot-recover.py Head-of-Train frame recovery + head/tail join
scripts/transcribe-worker.py voice clip → comms filter → Whisper → transcript
dashboard/ serve.py (the API + static server, stdlib, no framework) + the web UI
docker/ Compose template + Dockerfiles (web / airband / scanhop / worker)
config/ istrain.conf.example (your channels go here) + the DVB-blacklist file

The idea in three transmitters

  1. Voice (160162 MHz): dispatchers, crews, and defect detectors that read out milepost, axle count, and speed in plain English. The most direct "a train just passed here" signal.
  2. End-of-Train (457.9375 MHz): the last car's telemetry box — unit ID, brake-pipe pressure, motion flag — a 1200-baud FFSK burst every few seconds. The brake-pressure curve tells you passing vs. dwelling vs. cut-and-standing vs. departing.
  3. Head-of-Train (452.9375 MHz): the locomotive's half; decode it and join head to tail for a confirmed complete train.

Any one can be too weak to read, but a real train lights several bands at once — so istrain correlates across all of them.

License & credits

GPLv3 — see LICENSE. The EOT decoder validates frames against PyEOT by Eric Reuter (GPLv3, vendored under scripts/eot/); full attribution and the licensing note for forkers are in ATTRIBUTION.md. The communities and tools that made this possible — RTL-SDR Blog, osmocom rtl-sdr, RTLSDR-Airband, faster-whisper / OpenAI Whisper, FFmpeg, NumPy, Docker + Dockge, and the railfan frequency databases — are credited in the dashboard's With Thanks panel.

A community project. If you build one, we'd love to hear what you heard.

S
Description
Passive RF train detector you can build from scratch — public community release
Readme GPL-3.0 216 KiB
Languages
Python 77.5%
HTML 9.6%
CSS 6.7%
JavaScript 5%
Dockerfile 1.2%