MegaModem MQTT: Interpreting the data from PR55-5A

Hi, I have a Megamodem which is sending data to an MQTT server, But I don’t know how to interpret the data. I have a 4-20ma water level sensor connected to the PR55-5A “Current receiver”, which are both powered by a 12v DC battery source.

Here are the MQTT messages I’m seeing published, can someone help me decipher these? I’ve read through the manual… but frankly it’s about as clear as mud, and I don’t know how to translate what’s in the manual to what I’m seeing.
Is there someone who can help me interpret this data? This is my first time ever working with this hardware, or any 4-20ma sensor.

Megapub {“data”:[126,0,25,144,0,19,162,0,65,244,61,133,255,254,194,127,0,3,3,255,52,0,45,0,27,135,1,228,152]}
Megapub {“data”:[126,0,25,144,0,19,162,0,65,244,61,133,255,254,194,127,0,3,3,255,53,0,45,0,27,136,1,228,150]}
Megapub {“data”:[126,0,25,144,0,19,162,0,65,244,61,133,255,254,194,127,0,3,3,255,54,0,45,0,27,137,1,229,147]}
Megapub {“data”:[126,0,25,144,0,19,162,0,65,244,61,133,255,254,194,127,0,3,3,255,55,0,45,0,27,136,1,228,148]}

Edit: I understand that the data is all comma separated, I just don’t know how to interpret the data between the commas - How do I figure out what each number means?

You should print data in hex
7E 00 19 90 00 13 A2 00 41 F4 3D 85 FF FE C2 7F 00 03 03 FF 37 00 2D 00 1B 88 01 E4 94
This is your payload – 7F 00 03 03 FF 37 00 2D 00 1B 88 01 E4

Hi Anil, I don’t know what that means. The megamodem doesn’t give me the option of printing in HEX.

You can convert the dec into hex by using Python. The product manual uses Hex representation in all the examples.
7F 00 03 03 FF 37 00 2D 00 1B 88 01 E4
7F – Header
00 – Node id
03 – Firmware type
03 FF – battery level
37 – Packet counter
00 2D – Device type
00 – Reserve
1b 88 – raw DC value
01 E4 – mA value

All this is explained in the manual as well

Hi @Bhaskar Thanks. Which sensor type should I be referencing in the manual? I see 45, 48, 52, 56, 75, and 76 in the documentation, but I don’t see 55. It seems maybe the documentation was written for another product originally? I’m assuming I should use the 45/48 section for decoding the payload? But I would appreciate if you could confirm.

This is the device type you have

1 Like

I made a simple python script to subscribe to an MQTT broker, and convert the data into human readable, and machine usable JSON data. For my use case, I’m dumping water depth to a log file in JSON, where another script picks up the data, and uses it. Yesterday I posted something similar, but it didn’t allow for custom calibration of the 4-20mA water level sensor, so my measurements were off and it annoyed me, so I fixed that, and calibration instructions are in the script below.

Hopefully this helps someone else get started, I know this would have been helpful to me getting started trying to figure out how to navigate the data.

Disclaimer: I’m by no means a developer, let alone a python developer. If my script burns your house down, or offends your superior sensibilities, sorry? :man_shrugging:

#!/usr/bin/python3
import time
import os 
import logging
#import signal
import paho.mqtt.client as mqtt
import json

os.environ['TZ'] = 'America/Los_Angeles'
log_level=logging.INFO
logging.basicConfig(filename="/tmp/ncd.log", datefmt = '%Y-%m-%d %H:%M:%S', format='%(asctime)s %(levelname)s %(message)s', level=log_level)
mqtt_host="xxx.xxx.xxx.xxx"
mqtt_port=1883
mqtt_user="xxxxxx"
mqtt_pass="xxxxxxx"
mqtt_topic="xxxx/yyyy"
#4-20ma water level sensor calibration
#Measure water level (in cm) at a known low depth, and measure mA at that same height
#Then measure water level at a known higher depth, along with mA at that height. 
#The larger the gap between the high, and low measurements the more accurate your numbers will be
#But even with a small delta, the formula is still likely accurate "enough", and 
#will still calculate water levels above and below your high/low marks. 
#Do not use "0cm" as your low_cm, becuase the mA at 0cm (no water) doesn't seem accurate. 
low_cm = 6
high_cm = 21
low_ma = 4.21
high_ma = 5.41

logging.info(f"startup: mqtt_host: {mqtt_host}, topic: {mqtt_topic}")

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))

    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    client.subscribe(mqtt_topic)

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    #Assumes MQTT message payload looks like this:
    #{"data":[126,0,25,144,0,19,162,0,65,244,61,133,255,254,194,127,0,3,3,222,214,0,45,0,27,240,1,236,166]}
    #In this example, the payload starts at the 15th position (starting from 0), at 127. 
    #see https://community.ncd.io/t/megamodem-mqtt-interpreting-the-data-from-pr55-5a/12564 for more info. 
    print(f"topic: {msg.topic} payload: {msg.payload.decode()}")
    logging.info(f"raw data: {msg.topic} {msg.payload.decode()}")
    payload = json.loads(msg.payload.decode())
    battery_msb = payload['data'][18]
    battery_lsb = payload['data'][19]
    battery_voltage = round(((battery_msb * 256) + battery_lsb) * .00322,4)
    adc0 = payload['data'][26]
    adc1 = payload['data'][27]
    sensor_ma = ((adc0 * 256) + adc1) / 100.00
    #This formula uses known measurements for cm and mA to calibrate to this specific water level sensor
    level_cm = round((sensor_ma - low_ma) / ((high_ma - low_ma) / (high_cm - low_cm)) + low_cm,3)
    level_inches = round(level_cm / 2.54,3)
    node_id = payload['data'][16]
    calculated_payload = {
      node_id:  {
        'sensor_ma': sensor_ma,
        'level_inches': level_inches,
        'level_cm': level_cm,
        'battery_voltage': battery_voltage 
        }
      }
    calculated_payload_json = json.dumps(calculated_payload)
    print(f"{calculated_payload_json}")
    logging.info(f"{calculated_payload_json}")


client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.username_pw_set(username=mqtt_user, password=mqtt_pass)
client.connect(mqtt_host, port=mqtt_port, keepalive=60)

# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
# Other loop*() functions are available that give a threaded interface and a
# manual interface.
client.loop_forever()

/tmp/ncd.log looks like:

2023-06-03 20:07:28 INFO raw data: megamodem/pub1 {"data":[126,0,25,144,0,19,162,0,65,244,61,133,255,254,194,127,0,3,3,219,231,0,45,0,27,239,1,236,153]}
2023-06-03 20:07:28 INFO {"0": {"sensor_ma": 4.92, "level_inches": 5.856, "level_cm": 14.875, "battery_voltage": 3.1781}}

I also took the sensor 45 table from the user manual, and modified it to show my sample data alongside the descriptions in the manual, which made it easier while I was writing the above python script.
Here is the sample MQTT message, with the relevant payload in bold:
sub/topic {“data”:[126,0,25,144,0,19,162,0,65,244,61,133,255,254,194,127,0,3,3,255,55,0,45,0,27,136,1,228,148]}
And here is the modified table from the user manual, using the above payload for reference:

1 Like