September 12, 2019

Last year my city began installing Neptune E-Coder smart water meters with R900 meter interface units. I was excited because I had a spare software-defined radio that I could put to use. I was also excited because I’m a nerd.

I wasn’t a Home Assistant user at the time. I set up rtlamr, inserted readings into InfluxDB, set up graphs in Grafana, and called it a day.

Well, I recently started using Home Assistant, so I’ve been searching for a way to integrate my meter. I’m going to cover two easy methods of getting rtlamr output into Home Assistant. I’m working with a water meter but these should be adaptable to gas and electric smart meters as well.

Requirements

Compatible smart meter

RTL2832U-based software-defined radio warning: affiliate link

A computer. I’m using Raspbian Buster on a Raspberry Pi 4, but any Linux, macOS, or Windows PC should work

Install dependencies

You need rtl-sdr , golang , git , and jq . You will find these in your package manager on Linux or Homebrew on macOS.

Find your meter interface unit ID

You need to locate your water meter’s 10-digit MIU ID. Your SDR will also pick up your neighbors meters and you will use your ID to filter them out. My MIU ID is printed on a label affixed to the R900 unit outside.

If you are unable to find your ID take a manual reading, run rtlamr without a filter, and get the ID from a transmission with a matching consumption value.

jq to the rescue

Here is a sample of rtlamr’s JSON output:

{ "Time": "2019-09-12T10:04:40.940874822-05:00", "Offset": 0, "Length": 0, "Type": "R900", "Message": { "ID": 1499285123, "Unkn1": 163, "NoUse": 32, "BackFlow": 0, "Consumption": 915521, "Unkn3": 0, "Leak": 0, "LeakNow": 0 } }

Unfortunately Home Assistant can only extract top level json_attributes from a sensor. If your JSON includes children then you have to create template sensors to access these values.

You can avoid template sensors by piping the JSON through jq to move all of the Message elements to the top level:

jq '. |= del(.Message) + .Message'

Option 1: Command line sensor

If you connected your SDR to your Home Assistant machine, and you are not running Home Assistant with Docker, then you can set up a command line sensor.

Download rtlamr and start rtl_tcp :

GOPATH=${HOME} go get github.com/bemasher/rtlamr sudo rtl_tcp &

Add the sensor to your Home Assistant configuration, making sure you plug in your MIU ID:

sensor: - platform: command_line name: neptune command: ${HOME}/bin/rtlamr -msgtype=r900 -format=json -single -duration=1m -filterid=YOUR_MIU_ID | jq -c '. |= del(.Message) + .Message' command_timeout: 45 value_template: '{{ value_json.Consumption | float / 10 }}' unit_of_measurement: 'gal' json_attributes: - Time - BackFlow - Consumption - Leak - LeakNow

Your water meter emits readings periodically, and rtlamr will block until it gets one. Your Home Assistant log is going to fill up with warnings that this sensor is taking longer than 10 seconds.

Option 2: RESTful sensor

If your SDR is not connected to your Home Assistant machine, or you are running Home Assistant with Docker, then you can use stdout_httpd with a RESTful sensor. stdout_httpd is a simple program I wrote to serve the last line of standard output over HTTP.

Start rtl_tcp , rtlamr , and stdout_httpd , making sure you plug in your MIU ID:

sudo rtl_tcp & GOPATH=$(pwd) go get \ github.com/bemasher/rtlamr \ github.com/abaker/stdout_httpd bin/rtlamr -msgtype=r900 -format=json -filterid=YOUR_MIU_ID | jq --unbuffered -c '. |= del(.Message) + .Message' | bin/stdout_httpd -port 8080

Add the sensor to your Home Assistant configuration:

sensor: - platform: rest name: neptune resource: http://your-sdr-host:8080 force_update: true value_template: '{{ value_json.Consumption | float / 10 }}' unit_of_measurement: 'gal' json_attributes: - Time - BackFlow - Consumption - Leak - LeakNow

That’s it!

Restart Home Assistant to check out your new sensor. You can detect leaks and backflow using sensor attributes.

If you had any trouble setting this up leave a comment below and I’ll try to help out