Open-source project
bemasher/rtlamr avatar
bemasher/rtlamr

rtlamr: decoding Itron ERT smart meters with an rtl-sdr dongle

An rtl-sdr receiver for Itron ERT compatible smart meters operating in the 900MHz ISM band.

2,546 stars276 forksGoAGPL-3.0

At a glance

What is it?
rtlamr is a Go receiver that turns an inexpensive rtl-sdr dongle into a decoder for Itron ERT and Neptune R900 meter transmissions in the 900MHz ISM band. It is a command-line tool for people who want their own consumption data without asking the utility for it.
Who is it for?
Adopt rtlamr if you already own an rtl-sdr dongle, your meter appears in meters.md, and you are comfortable running rtl_tcp as a separate process on the same machine or across the network. Do not adopt it if you need a supported, warrantied data path for billing disputes, or if your meter is one of the many ERT-capable models the project lists as unverified.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 68 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: your meter already broadcasts, you just cannot read it

Utilities deploy smart meters so that a reader driving through a neighborhood can collect consumption data over the air. Itron's Encoder Receiver Transmitter protocol, or ERT, is one of the simpler ones: it runs in the 900MHz ISM band, which sits inside the tuning range of cheap rtl-sdr dongles. The data is already leaving your house. What is missing is a receiver.

rtlamr is that receiver. It is written in Go and targets people who want to non-invasively record and analyze their own household consumption, per the README's description of the project's purpose. The audience is narrow and technical: you need an rtl-sdr dongle, a machine to run it on, and enough patience to match your meter against a compatibility list before you spend an evening on it.

The README's use cases are telling. Tracking down a stray appliance, comparing power generated against power consumed, finding a water leak before the bill arrives, and feeding a thermostat are all listed as ethical uses. Mass collection for research is allowed with the explicit request to anonymize the data. The same section names the unethical case directly: determining the living patterns of specific people without their permission. That framing matters because the tool cannot distinguish your meter from your neighbor's. It decodes whatever it hears.

How rtlamr works: rtl_tcp feeds a Go decoder over a socket

rtlamr does not talk to the USB dongle itself. The README's usage section shows the split: you start rtl_tcp, a separate program from the Osmocom rtl-sdr project, and then start rtlamr. rtl_tcp owns the hardware and exposes the sample stream on a TCP socket. rtlamr connects to that socket, demodulates, and prints decoded messages.

That architecture has a practical consequence. If the spectrum server runs on a different machine than the receiver, the README says you specify an address with the -a flag for rtl_tcp and the -server flag for rtlamr. This is what makes a Raspberry Pi next to a window with the dongle, and a laptop elsewhere, a workable arrangement.

The repository layout mirrors the protocol families. There are separate top-level directories for scm, scmplus, idm, netidm, r900, and r900bcd, plus a crc package and a protocol package. The Go module declares only two direct dependencies: github.com/bemasher/rtltcp for the socket client and golang.org/x/xerrors. The Go version in go.mod is 1.21.

Message types differ in what they carry. SCM is a simple packet reporting total consumption. SCM+ allows greater precision and longer meter IDs. IDM provides differential consumption for the previous 47 intervals at five minutes each. netidm handles net meters, whose type 8 packets have a different internal structure, interval count and precision, and it reports total power production. r900 and r900bcd cover Neptune R900 transmitters, which report total consumption and leak flags, with r900bcd for meters that encode consumption as binary-coded digits.

The README notes a v0.9.0 release titled Concurrent Multi-Protocol Decoding, which is consistent with a design where several protocol decoders run at once rather than one being selected.

Installing rtlamr and getting a first decode

You need two things before rtlamr is useful: a Go toolchain of at least 1.21, and a working rtl-sdr installation. The README points Windows users at pre-built rtl-sdr binaries from the Osmocom FTP server and Linux users at source and build instructions on the SDR Osmocom site. Install that first and confirm the dongle is recognized.

The Go install command is a single line. It places the binary in $HOME/go/bin, or in $GOPATH/bin when GOPATH is set.

bash
go install github.com/bemasher/rtlamr@latest

For Go versions older than 1.16 the README gives the older form, go get github.com/bemasher/rtlamr. Either way the binary has to be on your PATH to run it from any directory.

Running the receiver takes two terminals. The first starts the spectrum server, which holds the dongle and listens for connections.

bash
rtl_tcp

The second starts the decoder, which connects to that socket and prints messages as they arrive.

bash
rtlamr

When it works you see decoded packets scroll past, and the README's animated capture shows an ERT message being received. The README refers to a wiki page titled Configuration for the full set of options, and flags.go in the repository is where those flags are declared. The README itself only documents -a for rtl_tcp and -server for rtlamr, so plan on reading the wiki rather than the README for anything beyond the default invocation.

One thing to sort out before you start: your meter's identity. The README says to look for an FCC ID label on the meter, which should identify the two-digit commodity or endpoint type and the eight- or ten-digit endpoint ID, formatted as two digits, a space, eight digits, and an optional two more. Once rtlamr is printing, that ID is how you find your own meter in the stream.

Sensitivity is the real ceiling, and the README is honest about it

The most useful number in the README is not a throughput figure. Using a NooElec NESDR Nano R820T with the supplied antenna, the author reports reliable reception from roughly 300 meters and intermittent reception from another 600, measured over a 25 minute window. Reliable is defined as at least 10 of the expected 12 messages; intermittent is 3 to 9.

Read that carefully. Even in the author's own setup, most of the meters heard were not heard reliably. Antenna placement, the dongle's tuner, and the gain setting all move that boundary, and the README does not give a tuning procedure beyond pointing at the wiki's configuration page. If your meter is at the edge of reception, you will get gaps in the interval data, and IDM's 47 five-minute intervals will have holes in them.

The compatibility picture is the second constraint. The README states that the only tested meters are the Itron C1SR and Itron 40G. It then says the protocol is designed to be useful across commodities and should work with any ERT-capable meter, and links a meters.md table compiled from internet sources plus a user-provided Google Sheets list that the README itself labels unverified. Should is doing a lot of work in that sentence. If your meter is not one of the two tested models, you are relying on someone else's spreadsheet.

A third limitation is structural: rtlamr is a receiver, not a data store. The README points to rtlamr-collect for data collection and aggregation and describes that support as experimental. If you want history, dashboards or long-term records, rtlamr alone produces a stream on stdout and nothing more.

Where rtlamr sits next to rtlamr-collect and a plain rtl-sdr setup

The closest thing to an alternative inside this project's own ecosystem is rtlamr-collect, which the README describes as experimental support for data collection and aggregation. The division of labour is clean: rtlamr decodes, rtlamr-collect persists and aggregates. If your goal is a database of readings rather than a terminal window, running only rtlamr is solving half the problem.

The other comparison is against using rtl-sdr tooling directly. A general SDR workflow gives you raw IQ samples and a waterfall, and you can look at the 900MHz band, find bursts, and inspect them. What it does not give you is a parser for the ERT packet structure, the CRC handling in the crc package, or the per-protocol field layouts in scm, idm, netidm, r900 and r900bcd. That decoding layer is the entire value of rtlamr. The trade-off is that you inherit its compatibility assumptions: it decodes the protocols it knows, and anything else in the band is just noise to it.

There is also a licensing difference worth naming. rtlamr is AGPL-3.0, which is a stronger copyleft than the permissive licences common in SDR tooling. If you wrap rtlamr in a network service, the licence's network-use clause applies.

Licence, maintenance and the cost of upgrading

rtlamr is licensed under Affero GPL v3.0. The README reproduces the summary from choosealicense.com: you must disclose source when distributing, include the licence and copyright notice, indicate significant changes, and, under the network-use clause, give users who interact with the software over a network the right to receive the corresponding source. Commercial use, distribution, modification, patent grant and private use are all permitted. Sublicensing is not, and the software carries no warranty. That last point is the one to weigh if you are building anything operational on top of it. This is a description of the licence text, not legal advice; read the LICENSE file in the repository for the binding terms.

On maintenance, the release history is uneven. v0.9.0 and v0.9.1 both landed in September 2018, and v0.9.1 was titled Fix R900 Decoder and New Release Tool. Then there is a long gap to v0.9.5 on 2026-04-25, and the last push to the repository was on 2026-07-25. The repository is not archived. The dependency set is small, which keeps upgrade cost low: rtltcp and xerrors, with Go 1.21 as the floor in go.mod. A user tracking the project mainly needs to watch the Go version requirement and the rtltcp pin, not a large tree of transitive dependencies.

The upgrade risk that matters is behavioural rather than mechanical. The R900 decoder was fixed once already in v0.9.1, so anyone depending on Neptune R900 output should re-check decoded values after moving versions rather than assuming the packet format handling is stable.

What to verify before you commit an evening to it

Start with the meter, not the software. Find the FCC ID label, read the two-digit commodity or endpoint type and the endpoint ID, and check that model against meters.md. If it is not the Itron C1SR or Itron 40G, treat the result as unverified until you see your own endpoint ID in the output.

Then confirm the plumbing. rtl_tcp must be running and reachable; if the dongle is on another machine, the -a and -server flags are what connect the two halves, and a firewall between them will look exactly like a decoder that finds nothing. The README does not document rollback or a diagnostic mode for a silent receiver, so the fastest check is whether rtl_tcp itself is serving samples.

Finally, decide what you are doing with the data. If you want history, rtlamr-collect is the project's own answer and the README calls that support experimental. If you want a one-off reading of total consumption, SCM output on stdout is enough. If you want interval-level detail for a home energy project, you need IDM to decode reliably, which puts you back at the sensitivity ceiling the README quantifies.

Editorial conclusion

Adopt rtlamr if you already own an rtl-sdr dongle, your meter appears in meters.md, and you are comfortable running rtl_tcp as a separate process on the same machine or across the network. Do not adopt it if you need a supported, warrantied data path for billing disputes, or if your meter is one of the many ERT-capable models the project lists as unverified. Before anything else, check the FCC ID label on your meter against the two-digit commodity or endpoint type and the eight- or ten-digit endpoint ID format the README describes, then confirm that rtlamr prints your endpoint ID at all.

Frequently asked questions

What can rtlamr be used for?

The README lists tracking down stray appliances, comparing power generated against power consumed, finding a water leak before the bill arrives, optimizing a thermostat, and mass collection for research with anonymized data. It also states plainly that using collected data to determine the living patterns of specific people without permission is unethical.

Which meters does rtlamr support?

The README says the only tested meters are the Itron C1SR and Itron 40G, while the protocol is designed to work with any ERT-capable meter. It links a compiled meters.md table and a user-provided spreadsheet that the README describes as unverified.

What message types can rtlamr decode?

SCM, SCM+, IDM, netidm, r900 and r900bcd. SCM reports total consumption, IDM provides differential data for 47 five-minute intervals, netidm handles net meters and reports total power production, and the two R900 types cover Neptune transmitters including leak flags.

Does rtlamr talk to the rtl-sdr dongle directly?

No. You start an rtl_tcp instance, which owns the hardware and serves the sample stream, and then start rtlamr, which connects to it. If the two run on different machines, the README says to use the -a flag for rtl_tcp and the -server flag for rtlamr.

How does rtlamr store or aggregate the data it receives?

It does not. The README points to rtlamr-collect for data collection and aggregation and describes that support as experimental, so rtlamr on its own produces a decoded stream rather than a persistent record.

Official sources

  1. bemasher/rtlamr on GitHub
  2. Issues
  3. License: AGPL-3.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bemasher-rtlamr.svg)](https://hysenlabs.com/projects/bemasher-rtlamr)