Curbstop

FI-173 · v1.0.0

Listen to the meters around you

One button. This picks up every automatic meter reading transmission in earshot, works out which protocol they speak, and shows you the numbers. Everything it does is the same machinery as the full bench; what is missing here is the decisions, not the honesty.

What is out there

Listening
no
Transmissions
0
Meters
0
Protocol
-
Rejected as noise
0
Listening for
-
a meter speaks every 30 seconds or so

Nothing heard yet.

What to do next

Press a button above and give it a minute.

The meters in earshot

Biggest first. A meter you have not claimed shows a label for this session rather than its number, because most of these belong to your neighbours. Find the one whose reading matches your own meter face and claim it.

Nothing heard yet.

Packets as they arrive

The newest thirty, newest first. A checksum reading advisory means the arithmetic came out right against a polynomial nobody has confirmed, which proves the mechanism and not the polynomial. The full bench has a station that solves for it.

AtProtocolMeterReadingChecksumSignal
No packets yet.

Source

Pick where samples come from. The fixture and file paths work with the page opened straight off disk. The two live paths need the page served over http, because browsers refuse USB and sockets to a file:// origin.

Fixture · no hardware

Synthesises real IQ from the same layout table the decoder reads, at a noise level you choose. The answers are known ahead of time, which is what makes the decode chain testable.

File

Feed a capture you already have. Raw IQ is read as unsigned 8-bit interleaved, the shape rtl_sdr writes.

Dongle over WebUSB CORRECTED AGAINST A WORKING RADIO

This programs the demodulator and the R820T tuner: the initialisation set, the tracking filter for the band, the phase locked loop, the gain, and the decimation filter. Up to v1.7.3 it wrote none of the tuner and none of the decimation filter, and three of its USB register addresses were wrong.

The register map now comes from a working implementation rather than from recollection, which is why it is worth trusting more than the last two attempts. Six corrections, any one of which produces silence on its own: the endpoint control register is 0x2148 and was being written at 0x2158, which is the packet size register, so the sample endpoint never came out of reset; the decimation coefficients were never written, and left at zero they silence the whole converter path; the tuner was never programmed at all; the demodulator was set up for a zero intermediate frequency tuner, which the R820T is not; the tuner was written seven registers at a time rather than one; and the stream used one transfer at a time, which drops samples continuously while the spectrum still looks healthy.

Two things are reported rather than enforced. The loop's lock bit is unreliable on several of the clones this is most likely to meet, so a failure to lock is said plainly and does not block streaming: if nothing decodes, it is the first thing to suspect. And the intermediate frequency filter is not calibrated, which for a 2.4 MHz window inside a filter built for 6 is a comfortable margin rather than a shortcut. Needs a served page, and on Windows the dongle needs the WinUSB driver. The frequency comes from the Band station; a dongle is retuned by stopping and claiming it again.

The gain field defaulted to zero until v1.8.2, and its label said zero meant automatic. That was true while there was an automatic path. There is not one now, so zero meant the lowest gain the tuner has, and a dongle set that way sitting on top of a meter hears a transmission barely above its own noise floor. If the last version framed nothing at all, this is the first thing to change.

Record what the dongle is actually delivering

This is the fastest way to stop guessing. It keeps the raw bytes exactly as they arrive off the endpoint and writes them out as a .cu8 file, the same format rtl_sdr produces. Nothing is interpreted on the way: no correlator, no protocol, no gate. Send that file to someone who can look at the spectrum in it and the question of whether there is a meter in your air stops being a matter of opinion.

Find the sample rate

Everything downstream assumes it knows how many samples make a chip, and if that number is wrong by one, the whole chain produces nothing at all. Measured on the reference implementation's own capture: chip length 78 yields nine frames that satisfy the checksum, and 77 or 79 yield zero. Not fewer, zero. A rate assumption is a cliff rather than a tuning knob.

Two steps, and the second is what makes it honest. An amplitude keyed Manchester burst puts a strong line in its envelope at the bit rate, so one peak in a band-limited spectrum estimates the chip length. Then it decodes at that estimate and its neighbours and counts what survives a checksum that can be believed. The estimate is a guess; the count is evidence, and nothing is claimed on the strength of the guess.

Estimated from the envelope
-
How clear that line is
-
Blocks watched
0
Samples per chipSample rateFramedSurvived a checksum
Not looked yet.

Sweep the whole band

One dwell sees 2.4 MHz. The band these meters live in runs 902 to 928 MHz, so a single look covers about a tenth of it, and 912.6 is only where one popular tool points by default rather than where the traffic is confined. A sweep dwells, retunes, dwells, and builds a picture of the whole thing. At each stop it runs the detector that assumes no protocol, no preamble and no chip rate, then judges what it found on the one thing measured here that a frame cannot fake: how long it lasts. Width is shown in the table but is not used to rule anything in or out, because three attempts at measuring occupied bandwidth have each been wrong in one direction or the other, and a discriminator that is wrong both ways is worse than none.

-

Sweep
idle
Listening at
-
Transmissions found
0
MHzFoundMedian lengthWidthLoudestRight length for
No sweep run yet.

Is anything there at all

Everything else on this bench assumes a protocol, a preamble and a field map. This assumes none of them: it reports what the samples themselves say. A screen with no meters on it and a receiver that is not hearing anything look identical from the outside and want opposite responses, so they need telling apart.

Front end
-
-
Noise floor
-
-
Clipping
-
Transmissions found, nothing assumed
-
Best match seen
-
-
Best contrast seen
-

rtl_tcp over a websocket UNPROVEN

If rtl_tcp already runs somewhere on your network, this reads its stream. rtl_tcp speaks plain TCP, so a one line relay is needed in between. The README carries the command. This is a companion, never load bearing.

What is running

Source
idle
Sample rate
-
Samples seen
0
Frames framed
0
Checksum pass
-
Keeping up
-
-
Cost per block
-
-

A browser tab has to keep up with the dongle in real time or it starts throwing samples away, and a decoder that is quietly falling behind looks exactly like a quiet neighbourhood. So the cost of every block is measured and the verdict is stated plainly. When the arithmetic runs long the drawing gets thinned out first, which is said rather than done silently.

About Curbstop

Name
CURBSTOP
Series
Field Instruments, FI-173
Version
1.20.0
Licence
GPL-3.0

A bench for finding, identifying and proving an automatic meter reading signal, and for emitting the configuration a daemon needs to read it unattended.

It is not a daemon. A browser tab closes, sleeps, and gets throttled in the background. For a reading every minute forever, run rtlamr2mqtt on something that stays awake. This instrument exists for the part of the job that happens once, at the bench, with a person watching.

Standing on: the protocol work in rtlamr by bemasher, and the daemon and Home Assistant integration in rtlamr2mqtt by allangood. Neither project's code is included here. Every reader, checksum, demodulator and the MQTT client are written from scratch in this file.

Embedded assets: none. Every mark on the screen is CSS or canvas drawn in this file. No fonts, images or sounds are shipped, so the asset budget is zero bytes.

Known limits in 1.0.0: the websocket relay path is written but unproven. The WebUSB path was corrected after a real dongle refused its first demodulator write, and is now checked against a model of the chip, but has not yet streamed samples end to end. Field offsets for IDM, NetIDM and R900 are unconfirmed and their checksums are advisory. There is no continuous background operation.

Receiving these transmissions is passive. Publishing your neighbours' consumption is a different act from receiving it, and this instrument is built to make the second one difficult on purpose.

Feedback, and the thing that keeps the series going: buymeacoffee.com/mbparks

Self test