Rapsberry Pi MQTT monitor

I wrote a small python script to capture cpu load, cpu temperature, free space, voltage and system clock speed on a Raspberry Pi computer and publish the data to a MQTT server.

Here is how it looks
Rapsberry Pi MQTT monitor in Home Assistant

here is the script

I find this very useful to monitor the health of all my 8 raspberries at home via home assistant.
If you have an idea of another value that can be tracked I am opened to suggestions.

Update:

  • I have fixed the cpu load so its really in % now - I am getting the cpu cores count and then divide by their number and multiply by 100
  • I have added memory and swap in % - I made it via bash so I don’t use another python library like psutil
  • Added an option to choose what messages are send via the config
  • Added an option to send a bulk message in CSV
8 Likes

Good idea! I’m doing all my sensors for the Pis with Glances. But this seems way better, Glances needs a lot more ressources, and tbh I’m using just four sensors from all the ones Glances offers.

Downloading & trying! I’ll report back! :slight_smile:

EDIT: You need to change the link, it is linking to the picture…
Correct one should be: https://github.com/hjelev/rpi-mqtt-monitor

thanks for that - I put the correct link initially but some how it got messed when I updated the picture

This is a great little tool, @masoko
Don’t have to run glances now to as a separate add-on :+1:

The CPU Load value should NOT be in %, correct?

Sure the CPU load should be in percent. :slight_smile: What other unit would you prefer? :wink:

@masoko
Some kind of RAM value would be great. “Percent used” or something with “free/used” . :slight_smile:

Swap use and Ethernet in / out would be great.

1 Like

Hi,
The cpu load value is not exactly in % - its the value displayed in uptime - its in % only for single core rpis - like rpi 1, but I put the % so it looks better. I’ll divide it by the number of cores and make it real, it was for personal use till now so I was ok like this since I know what it was.

this is a good idea - I’ll try to implement it

1 Like

Was literally about to do the same thing this has saved me one less task now thanks.

There is a similar thing here that I’m using on two remote GPIO to MQTT bridges at the moment:

It does not have network throughput, but it does have discovery.

I really like such a srcipt but get errors running in on thr rpi:
Traceback (most recent call last):
File “rpi-cpu2mqtt.py”, line 71, in
cpu_load = check_cpu_load()
File “rpi-cpu2mqtt.py”, line 31, in check_cpu_load
cpu_load = p.split(“average:”)[1].split(",")[0].replace(’ ', ‘’)
TypeError: a bytes-like object is required, not ‘str’

I am new in Python. Any suggestion?

what version of python do you use - I have tested and developed this on python 2 as the mqtt library was not available for version 3 when I wrote this couple of years ago. If you are on python 3 pls try version 2.
I plan to test with python 3 and make corrections if needed when I have time - but now I plan to first fix the cpu load % and implement the network traffic (also I have plans to add to the configuration ways to choose what is monitored)

This script looks good and the graphs are better than mine - sorry for duplicating I was not aware of this and it was not available when I did mine.

You have nothing to apologise for.

Options are always good.

The graphs are not part of it, that’s just Lovelace (and maybe some custom cards).

1 Like

Instead of defining the sensors in YAML, you can use the following script to define them via MQTT Discovery. The advantage is that all of the sensors will be associated with a device (that’s the one thing you currently can’t do in YAML is define MQTT Sensors with a device). It’s a handy way to organize the sensors (they are all associated with a specific device) and also permits the creation of device-oriented automations.

Modify the following script to suit your environment’s requirements:

#script:
create_rpi4_sensors:
  alias: "Create RPI4 sensors via MQTT Discovery"
  sequence:
    - service: mqtt.publish
      data:
        topic: homeassistant/sensor/rpi4_cpuload/config
        retain: true
        payload: >
          {
            "name": "RPI4 CPU Load",
            "unit_of_measurement": "%",
            "state_topic": "masoko/rpi4/cpuload",
            "unique_id": "rpi4_cpu_load",
            "device": {
                "identifiers": ["rpi4_status_monitor"],
                "name": "Raspberry Pi",
                "model": "RPI4",
                "manufacturer": "Raspberry Pi Foundation",
                "sw_version": "X.XX"
            }
          }

    - service: mqtt.publish
      data:
        topic: homeassistant/sensor/rpi4_cputemp/config
        retain: true
        payload: >
          {
            "name": "RPI4 CPU Temperature",
            "unit_of_measurement": "°C",
            "state_topic": "masoko/rpi4/cputemp",
            "unique_id": "rpi4_cpu_temp",
            "device": {
                "identifiers": ["rpi4_status_monitor"],
                "name": "Raspberry Pi",
                "model": "RPI4",
                "manufacturer": "Raspberry Pi Foundation",
                "sw_version": "X.XX"
            }
          }

    - service: mqtt.publish
      data:
        topic: homeassistant/sensor/rpi4_diskusage/config
        retain: true
        payload: >
          {
            "name": "RPI4 Disk Usage",
            "unit_of_measurement": "%",
            "state_topic": "masoko/rpi4/diskusage",
            "unique_id": "rpi4_disk_usage",
            "device": {
                "identifiers": ["rpi4_status_monitor"],
                "name": "Raspberry Pi",
                "model": "RPI4",
                "manufacturer": "Raspberry Pi Foundation",
                "sw_version": "X.XX"
            }
          }

    - service: mqtt.publish
      data:
        topic: homeassistant/sensor/rpi4_voltage/config
        retain: true
        payload: >
          {
            "name": "RPI4 Voltage",
            "unit_of_measurement": "V",
            "state_topic": "masoko/rpi4/voltage",
            "unique_id": "rpi4_voltage",
            "device": {
                "identifiers": ["rpi4_status_monitor"],
                "name": "Raspberry Pi",
                "model": "RPI4",
                "manufacturer": "Raspberry Pi Foundation",
                "sw_version": "X.XX"
            }
          }

    - service: mqtt.publish
      data:
        topic: homeassistant/sensor/rpi4_clockspeed/config
        retain: true
        payload: >
          {
            "name": "RPI4 System Clock Speed",
            "unit_of_measurement": "hz",
            "state_topic": "masoko/rpi4/sys_clock_speed",
            "unique_id": "rpi4_sys_clock_speed",
            "device": {
                "identifiers": ["rpi4_status_monitor"],
                "name": "Raspberry Pi",
                "model": "RPI4",
                "manufacturer": "Raspberry Pi Foundation",
                "sw_version": "X.XX"
            }
          }
2 Likes

Thanks I’ll look at that looks really useful and interesting. I’ll look at it later.
Now I am updating the script as I got inspired by all the nice comments here - I just fixed the CPU load so its really in %

Memory and swap are implemented - both in % used

2 Likes

Thank you very much for your fast and helpful response, that works! Great script: easy and very useful!

I did something similar, but I needed different informations.
My goal was to publish two tasmota-like topics every x minutes with STATE and SENSOR jsons.

tele/p2p_server/LWT Online
tele/p2p_server/STATE {"Time":"2020-04-29T18:53:15","Uptime":"54T21:04:37","CPULoad":2.7,"MemoryTotal":926.1,"MemoryAvailable":512.4,"MemoryPercent":44.7,"DiskTotal":77.8,"DiskFree":48.7,"DiskPercent":34.0,"POWER":"ON"}
tele/p2p_server/SENSOR {"Time":"2020-04-29T18:53:15","AMULE":{"Upload":25.01,"Download":0.0},"TRANSMISSION":{"Upload":0.0,"Download":0.0}}

My script once started will loop forever and publishes an LWT topic to share the availability. You can easily convert it into a service and manage it with systemctl command.
Here is the code I used:

#!/usr/bin/python3
import os
import re
import time
from datetime import datetime
import paho.mqtt.client as mqtt
import psutil

def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))
    client.subscribe("tele/p2p_server/#")
def on_message(client, userdata, msg):
    print(msg.topic+" "+str(msg.payload))

def time_now():
        data_now_obj = datetime.now()
        data_now_str = data_now_obj.strftime("%Y-%m-%dT%H:%M:%S")
        return (data_now_str.strip())

def uptime():
        data_now_obj = datetime.now()
        data_now_str = data_now_obj.strftime("%Y-%m-%dT%H:%M:%S")
        data_uptime_str = os.popen("uptime -s").readline().strip()
        data_uptime_obj = datetime.strptime(data_uptime_str,"%Y-%m-%d %H:%M:%S")
        uptime_obj = data_now_obj - data_uptime_obj
        uptime_str = "%dT%02d:%02d:%02d" % (uptime_obj.days, (uptime_obj.seconds // 3600), (uptime_obj.seconds % 3600 // 60), (uptime_obj.seconds % 60))
        return (uptime_str.strip())

def load():
        cpu = psutil.cpu_percent(interval=None)
        mem = psutil.virtual_memory()
        disk = psutil.disk_usage('/mnt/usbdisk')
        temp = "\"CPULoad\":%s,\"MemoryTotal\":%s,\"MemoryAvailable\":%s,\"MemoryPercent\":%s,\"DiskTotal\":%s,\"DiskFree\":%s,\"DiskPercent\":%s" % (cpu,(round(mem.total / 1048576,1)),(round(mem.available / 1048576,1)),mem.percent,(round(disk.total / 1073741824,1)),(round(disk.free / 1073741824,1)),disk.percent)
        return (temp)

def transmission():
        temp = os.popen("transmission-remote -n transmission:frigor -l|grep ^Sum:").readline()
        return (re.sub(r'^.*(\d+\.\d+)\s+(\d+\.\d+)$', r'"TRANSMISSION":{"Upload":\1,"Download":\2}', temp.strip()))
def amule():
        dlstr = 0
        upstr = 0
        temp = os.popen("amulecmd -P frigor -p 4713 -c 'status'").read()
        for item in temp.split("\n"):
                if "Download" in item:
                        dlstr = re.sub(r'^.+\s(\d+\S*).*$', r'\1', item.strip())
                        if "bytes" in item:
                                dlstr = round(eval('float(dlstr)/1024'),1)
                elif "Upload" in item:
                        upstr = re.sub(r'^.+\s(\d+\S*).*$', r'\1', item.strip())
                        if "bytes" in item:
                                upstr = round(eval('float(upstr)/1024'),1)
        temp = "\"AMULE\":{\"Upload\":%s,\"Download\":%s}" % (upstr, dlstr)
        return (temp)

qos=0
retain=True
topic_id="YOUR_TOPIC"
client=mqtt.Client(topic_id)
client.username_pw_set("USERNAME", password="SECRET_PWD")
topic = "tele/%s/LWT" % topic_id
payload = "Offline"
client.will_set(topic, payload, qos, retain)
client.reconnect_delay_set(min_delay=1, max_delay=120)
client.connect("IP_ADDRESS", 1883, 60)
payload = "Online"
client.publish(topic, payload, qos, retain)

#client.loop_forever()
while True:
        retain=False
        topic = "tele/%s/STATE" % topic_id
        payload = "{\"Time\":\"%s\",\"Uptime\":\"%s\",%s,\"POWER\":\"ON\"}" % (time_now(),uptime(),load())
        client.publish(topic, payload, qos, retain)
        topic = "tele/%s/SENSOR" % topic_id
        payload = "{\"Time\":\"%s\",%s,%s}" % (time_now(),amule(),transmission())
        client.publish(topic, payload, qos, retain)
        time.sleep(60)