Get your smart electric, water and gas meter scm readings into home assistant with a RTL-SDR

Damn, looks like my electricity meter is using the cell phone network to send back data (itron centron c1sx)

Check your meter and RTL-SDR reading, wait a while, and then check both again. See how much the reading changed and then you can determine the conversion.

Mine I think I have to divide by 100 to convert the meterā€™s RF reading into kWh to match the dial on the front.

Range will depend on local RF interference, the power the meter is sending, and what type of antenna you are using to pick it up (what frequency itā€™s tuned for). I typically pick up a few neighbors meters a couple hundred feet away with my RTLSDR (I think itā€™s a v1 or v2) and the crappy couple inch antenna it came with.

If you live near any AM/FM broadcast towers, you may want to buy the appropriate AM or FM band block filters to reduce the noise floor and prevent the receiver from being overloaded by strong signals. This will help it hear the weaker signals better.

If itā€™s still struggling, you could get a directional antenna (such as a Yagi) that is designed for the frequency you need to receive (probably 900MHz for power meters) and point it in the direction of the meter. This will be more sensitive to signals the direction itā€™s aimed and less sensitive to signals to the sides and behind it.

Given the low cost of these SDRs, I would almost suggest get one and try using the rtlamr app on a laptop or something and carry it around to see how it does.

Cool, I should be Ok then most likely. My gas meter is about 2 floors away from my Home Assistant away. My electrical meter looks like a non starter anyways, as it seems (from what I can see) to report readings by cell network. Iā€™m on a well so no water meter.

Yeah, just donā€™t put the antenna inside a metal rack or anything that will really shield it. Mine is doing fine in my basement below-grade with the antenna stuck on top of my 42U enclosure and I still pick up at least a few neighbors meters Iā€™m guessing are probably 100 feet away.

Only thing I have to watch is my metal roofā€¦ my home assistant box lives at the top of my house, basically right at the roof line (compromise between ability to get cellular internet and good wifi coverage for the house)

Actually as these meters typically use 900MHz and cellular is often +/- 200MHz from that, phone signal may be a good measurement of how well it could work now that I think of itā€¦

Any idea the specs required for the machine to run this? I was planning to run this on my home assistant box, but of course no apt on home assistantā€¦ (thinking about a pi 0)

Started playing with last nightā€¦ I can see two meters my house, neither of which matches my meters when in comes to consumption or ID numbers. Kind of weird because the closest house is about 400m away through dense treesā€¦

Saga continuesā€¦ I think Iā€™ve got my gas meter (none of the ids or use lines up but the values on the meter and values in the software show a linear relationship), looks like some unit differences, and a 0 offset, but canā€™t really tell whyā€¦

This solution is great, and Iā€™m delighted that itā€™s available as an Add-On. Everythingā€™s running delightfully, except mosquitto_pub. This is my first ever mosquitto install, so itā€™s equally possible the issue is with mosquitto and not RTLAMR2MQQT.

  • When my RTLAMR2MQQT configuration uses mqtt_host: localhost it results in error Error: Address not available
  • When mqtt_host: hassio.local it results in error Unable to connect (Lookup error.).
  • When mqtt_host: 127.0.0.1 it results in error Error: Connection refused
  • Interestingly, when I run the same command from SSH as root, it succeeds.
    docker exec addon_d9cf98df_rtlamr echo 4 | /usr/bin/mosquitto_pub -h 127.0.0.1 -u mqtt -P MYPASSWORD -i RTL_433 -r -l -t readings/56572016/meter_reading
    ā€¦results in the Home Assistant sensor successfully updating.

My hunch is that it has to do with the rtlamr docker container effectively using the network. Has anybody overcome similar challenges?

Configuration:

mqtt_host: 127.0.0.1
mqtt_user: mqtt
mqtt_password: MYPASSWORD
msgType: scm
ids: '56572016,28512779'

Hmm, that is weird that it works in the docker container via the command line.

Can you use the actual IP address of your home assistant install? 192.168.xx.xx (or whatever you use). That is what I use.

1 Like

Awesome. That worked immediately. Thank you so much!

So Iā€™ve successfully added a meter to Home Assistant using my laptop to run the rtl-sdr. Obviously not ideal, but as a proof of concept, not horrible.

Still not sure what meter Iā€™m actually looking at, Iā€™m assuming gas, and Iā€™m assuming its mine, but the numbers certainly donā€™t line up to anything I recognize. Plotting them does look like a linear transformation relative to my meter. (Roughly 1/3 of reported value+offset = my reading)

It takes some trial and error. Usually the ID is printed on the meter somewhere, so check that they correspond. In my area, gas meters only update when the truck drives by because they are battery powered. Electric meters constantly report. A sdr will pull in meters a block away (or even farther), so it may not be yours.

Closest meter that isnā€™t mine is maybe 400m away, through a bunch of treesā€¦

Has anyone successfully collected data from an Itron 100GDLS gas meter? Itā€™s not on the rtl-amr csv of compatible devices - but the 100G and 100GDLAN are listed - and the frequencies are 910-920, so I thought it might pick it up.

1 Like

In my SCM+ messages, the fields are different. I think this will work but I donā€™t know if SCM+ is universal.

#!/usr/bin/env python3
'''
Runs rtlamr to watch for IDM broadcasts from power meter. If meter id
is in the list, usage is sent to 'readings/{meter id}/meter_reading'
topic on the MQTT broker specified in settings.

WATCHED_METERS = A Python list indicating those meter IDs to record and post.
MQTT_HOST = String containing the MQTT server address.
MQTT_PORT = An int containing the port the MQTT server is active on.

'''
import subprocess
import signal
import sys
import time
import paho.mqtt.publish as publish
import settings

# uses signal to shutdown and hard kill opened processes and self
def shutdown(signum, frame):
    subprocess.call('/usr/bin/pkill -9 rtlamr', shell=True)
    subprocess.call('/usr/bin/pkill -9 rtl_tcp', shell=True)
    subprocess.call('/usr/bin/pkill -9 amridm2mqtt', shell=True)
    sys.exit(0)

signal.signal(signal.SIGTERM, shutdown)
signal.signal(signal.SIGINT, shutdown)

auth = None

if len(settings.MQTT_USER) and len(settings.MQTT_PASSWORD):
        auth = {'username':settings.MQTT_USER, 'password':settings.MQTT_PASSWORD}

def send_mqtt(topic, payload,):
    try:
        publish.single(topic, payload=payload, qos=1, hostname=settings.MQTT_HOST, port=settings.MQTT_PORT, auth=auth)
    except Exception as ex:
        print("MQTT Publish Failed: " + str(ex))

time.sleep(5)

# start the rtl_tcp program
rtltcp = subprocess.Popen([settings.RTL_TCP + " > /dev/null 2>&1 &"], shell=True,
    stdin=None, stdout=None, stderr=None, close_fds=True)

# Wait a little as sometimes rtl_tcp takes some time to start
time.sleep(5)

# Use the WATCHED_METERS from settings.py for -filterid in rtlamr
filterids = ','.join([str(elem) for elem in settings.WATCHED_METERS])

# start the rtlamr program
rtlamr = subprocess.Popen([settings.RTLAMR,
    '-msgtype=scm,scm+',
    '-format=csv',
    '-filterid='+filterids],
    stdout=subprocess.PIPE)

while True:

    try:
        # rtlamr's readline returns byte list, remove whitespace and convert to string
        amrline = rtlamr.stdout.readline().strip().decode()
        # split string on commas
        flds = amrline.split(',')
        length = int(len(flds))
        # Set meter_id and value from message depending on type
        # For SCM+
        if length == 10:
            meter_id = int(flds[6])
            read_cur = int(flds[7])
        # For SCM
        elif length == 9:
            meter_id = int(flds[3])
            read_cur = int(flds[7])
        else:
            continue

        current_reading_in_kwh = (read_cur * settings.WH_MULTIPLIER) / 1000

        send_mqtt(
            'readings/' + str(meter_id) + '/meter_reading',
            '%s' % (current_reading_in_kwh)
        )

    except:
        time.sleep(2)

Honestly reading through the code (not a great coder btw) it still needs work and there are a lot of things that could be done to make it more robustā€¦ I didnā€™t like the other solution that just uses bash and jq. Will have to look into it later (probably never) if I have time

Also note for some having issues with power, mine at least only broadcasts scm+ messages so that may be why (or your meter isnā€™t supported).

1 Like

@biochemguy, Iā€™m having a hard time with your stats templates, not sure what Iā€™m doing wrongā€¦

2021-03-02 22:46:43 ERROR (MainThread) [homeassistant.helpers.event] Error while processing template: Template("{% if states.sensor.gas_stats_mean.attributes.min_value | float == 0 %}0 {% elif states.sensor.gas_meter.state | float <= states.sensor.gas_stats_mean.attributes.min_value | float %}0 {% else %} {{((states.sensor.gas_meter.state | float) - (states.sensor.gas_stats_mean.attributes.min_value | float)) * 1000 / 10 | max (0) | round(2) }} {% endif %}")
Traceback (most recent call last):
  File "/root/homeassistant/lib/python3.8/site-packages/homeassistant/helpers/template.py", line 353, in async_render
    render_result = compiled.render(kwargs)
  File "/root/homeassistant/lib/python3.8/site-packages/jinja2/environment.py", line 1090, in render
    self.environment.handle_exception()
  File "/root/homeassistant/lib/python3.8/site-packages/jinja2/environment.py", line 832, in handle_exception
    reraise(*rewrite_traceback_stack(source=source))
  File "/root/homeassistant/lib/python3.8/site-packages/jinja2/_compat.py", line 28, in reraise
    raise value.with_traceback(tb)
  File "<template>", line 1, in top-level template code
  File "/root/homeassistant/lib/python3.8/site-packages/jinja2/sandbox.py", line 407, in getattr
    value = getattr(obj, attribute)
jinja2.exceptions.UndefinedError: 'None' has no attribute 'attributes'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/root/homeassistant/lib/python3.8/site-packages/homeassistant/helpers/template.py", line 462, in async_render_to_info
    render_info._result = self.async_render(variables, **kwargs)
  File "/root/homeassistant/lib/python3.8/site-packages/homeassistant/helpers/template.py", line 355, in async_render
    raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: UndefinedError: 'None' has no attribute 'attributes'

Itā€™s been a while since I had played with this template. Can you confirm that you are getting your readings into homeassistant, and that the statistics are working? It seems as the template is not seeing the numbers as you are getting ā€˜noneā€™ as a value instead of a number.