Instrumenting Utilities Usage

I’ve been working on a side project to help track utilities usage around my house, to help us conserve water and electricity and quantify how much we are using on a day-by-day basis. Since our water/power companies’ smart meters broadcast their usage stats unencrypted on ~900MHz, we can use a program to decode their packets using a software-defined radio. There’s a project on github https://github.com/bemasher/rtlamr which has most of this functionality already written. We just need a way to pipe those numbers into a dashboard to view.

Process

First, I installed prometheus and Grafana on a Raspberry PI. I’m not going to detail those steps here - but I installed prometheus via the raspbian apt package manager, and grafana after adding it’s repository.

I wrote a script available on my github (https://github.com/richinfante/powermeter), which manages the rtl_tcp and rtlamr processes and writes a file for prometheus.

Tweaks

If using a raspberry pi (as I did), customization may be required. If running the scripts prints a lot of messages like ll+ now ${number}, try editing the script to call rtl-amr with a different set of arguments. Changing the msgtype to scm,r900 (or limit to the specific protocols you need for your meters), can reduce the amount of processing needed to reliable parse messages. Some people have had success with changing the symbol length.

On my raspberry pi 4 (4gb ram), the following code works for my electric and water:

# edit this line inside the powermeter.py file to customize the protocols you want to recieve
self.amr_proc = subprocess.Popen(
  ["rtlamr", "-format=json", '--msgtype=scm,r900'],
  stdout=subprocess.PIPE
)

I was able to get a Pi 3B+ to run the powermeter scipt, but only with the SCM protocol enabled.

Grafana charts

It’s out of scope for this post, but it’s relatively easy to set up some nice visualizations in Grafana once the data is flowing:

water graph

Then, we can use a query inside grafana in order to read the meter’s contents. Mine is off by a factor of 100, so I divide to get the actual usage in cubic feet:

meter_consumption{meter_id="METER_ID_HERE"} / 100

Change Log

  • 2021-08-10 - Initial Revision

Found a typo or technical problem? file an issue!