Announcement

Collapse
No announcement yet.

Monitoring some power/gas/water meters via an RTL-SDR

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Monitoring some power/gas/water meters via an RTL-SDR

    I stumbled on to this today:
    https://blog.kroy.io/monitoring-home...-less-than-25/

    Looks to be written in Go, and supports native CSV and JSON outputting. Took me literally 5mins on a Linux box to get running with an RTL-SDR I had sitting around. Not quite as detailed as I'd want with my two meters (just basic SCM with consumption), but pretty interesting to see the usage stats. My gas meter I haven't figured out yet (pretty certain it's mine as it's the only one it's seeing), as the dial doesn't line up to the numbers I'm seeing unlike the electric meter. Meter is in CCF, but the value I'm seeing doesn't seem to be CCF, Therms or kwh.

    #2
    This is exciting, I have a RTL-SDR module that is surplus to use and a radio water meter (I have no idea where it is, long story but it is somewhere buried in the road) that is read remotely. I'm going to give it a go thanks for the link.

    Comment


      #3
      Originally posted by mrhappy View Post
      This is exciting, I have a RTL-SDR module that is surplus to use and a radio water meter (I have no idea where it is, long story but it is somewhere buried in the road) that is read remotely. I'm going to give it a go thanks for the link.
      I'm not sure how it works in the UK with non-900mhz devices, but worth a shot.

      I find it interesting as run it this am, was seeing the gas meter. Now this evening only seeing the electricity meter.

      Comment


        #4
        There are several models at Amazon, could you please send me a link of the one that you have?

        Thanks,
        Aldo

        Originally posted by mloebl View Post
        I stumbled on to this today:
        https://blog.kroy.io/monitoring-home...-less-than-25/

        Looks to be written in Go, and supports native CSV and JSON outputting. Took me literally 5mins on a Linux box to get running with an RTL-SDR I had sitting around. Not quite as detailed as I'd want with my two meters (just basic SCM with consumption), but pretty interesting to see the usage stats. My gas meter I haven't figured out yet (pretty certain it's mine as it's the only one it's seeing), as the dial doesn't line up to the numbers I'm seeing unlike the electric meter. Meter is in CCF, but the value I'm seeing doesn't seem to be CCF, Therms or kwh.

        Comment


          #5
          There are automation plugins today using RTL-SDR for the Domoticz open source automation program.

          Here mini sizing my NOAA satellite weather maps downloading to an RPI2 / antenna that today is doing GPIO ZWave, 1-wire stuff and running Domoticz on the side. For text data and jpg images do a share drive to the data directory on HS3.

          Many or most of the plugins are written in LUA. Very tight and easy peasy stuff that runs on OpenWRT OS...well like the Almond + or Vera or Wheezy or Stretch (linux in general).

          Here only the water meter uses a tiny transmitter. Updates now to it allow for remote views from the entrance of the subdivision.

          Just received this gift to tinker with from Ebay...(had one SDR radio from a few years back here). Note that you can get the USB radios for around $10 these days.

          It's the little SMA connectors that you want with antennas. Earlier testing all of my test SMA connectors purchased cost more than the radio.

          TCXO SMA Software Defined Radio Dongle With 2x Telescopic Antennas

          This "kit" with antennas, sma connectors and radio was around $28 USD. I got mine from China in less than a week.

          Lately Amazon Prime 2 day for this kind of stuff doesn't work for me and have noticed that the cost of the devices are more.

          [ATTACH]65475[/ATTACH]
          Last edited by Pete; December 31, 2017, 01:12 PM.
          - Pete

          Auto mator
          Homeseer 3 Pro - 3.0.0.548 (Linux) - Ubuntu 18.04/W7e 64 bit Intel Haswell CPU 16Gb
          Homeseer Zee2 (Lite) - 3.0.0.548 (Linux) - Ubuntu 18.04/W7e - CherryTrail x5-Z8350 BeeLink 4Gb BT3 Pro
          HS4 Lite - Ubuntu 22.04 / Lenovo Tiny M900 / 32Gb Ram

          HS4 Pro - V4.1.18.1 - Ubuntu 22.04 / Lenova Tiny M900 / 32Gb Ram
          HSTouch on Intel tabletop tablets (Jogglers) - Asus AIO - Windows 11

          X10, UPB, Zigbee, ZWave and Wifi MQTT automation-Tasmota-Espurna. OmniPro 2, Russound zoned audio, Alexa, Cheaper RFID, W800 and Home Assistant

          Comment


            #6
            Originally posted by aldo View Post
            There are several models at Amazon, could you please send me a link of the one that you have?

            Thanks,
            Aldo
            I got mine as part of a kit awhile back when I was experimenting with Outernet (the satellite service, not sure why as kinda useless for me ) It's essentially this:
            https://www.amazon.com/NooElec-NESDR.../dp/B06Y1HKLHY

            But in theory any of the RTL SDR sticks that do 900mhz should work.

            Comment


              #7
              Thank you

              Originally posted by mloebl View Post
              I got mine as part of a kit awhile back when I was experimenting with Outernet (the satellite service, not sure why as kinda useless for me ) It's essentially this:
              https://www.amazon.com/NooElec-NESDR.../dp/B06Y1HKLHY

              But in theory any of the RTL SDR sticks that do 900mhz should work.

              Comment


                #8
                All, thank you for this post. I was able to read my meter. My next step would be to parse the json file in mysql. Did anyone do it already? If not, could you put me in the right direction?

                Thanks,
                Aldo

                Comment


                  #9
                  So here's the flow I did... I started by trying to do it via a JSON update to HS3, but was having issues posting the update of just the status as wanted a status only device. I ended up writing a python script that runs the rtlamr utility once, waits for the ID(s) to come thru that you specify, decodes the JSON, then posts it to MQTT so I can get it from there. This is very low CPU usage as not running all the time.

                  The python script could be easily adapted to change the mqtt submits to whatever people want to do.

                  That being said, if I have some time, I'd love to learn GoLang a bit to try to add an MQTT module to the existing tool, so no script is necessary, it just posts constantly from a Pi dedicated to this task.

                  I'll try to clean up the script tonight if I have some time and will post it here. It's enough for sure to get someone going. FWIW I went this route as didn't want to run it from my HS box as it's an arm board, so wanted to take the CPU load off by running it elsewhere off the network.

                  Comment


                    #10
                    I'm enjoying this, you guys are good!!!! I like your idea, I was also thinking to get these values in mysql database, then from there the sky has no limit. I could use Jon00 or grafana to display those values. Unfortunately I'm really bad with scripts and json. I will look forward to your script.

                    Thanks,
                    Aldo

                    Comment


                      #11
                      Originally posted by aldo View Post
                      I'm enjoying this, you guys are good!!!! I like your idea, I was also thinking to get these values in mysql database, then from there the sky has no limit. I could use Jon00 or grafana to display those values. Unfortunately I'm really bad with scripts and json. I will look forward to your script.

                      Thanks,
                      Aldo
                      No worrries, I've got a busy weekend, but will see what I can do I've *really* wanted to get started with grafana myself, but had issues awhile ago getting it going.

                      In the mean time, not sure if you saw this from the rtlamr guy:
                      https://github.com/bemasher/rtlamr-collect

                      Comment


                        #12
                        Thanks that will get me started. I really like Grafana especially now that they have integrated MySQL.

                        Comment


                          #13
                          I forked this off an existng script I use to push TED1000 or 1wire messages to MQTT via a service, so it's not perfect, but worked enough for my testing. I take no responsibility for the damage it may cause The script itself is based on an original MQTT publishing script I found here on github, https://github.com/kylegordon/mqtt-owfs-temp.

                          Attached is the python script, and a sample config file. The python script reads that config sample config file where you can set path values, credentials, etc. For my testing I had rtlamr, the log, and config file all in the same directory. If you want to use this script, rename the SAMPLE-mqtt-rtlamr.cfg to mqtt-rtlamr.cfg and set values accordingly. It's not perfect, but something I threw together in an evening to test how it may work. It's definitely a good starting point for someone looking to use a python script to process the data.

                          SAMPLE-mqtt-rtlamr.cfg
                          Code:
                          [global]
                          DEBUG = False
                          LOGFILE = mqtt-rtlamr.log
                          RTLAMR_PATH =./rtlamr
                          MQTT_HOST = CHANGEME-MQTTHOST
                          MQTT_PORT = CHANGEME-MQTTPORT
                          MQTT_TOPIC = /#
                          MQTT_SUBTOPIC = /rtlamr/
                          MQTT_USERNAME = CHANGEME-MQTTUSERNAME
                          MQTT_PASSWORD = CHANGEME-MQTTPASSWORD
                          POLLINTERVAL = 1
                          METRICUNITS = 0
                          UNITID = CHANGEME-UNITID
                          MSGTYPE = scm
                          Code:
                          #!/usr/bin/env python
                          # -*- coding: iso-8859-1 -*-
                          
                          # Script based on mqtt-owfs-temp written by Kyle Gordon and converted for use with script
                          # Source: https://github.com/kylegordon/mqtt-owfs-temp
                          
                          import os
                          import logging
                          import signal
                          import socket
                          import time
                          import sys
                          import ConfigParser
                          import json
                          
                          import subprocess
                          import paho.mqtt.client as paho
                          
                          import setproctitle
                          # from datetime import datetime, timedelta
                          
                          # Read the config file
                          config = ConfigParser.RawConfigParser()
                          config.read("mqtt-rtlamr.cfg")
                          
                          # Use ConfigParser to pick out the settings
                          DEBUG = config.getboolean("global", "debug")
                          LOGFILE = config.get("global", "logfile")
                          MQTT_HOST = config.get("global", "mqtt_host")
                          MQTT_PORT = config.getint("global", "mqtt_port")
                          MQTT_SUBTOPIC = config.get("global", "MQTT_SUBTOPIC")
                          MQTT_TOPIC = "/raw/" + socket.getfqdn() + MQTT_SUBTOPIC
                          MQTT_USERNAME = config.get("global", "MQTT_USERNAME")
                          MQTT_PASSWORD = config.get("global", "MQTT_PASSWORD")
                          METRICUNITS = config.get("global", "METRICUNITS")
                          
                          POLLINTERVAL = config.getint("global", "pollinterval")
                          
                          RTLAMR_PATH = config.get("global", "RTLAMR_PATH")
                          UNITID = config.get("global", "UNITID")
                          MSGTYPE = config.get("global", "MSGTYPE")
                          
                          
                          APPNAME = "rtlamr"
                          
                          PRESENCETOPIC = "clients/" + socket.getfqdn() + "/" + APPNAME + "/state"
                          setproctitle.setproctitle(APPNAME)
                          client_id = APPNAME + "_%d" % os.getpid()
                          
                          mqttc = paho.Client()
                          
                          LOGFORMAT = '%(asctime)-15s %(message)s'
                          
                          if DEBUG:
                              logging.basicConfig(filename=LOGFILE,
                                                  level=logging.DEBUG,
                                                  format=LOGFORMAT)
                          else:
                              logging.basicConfig(filename=LOGFILE,
                                                  level=logging.INFO,
                                                  format=LOGFORMAT)
                          
                          logging.info("Starting " + APPNAME)
                          logging.info("INFO MODE")
                          logging.debug("DEBUG MODE")
                          
                          # All the MQTT callbacks start here
                          
                          
                          def on_publish(mosq, obj, mid):
                              """
                              What to do when a message is published
                              """
                              logging.debug("MID " + str(mid) + " published.")
                          
                          
                          def on_subscribe(mosq, obj, mid, qos_list):
                              """
                              What to do in the event of subscribing to a topic"
                              """
                              logging.debug("Subscribe with mid " + str(mid) + " received.")
                          
                          
                          def on_unsubscribe(mosq, obj, mid):
                              """
                              What to do in the event of unsubscribing from a topic
                              """
                              logging.debug("Unsubscribe with mid " + str(mid) + " received.")
                          
                          
                          def on_connect(mosq, obj, result_code):
                              """
                              Handle connections (or failures) to the broker.
                              This is called after the client has received a CONNACK message
                              from the broker in response to calling connect().
                              The parameter rc is an integer giving the return code:
                              0: Success
                              1: Refused – unacceptable protocol version
                              2: Refused – identifier rejected
                              3: Refused – server unavailable
                              4: Refused – bad user name or password (MQTT v3.1 broker only)
                              5: Refused – not authorised (MQTT v3.1 broker only)
                              """
                              logging.debug("on_connect RC: " + str(result_code))
                              if result_code == 0:
                                  logging.info("Connected to %s:%s", MQTT_HOST, MQTT_PORT)
                                  # Publish retained LWT as per
                                  # http://stackoverflow.com/q/97694
                                  # See also the will_set function in connect() below
                                  mqttc.publish(PRESENCETOPIC, "1", retain=True)
                                  process_connection()
                              elif result_code == 1:
                                  logging.info("Connection refused - unacceptable protocol version")
                                  cleanup()
                              elif result_code == 2:
                                  logging.info("Connection refused - identifier rejected")
                                  cleanup()
                              elif result_code == 3:
                                  logging.info("Connection refused - server unavailable")
                                  logging.info("Retrying in 30 seconds")
                                  time.sleep(30)
                              elif result_code == 4:
                                  logging.info("Connection refused - bad user name or password")
                                  cleanup()
                              elif result_code == 5:
                                  logging.info("Connection refused - not authorised")
                                  cleanup()
                              else:
                                  logging.warning("Something went wrong. RC:" + str(result_code))
                                  cleanup()
                          
                          
                          def on_disconnect(mosq, obj, result_code):
                              """
                              Handle disconnections from the broker
                              """
                              if result_code == 0:
                                  logging.info("Clean disconnection")
                              else:
                                  logging.info("Unexpected disconnection! Reconnecting in 5 seconds")
                                  logging.debug("Result code: %s", result_code)
                                  time.sleep(5)
                          
                          
                          def on_message(mosq, obj, msg):
                              """
                              What to do when the client recieves a message from the broker
                              """
                              logging.debug("Received: " + msg.payload +
                                            " received on topic " + msg.topic +
                                            " with QoS " + str(msg.qos))
                              process_message(msg)
                          
                          
                          def on_log(mosq, obj, level, string):
                              """
                              What to do with debug log output from the MQTT library
                              """
                              logging.debug(string)
                          
                          # End of MQTT callbacks
                          
                          
                          def cleanup(signum, frame):
                              """
                              Signal handler to ensure we disconnect cleanly
                              in the event of a SIGTERM or SIGINT.
                              """
                              logging.info("Disconnecting from broker")
                              # Publish a retained message to state that this client is offline
                              mqttc.publish(PRESENCETOPIC, "0", retain=True)
                              mqttc.disconnect()
                              mqttc.loop_stop()
                              logging.info("Exiting on signal %d", signum)
                              sys.exit(signum)
                          
                          def connect():
                              """
                              Connect to the broker, define the callbacks, and subscribe
                              This will also set the Last Will and Testament (LWT)
                              The LWT will be published in the event of an unclean or
                              unexpected disconnection.
                              """
                              logging.info("Connecting to %s:%s", MQTT_HOST, MQTT_PORT)
                          
                              if MQTT_USERNAME:
                                  logging.info("Found username %s", MQTT_USERNAME)
                                  mqttc.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
                          
                              # Set the Last Will and Testament (LWT) *before* connecting
                              mqttc.will_set(PRESENCETOPIC, "0", qos=0, retain=True)
                              result = mqttc.connect(MQTT_HOST, MQTT_PORT, 60)
                              if result != 0:
                                  logging.info("Connection failed with error code %s. Retrying", result)
                                  
                                  time.sleep(10)
                                  connect()
                          
                              # Define the callbacks
                              mqttc.on_connect = on_connect
                              mqttc.on_disconnect = on_disconnect
                              mqttc.on_publish = on_publish
                              mqttc.on_subscribe = on_subscribe
                              mqttc.on_unsubscribe = on_unsubscribe
                              mqttc.on_message = on_message
                              if DEBUG:
                                  mqttc.on_log = on_log
                          
                              mqttc.loop_start()
                          
                          def process_connection():
                              """
                              What to do when a new connection is established
                              """
                              logging.debug("Processing connection")
                          
                          
                          def process_message(mosq, obj, msg):
                              """
                              What to do with the message that's arrived
                              """
                              logging.debug("Received: %s", msg.topic)
                          
                          
                          def find_in_sublists(lst, value):
                              for sub_i, sublist in enumerate(lst):
                                  try:
                                      return (sub_i, sublist.index(value))
                                  except ValueError:
                                      pass
                          
                              raise ValueError("%s is not in lists" % value)
                          
                          def slicer(my_str,sub):
                              index=my_str.find(sub)
                              if index !=-1 :
                                  return my_str[index:] 
                              else :
                                  raise Exception('Sub string not found!')
                          
                          def decodeJSON(jsonString):
                              logging.debug('Processing JSON: ', jsonString)
                              return(json.loads(jsonString))
                          
                          def getjsonvalue(jsonData, jsonmessage):
                              return(jsonData["Message"][jsonmessage])
                          
                          def getMeterType(metertype):
                              meter = "unknown"
                              if (metertype == 4) or (metertype == 5) or (metertype == 7) or (metertype == 8):  
                                  meter = "electric"
                              if (metertype == 2) or (metertype == 9) or (metertype == 12): 
                                  meter = "gas"
                              if (metertype == 11) or (metertype == 13):
                                  meter = "water"
                              return meter
                          
                          
                          def main_loop():
                              """
                              The main loop in which we stay connected to the broker
                              """
                              
                          
                              while True:
                                  rawjson = subprocess.check_output([RTLAMR_PATH, '-filterid='+UNITID, '-msgtype='+MSGTYPE,'--unique=true' ,'--format=json','--single=true'])
                                  logging.debug(slicer(rawjson, "{"))
                                  jsondata = decodeJSON(rawjson)
                          
                                  json_time=jsondata["Time"]
                                  json_id = getjsonvalue(jsondata, "ID")
                                  json_type = getjsonvalue(jsondata, "Type")
                                  json_tamper = getjsonvalue(jsondata, "TamperPhy")
                                  json_consumption = getjsonvalue(jsondata, "Consumption")
                          
                                  logging.debug("Current consumption: %.2f kw/h" % (json_consumption / 100))
                          
                                  string_consumption = "%0.2f" % (float(json_consumption) / 100)  
                          
                                  mqttc.publish(MQTT_TOPIC + str(json_id) + "/time", json_time)
                                  mqttc.publish(MQTT_TOPIC + str(json_id) + "/unitid", json_id)
                                  mqttc.publish(MQTT_TOPIC + str(json_id) + "/msgtype", MSGTYPE)
                                  mqttc.publish(MQTT_TOPIC + str(json_id) + "/metertype", getMeterType(json_type))
                                  mqttc.publish(MQTT_TOPIC + str(json_id) + "/consumption_raw", json_consumption)
                                  mqttc.publish(MQTT_TOPIC + str(json_id) + "/consumption_kwh", string_consumption)
                                  mqttc.publish(MQTT_TOPIC + str(json_id) + "/tamperphy", json_tamper)
                                  
                                  time.sleep(POLLINTERVAL*60)
                          
                          # Use the signal module to handle signals
                          signal.signal(signal.SIGTERM, cleanup)
                          signal.signal(signal.SIGINT, cleanup)
                          
                          # Connect to the broker and enter the main loop
                          connect()
                          
                          # Try to start the main loop
                          try:
                              main_loop()
                          except KeyboardInterrupt:
                              logging.info("Interrupted by keypress")
                              sys.exit(0)
                          Last edited by mloebl; January 12, 2018, 07:01 PM. Reason: Forum decided not to attach my scripts...

                          Comment


                            #14

                            Comment


                              #15
                              Sorry if this is a stupid question, do you run it from HS3? It looks like is just what I need. Right now I have the meter sensor on a virtual machine. Do I need to install MQTT on it?

                              Thanks

                              Originally posted by mloebl View Post
                              I forked this off an existng script I use to push TED1000 or 1wire messages to MQTT via a service, so it's not perfect, but worked enough for my testing. I take no responsibility for the damage it may cause The script itself is based on an original MQTT publishing script I found here on github, https://github.com/kylegordon/mqtt-owfs-temp.

                              Attached is the python script, and a sample config file. The python script reads that config sample config file where you can set path values, credentials, etc. For my testing I had rtlamr, the log, and config file all in the same directory. If you want to use this script, rename the SAMPLE-mqtt-rtlamr.cfg to mqtt-rtlamr.cfg and set values accordingly. It's not perfect, but something I threw together in an evening to test how it may work. It's definitely a good starting point for someone looking to use a python script to process the data.

                              SAMPLE-mqtt-rtlamr.cfg
                              Code:
                              [global]
                              DEBUG = False
                              LOGFILE = mqtt-rtlamr.log
                              RTLAMR_PATH =./rtlamr
                              MQTT_HOST = CHANGEME-MQTTHOST
                              MQTT_PORT = CHANGEME-MQTTPORT
                              MQTT_TOPIC = /#
                              MQTT_SUBTOPIC = /rtlamr/
                              MQTT_USERNAME = CHANGEME-MQTTUSERNAME
                              MQTT_PASSWORD = CHANGEME-MQTTPASSWORD
                              POLLINTERVAL = 1
                              METRICUNITS = 0
                              UNITID = CHANGEME-UNITID
                              MSGTYPE = scm
                              Code:
                              #!/usr/bin/env python
                              # -*- coding: iso-8859-1 -*-
                              
                              # Script based on mqtt-owfs-temp written by Kyle Gordon and converted for use with script
                              # Source: https://github.com/kylegordon/mqtt-owfs-temp
                              
                              import os
                              import logging
                              import signal
                              import socket
                              import time
                              import sys
                              import ConfigParser
                              import json
                              
                              import subprocess
                              import paho.mqtt.client as paho
                              
                              import setproctitle
                              # from datetime import datetime, timedelta
                              
                              # Read the config file
                              config = ConfigParser.RawConfigParser()
                              config.read("mqtt-rtlamr.cfg")
                              
                              # Use ConfigParser to pick out the settings
                              DEBUG = config.getboolean("global", "debug")
                              LOGFILE = config.get("global", "logfile")
                              MQTT_HOST = config.get("global", "mqtt_host")
                              MQTT_PORT = config.getint("global", "mqtt_port")
                              MQTT_SUBTOPIC = config.get("global", "MQTT_SUBTOPIC")
                              MQTT_TOPIC = "/raw/" + socket.getfqdn() + MQTT_SUBTOPIC
                              MQTT_USERNAME = config.get("global", "MQTT_USERNAME")
                              MQTT_PASSWORD = config.get("global", "MQTT_PASSWORD")
                              METRICUNITS = config.get("global", "METRICUNITS")
                              
                              POLLINTERVAL = config.getint("global", "pollinterval")
                              
                              RTLAMR_PATH = config.get("global", "RTLAMR_PATH")
                              UNITID = config.get("global", "UNITID")
                              MSGTYPE = config.get("global", "MSGTYPE")
                              
                              
                              APPNAME = "rtlamr"
                              
                              PRESENCETOPIC = "clients/" + socket.getfqdn() + "/" + APPNAME + "/state"
                              setproctitle.setproctitle(APPNAME)
                              client_id = APPNAME + "_%d" % os.getpid()
                              
                              mqttc = paho.Client()
                              
                              LOGFORMAT = '%(asctime)-15s %(message)s'
                              
                              if DEBUG:
                                  logging.basicConfig(filename=LOGFILE,
                                                      level=logging.DEBUG,
                                                      format=LOGFORMAT)
                              else:
                                  logging.basicConfig(filename=LOGFILE,
                                                      level=logging.INFO,
                                                      format=LOGFORMAT)
                              
                              logging.info("Starting " + APPNAME)
                              logging.info("INFO MODE")
                              logging.debug("DEBUG MODE")
                              
                              # All the MQTT callbacks start here
                              
                              
                              def on_publish(mosq, obj, mid):
                                  """
                                  What to do when a message is published
                                  """
                                  logging.debug("MID " + str(mid) + " published.")
                              
                              
                              def on_subscribe(mosq, obj, mid, qos_list):
                                  """
                                  What to do in the event of subscribing to a topic"
                                  """
                                  logging.debug("Subscribe with mid " + str(mid) + " received.")
                              
                              
                              def on_unsubscribe(mosq, obj, mid):
                                  """
                                  What to do in the event of unsubscribing from a topic
                                  """
                                  logging.debug("Unsubscribe with mid " + str(mid) + " received.")
                              
                              
                              def on_connect(mosq, obj, result_code):
                                  """
                                  Handle connections (or failures) to the broker.
                                  This is called after the client has received a CONNACK message
                                  from the broker in response to calling connect().
                                  The parameter rc is an integer giving the return code:
                                  0: Success
                                  1: Refused – unacceptable protocol version
                                  2: Refused – identifier rejected
                                  3: Refused – server unavailable
                                  4: Refused – bad user name or password (MQTT v3.1 broker only)
                                  5: Refused – not authorised (MQTT v3.1 broker only)
                                  """
                                  logging.debug("on_connect RC: " + str(result_code))
                                  if result_code == 0:
                                      logging.info("Connected to %s:%s", MQTT_HOST, MQTT_PORT)
                                      # Publish retained LWT as per
                                      # http://stackoverflow.com/q/97694
                                      # See also the will_set function in connect() below
                                      mqttc.publish(PRESENCETOPIC, "1", retain=True)
                                      process_connection()
                                  elif result_code == 1:
                                      logging.info("Connection refused - unacceptable protocol version")
                                      cleanup()
                                  elif result_code == 2:
                                      logging.info("Connection refused - identifier rejected")
                                      cleanup()
                                  elif result_code == 3:
                                      logging.info("Connection refused - server unavailable")
                                      logging.info("Retrying in 30 seconds")
                                      time.sleep(30)
                                  elif result_code == 4:
                                      logging.info("Connection refused - bad user name or password")
                                      cleanup()
                                  elif result_code == 5:
                                      logging.info("Connection refused - not authorised")
                                      cleanup()
                                  else:
                                      logging.warning("Something went wrong. RC:" + str(result_code))
                                      cleanup()
                              
                              
                              def on_disconnect(mosq, obj, result_code):
                                  """
                                  Handle disconnections from the broker
                                  """
                                  if result_code == 0:
                                      logging.info("Clean disconnection")
                                  else:
                                      logging.info("Unexpected disconnection! Reconnecting in 5 seconds")
                                      logging.debug("Result code: %s", result_code)
                                      time.sleep(5)
                              
                              
                              def on_message(mosq, obj, msg):
                                  """
                                  What to do when the client recieves a message from the broker
                                  """
                                  logging.debug("Received: " + msg.payload +
                                                " received on topic " + msg.topic +
                                                " with QoS " + str(msg.qos))
                                  process_message(msg)
                              
                              
                              def on_log(mosq, obj, level, string):
                                  """
                                  What to do with debug log output from the MQTT library
                                  """
                                  logging.debug(string)
                              
                              # End of MQTT callbacks
                              
                              
                              def cleanup(signum, frame):
                                  """
                                  Signal handler to ensure we disconnect cleanly
                                  in the event of a SIGTERM or SIGINT.
                                  """
                                  logging.info("Disconnecting from broker")
                                  # Publish a retained message to state that this client is offline
                                  mqttc.publish(PRESENCETOPIC, "0", retain=True)
                                  mqttc.disconnect()
                                  mqttc.loop_stop()
                                  logging.info("Exiting on signal %d", signum)
                                  sys.exit(signum)
                              
                              def connect():
                                  """
                                  Connect to the broker, define the callbacks, and subscribe
                                  This will also set the Last Will and Testament (LWT)
                                  The LWT will be published in the event of an unclean or
                                  unexpected disconnection.
                                  """
                                  logging.info("Connecting to %s:%s", MQTT_HOST, MQTT_PORT)
                              
                                  if MQTT_USERNAME:
                                      logging.info("Found username %s", MQTT_USERNAME)
                                      mqttc.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
                              
                                  # Set the Last Will and Testament (LWT) *before* connecting
                                  mqttc.will_set(PRESENCETOPIC, "0", qos=0, retain=True)
                                  result = mqttc.connect(MQTT_HOST, MQTT_PORT, 60)
                                  if result != 0:
                                      logging.info("Connection failed with error code %s. Retrying", result)
                                      
                                      time.sleep(10)
                                      connect()
                              
                                  # Define the callbacks
                                  mqttc.on_connect = on_connect
                                  mqttc.on_disconnect = on_disconnect
                                  mqttc.on_publish = on_publish
                                  mqttc.on_subscribe = on_subscribe
                                  mqttc.on_unsubscribe = on_unsubscribe
                                  mqttc.on_message = on_message
                                  if DEBUG:
                                      mqttc.on_log = on_log
                              
                                  mqttc.loop_start()
                              
                              def process_connection():
                                  """
                                  What to do when a new connection is established
                                  """
                                  logging.debug("Processing connection")
                              
                              
                              def process_message(mosq, obj, msg):
                                  """
                                  What to do with the message that's arrived
                                  """
                                  logging.debug("Received: %s", msg.topic)
                              
                              
                              def find_in_sublists(lst, value):
                                  for sub_i, sublist in enumerate(lst):
                                      try:
                                          return (sub_i, sublist.index(value))
                                      except ValueError:
                                          pass
                              
                                  raise ValueError("%s is not in lists" % value)
                              
                              def slicer(my_str,sub):
                                  index=my_str.find(sub)
                                  if index !=-1 :
                                      return my_str[index:] 
                                  else :
                                      raise Exception('Sub string not found!')
                              
                              def decodeJSON(jsonString):
                                  logging.debug('Processing JSON: ', jsonString)
                                  return(json.loads(jsonString))
                              
                              def getjsonvalue(jsonData, jsonmessage):
                                  return(jsonData["Message"][jsonmessage])
                              
                              def getMeterType(metertype):
                                  meter = "unknown"
                                  if (metertype == 4) or (metertype == 5) or (metertype == 7) or (metertype == 8):  
                                      meter = "electric"
                                  if (metertype == 2) or (metertype == 9) or (metertype == 12): 
                                      meter = "gas"
                                  if (metertype == 11) or (metertype == 13):
                                      meter = "water"
                                  return meter
                              
                              
                              def main_loop():
                                  """
                                  The main loop in which we stay connected to the broker
                                  """
                                  
                              
                                  while True:
                                      rawjson = subprocess.check_output([RTLAMR_PATH, '-filterid='+UNITID, '-msgtype='+MSGTYPE,'--unique=true' ,'--format=json','--single=true'])
                                      logging.debug(slicer(rawjson, "{"))
                                      jsondata = decodeJSON(rawjson)
                              
                                      json_time=jsondata["Time"]
                                      json_id = getjsonvalue(jsondata, "ID")
                                      json_type = getjsonvalue(jsondata, "Type")
                                      json_tamper = getjsonvalue(jsondata, "TamperPhy")
                                      json_consumption = getjsonvalue(jsondata, "Consumption")
                              
                                      logging.debug("Current consumption: %.2f kw/h" % (json_consumption / 100))
                              
                                      string_consumption = "%0.2f" % (float(json_consumption) / 100)  
                              
                                      mqttc.publish(MQTT_TOPIC + str(json_id) + "/time", json_time)
                                      mqttc.publish(MQTT_TOPIC + str(json_id) + "/unitid", json_id)
                                      mqttc.publish(MQTT_TOPIC + str(json_id) + "/msgtype", MSGTYPE)
                                      mqttc.publish(MQTT_TOPIC + str(json_id) + "/metertype", getMeterType(json_type))
                                      mqttc.publish(MQTT_TOPIC + str(json_id) + "/consumption_raw", json_consumption)
                                      mqttc.publish(MQTT_TOPIC + str(json_id) + "/consumption_kwh", string_consumption)
                                      mqttc.publish(MQTT_TOPIC + str(json_id) + "/tamperphy", json_tamper)
                                      
                                      time.sleep(POLLINTERVAL*60)
                              
                              # Use the signal module to handle signals
                              signal.signal(signal.SIGTERM, cleanup)
                              signal.signal(signal.SIGINT, cleanup)
                              
                              # Connect to the broker and enter the main loop
                              connect()
                              
                              # Try to start the main loop
                              try:
                                  main_loop()
                              except KeyboardInterrupt:
                                  logging.info("Interrupted by keypress")
                                  sys.exit(0)

                              Comment

                              Working...
                              X