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

Do you have one of the OpenWay Itron meters? I have been able to pickup consumption off these newer Xcel smart meters using RTLAMR. I had to scan all SCM and SCM+ signals and find the new meter ID when Xcel swapped mine out. The endpoint type I found for my meters was 110 which was very different from the supported meter list so I recommend just scanning by protocol and comparing consumption from what you see on your meter display plus trying to match a meter ID to a number on your unit.

1 Like

Hi @MacGyver33 ā€“

Mine is Itron Gen5 Riva (model G5R1).

I ran ā€˜rtlamr -msgtype=scm,scm+ -unique=trueā€™ and output is as follows:

{Time:2021-12-18T18:19:30.770 SCM:{ID:XXX Type: 7 Tamper:{Phy:02 Enc:01} Consumption: 3674303 CRC:0xFE96}}
{Time:2021-12-18T18:19:30.831 SCM:{ID:XXX Type: 5 Tamper:{Phy:01 Enc:01} Consumption: 1030964 CRC:0x6BFA}}

Iā€™m not seeing any Typeā€™s other than 5, 7, 12 (and a few Endpoint Type:0x07 & 0x6E) but nothing seems to tie out to whatā€™s listed on the display. Any thoughts? Thanks

What are the differences between the one posted previously: GitHub - jdeath/RTLAMR2MQQT

And this one below?

Your meter sends a different attribute for the meter reading, you are showing consumption_data instead of Consumption which is what my meter reports.

Youā€™ll need to use a different value template parser to get the reading.

For example:

value_template: "{{ value_json.Message.consumption_data | float }}"

Note that I have not used either of these 2 projects, but upon reviewing the code, I think the following is correct:

  • The allangood project is designed for using a manually set-up SDR, probably on a completely separate installation running on a separate computer. This one is more flexible but requires more set-up to work correctly.
  • The jdeath one is for people who are running HASSIO and want to plug the SDR dongle directly into the computer that runs HASS. This is nice because then you have less setup to do. The downside is that you might run into performance issues since the RTL-SDR reciever, decoder and parser is running on the same machine that you also have HASSIO running on.
2 Likes

Did you ever get this working? I have the same meter (gas company just swapped out my old, working meter with this one :frowning: )
I think it may only send when it gets a signal to broadcast (per the gas company guy I spoke toā€¦)

after reading this, bought a RPi 4 and SDR radio to mqtt the data into HA.

it seems the original nano SDR that @biochemguy references is not avialalble anymore (just the 2 is), so I got their mini version 2+, hopefully it works the sameā€¦I guess I will find out in a few days

hi!

Finally put all my stuff together using my nano SDR and RPi4 and follwed the instructions step-by-step (copy-paste), no errors during install.

I placed my mqtt local broker IP, in the settings file (left everything else defauly), but when i check if the service runs, I gete some errors here:

any idea what this means and what permissions its asking for?

pi@raspberrypi:~ $ sudo service amridm2mqtt status
ā— amridm2mqtt.service - AMR IDM to MQTT
     Loaded: loaded (/etc/systemd/system/amridm2mqtt.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Fri 2022-05-06 13:25:36 MDT; 1min 13s ago
    Process: 483 ExecStart=/opt/amridm2mqtt/amrscm2mqtt (code=exited, status=203/EXEC)
   Main PID: 483 (code=exited, status=203/EXEC)
        CPU: 7ms

May 06 13:25:36 raspberrypi systemd[1]: Started AMR IDM to MQTT.
May 06 13:25:36 raspberrypi systemd[483]: amridm2mqtt.service: Failed to locate executable /opt/amridm2mqtt/amrscm2mqtt: Permission denied
May 06 13:25:36 raspberrypi systemd[483]: amridm2mqtt.service: Failed at step EXEC spawning /opt/amridm2mqtt/amrscm2mqtt: Permission denied
May 06 13:25:36 raspberrypi systemd[1]: amridm2mqtt.service: Main process exited, code=exited, status=203/EXEC
May 06 13:25:36 raspberrypi systemd[1]: amridm2mqtt.service: Failed with result 'exit-code'.

hi again,

just wanted to provide a quick update, when I open two terminals and in the first one run rtl_tcp and in the other run rtlamr, and it started no problem reading a couple of meters but the IDs didā€™t make sense to me. Then I realized that the default is only to see SCM mesages, so I ran it again this time with:

rtlamr -msgtype=all

and boom, several hundred meters showed up, including my water and gas meter which are both SCM+.

so it works awesome this way!

But im still having those issues above, where it wonā€™t start the mqtt service to dump this data to HA via a local broker.

Any advice here would be greatly appreciated.

I used the instructions and code from the OP posts @biochemguy but there are other contributions from @adamg. Is the OPs post, the latest and working code for this? thanks for your help

any chance are you in california?

Finally got this working!

I had to modify the systemmd file and used the SCM+ script provided by @Meeseeks.

I have my gas meter AND water meter sending to mqtt, but it seems the water number is not updating, it just sent the first number and hasnt changed in over 18 hrs. Its a 5 digit value (as opposed to 6 digit), and endpoint type is 0xAB as opposed to 0x9C. I donā€™t know if this information is relevent, but the gas meter is working and updating perfectly.

When I was running just the ā€˜rtl_tcpā€™ and ā€˜rtlamr -msgtype=scm+ā€™, the water meter updates with the value on the meter, so im wondering if the scripts just needs some tweeks for my water meter, which is model Itron 100WR Water 11

Any idea if the scripts needs to be modified for my water meter? It just seems to report the first value on start-up then doesnā€™t update.

#!/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)

EDIT. ok I think if found the problem. It does update, BUT seems to update every 1000 Lā€¦yikes!

EDIT #2: @david1 I donā€™t know if that question was referred to me, but no, I donā€™t live in California now.

EDIT #3: upon closer inspection itā€™s actually 100L not 1,000L okay thatā€™s better. Okay this is working exactly as it should. Thank you very much everybody for sharing all your experiences and codes!

1 Like

could you share your gas meter model/make?

@david1 the natural gas meter I have has the Ltron 12 100G DLS data logging ert.

what channel did you have to turn your rtl to?

@david1

When you run rtlamr, type this

rtlamr -msgtype=all

Then you should be able to see a whole bunch of meters and then just look for your ID. Then it should tell you whether itā€™s scm or scm+ or IDM or anything else.

Is that what you mean by Channel? Because I never actually picked a channel, specifically.

Follow the steps in the the OP until install part. Before that it should be working for you, you can see all the metres your antenna picks up.

The rest is just coding it into a service and making it send the data via mqtt

thanks, i might give this another try, I think i have a Elster American AC250

I have an Itron 100W+ water meter and an Itron 100GDL*(canā€™t see the last letter in the picture I took). Iā€™m receiving readings from both every minute which matches the datasheets for the meters that I was able to find. I did have to adjust the center frequency to 922mhz to reliably pick up the water meter transmissions.

The data I get from the gas meter seems like itā€™s updating in real time, when I take a shower and use hot water the water heater starts consuming gas shortly after. This is further corroborated by the spike in humidity in the bathroom. The water meter is less consistent. Last night I ran the sprinklers while watching the physical meter and the mqtt topic and the water use stopped at 7:30pm but the reported value didnā€™t change until 8:18pm. Throughout this I was still getting transmissions every minute. Same thing this morning, shower started at 7:06am and the reading didnā€™t update until 8:09am.

The difference between readings doesnā€™t suggest a minimum change required, Iā€™ve had from 1285gal to 1.4gal and everything in between.

Has anyone run into anything like this? Could it be a signal strength issue? Iā€™m using the rtlamr2mqtt add-on by allangood.

Edit: I figured it out, buried in the Itron 100W+ installation guide is the line " When comparing the actual register value to that reported by the 100W/100W+ and
100WP/100WP+ ERT module, please keep in mind the ERT moduleā€™s consumption value is updated once an hour when it is in a run mode." So the transmitter sends a message out every minute but the value will only update every hour. Iā€™m probably still missing the occasional message which explains the variation in update times.

For the life of me, I canā€™t figure out what I am doing wrong. I have a Pi3B+ running HAOS and a Pi0W running amridm2mqtt. Iā€™m able to see my water meter fine (R900) when running rtl_tcp and rtlamr in two different terminals, but the data isnā€™t be passed to my MQTT Broker running in HA. Iā€™m using MQTT Explorer to monitor the broker and its not showing anything. My MQTT Broker is setup and running fine.

I read through most of this thread and used some of the bug fixes and modifications @biochemguy and @adamg posted. I have hit a wall and would appreciate any help.

Below are the ā€œamridm2mqtt.serviceā€, ā€œamrscm2mqtt.pyā€ and ā€œsettings.pyā€ files.

amridm2mqtt.service

[Unit]
Description=AMR IDM to MQTT
After=network.target

[Service]
ExecStart=/usr/bin/python3 /opt/amridm2mqtt/amrscm2mqtt.py
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=amridm2mqtt

[Install]
WantedBy=multi-user.target

amrscm2mqtt.py

#!/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(30)

# 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)

time.sleep(5)

# start the rtlamr program.
rtlamr = subprocess.Popen([settings.RTLAMR,
    '-msgtype=r900',
    '-format=csv'], stdout=subprocess.PIPE)
#changes msgtype from "scm" to "r900"
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(',')

        if len(flds) != 9:

            # proper SCM results have 9 fields. If SCM+ have more fields, you can adjust this number.
            # proper R900 results have 9 fields.
            continue

        # make sure the meter id is one we want - Change this if the meter ID is in another field.
        #R900 meter ID is in field 2
        meter_id = int(flds[2])
        if len(settings.WATCHED_METERS) and meter_id not in settings.WATCHED_METERS:
            continue

        # get some required info: current meter reading, current interval id, most recent interval - SCM+ Change this if there is more fields in the data
        #R900 consumption data is in field 6
        read_waterusage = int(flds[6])
        #R900 doesn't display decimle, converting to show tenth
        #changed "current_reading_in_kwh" to "current_reading_in_wholenumber"
        #changed multiplier to .1 to show tenth
        current_reading_in_wholenumber = (read_waterusage * settings.WH_MULTIPLIER) / .1

        #changed "current_reading_in_kwh" to "current_reading_in_wholenumber" to match above
        send_mqtt(
            'readings/' + str(meter_id) + '/meter_reading',
            '%s' % (current_reading_in_wholenumber)
        )

    except:
        time.sleep(2)

settings.py

# List of the Meter IDs to watch
# Use empty brackets to read all meters - []
# List may contain only one entry - [12345678]
# or multiple entries - [12345678, 98765432, 12340123]
WATCHED_METERS = [1564077862]

# multiplier to get reading to Watt Hours (Wh)
# examples:
#   for meter providing readings in kWh
#      MULTIPLIER = 1000
#   for meter providing readings in kWh
#   with 2 extra digits of precision
#      MULTIPLIER = 10
# MULTIPLIER needs to be a number
WH_MULTIPLIER = .1

# number of IDM intervals per hour reported by the meter
# examples:
#   for meter providing readings every 5 minutes
#   or 12 times every hour
#     READINGS_PER_HOUR = 12
#   for meter providing readings every 15 minutes
#   or 12 times every hour
#     READINGS_PER_HOUR = 4
READINGS_PER_HOUR = 12

# MQTT Server settings
# MQTT_HOST needs to be a string
# MQTT_PORT needs to be an int
# MQTT_USER needs to be a string
# MQTT_PASSWORD needs to be a string
# If no authentication, leave MQTT_USER and MQTT_PASSWORD empty
MQTT_HOST = '#######'
MQTT_PORT = 1883
MQTT_USER = '#######'
MQTT_PASSWORD = '#######'

# path to rtlamr
RTLAMR = '/usr/local/bin/rtlamr'

# path to rtl_tcp
RTL_TCP = '/usr/bin/rtl_tcp'

Home Assistant Config

mqtt:
  sensor:
    - name: "Water Meter"
      unique_id: "1564077862"
      state_topic: "readings/1564077862/meter_reading"
      unit_of_measurement: G

I have since migrated to the rtlamr2mqtt Add On. It works the same, but is much easier to use

Are you talking about the ā€œAMR2MQTTā€ addon or is there a different add-on? My Pi3B+ doesnā€™t seem to be able to handle HAOS and that addon. It keeps crashing due to low memory.

Therefore, I was running this on my extra Pi0W.

EDIT: I found the add-on you were talking about. Got it setup and everything is working perfectly!

Thanks