Intel NUC - Proxmox - CPU temperature monitor with Python + MQTT

Hello,

Was looking for a way to monitor my NUC temperature on Proxmox installation and Hass.io supervisor running a a VM. And, as I could not find something with MQTT, I build one.
So here it is Python script running in crontab on Proxmox, sending data to Mosquito server:

nuc_info.py
=========
import paho.mqtt.client as mqtt
import subprocess
from requests import post

#  function
def connect_msg():
    print('Connected to Broker')

# function
def publish_msg():
    print('Message Published')

# Creating client
MQTT_IP = "192.168.1.XXX"
MQTT_PORT = "1883"

# Retrieving CPUs temperatures from sensor
cpus = subprocess.check_output("sensors|grep 'Core'|awk '{print $3}'| rev | cut -c 4- | rev | cut -c2-", shell=True)
cpus = cpus.decode()
cpus = cpus.splitlines()

# Topics to publih for MQTT
TOPIC_TO_PUBLISH1 = "homeassistant/sensor/NUC_system/cpu1"
TOPIC_TO_PUBLISH2 = "homeassistant/sensor/NUC_system/cpu2"
TOPIC_TO_PUBLISH3 = "homeassistant/sensor/NUC_system/cpu3"
TOPIC_TO_PUBLISH4 = "homeassistant/sensor/NUC_system/cpu4"

client = mqtt.Client(client_id='NUC_system')

# Connecting callback functions
client.on_connect = connect_msg
client.on_publish = publish_msg

# Connect to broker
client.connect(MQTT_IP,MQTT_PORT)

# if you experience Socket error then replace above statement with following one
# client.connect("192.168.1.XXX",1883,60)

# Publish a message with topic
client.publish(TOPIC_TO_PUBLISH1,cpus[0])
client.publish(TOPIC_TO_PUBLISH2,cpus[1])
client.publish(TOPIC_TO_PUBLISH3,cpus[2])
client.publish(TOPIC_TO_PUBLISH4,cpus[3])

# Run a loop
client.loop()

Then this can be integrated to Home Assistant

configuration.yaml

like eg.:

sensor:
  - platform: mqtt
    name: NUC_cpu1
    state_topic: "homeassistant/sensor/NUC_system/cpu1"

Enjoy. :slight_smile:

3 Likes

Nice !

Is there any pre-requisite or dependency to run this script ?

This what I use for the moment :slight_smile:

sensor:
  - platform: command_line
    name: Proxmox CPU Temperaure
    command: "ssh -i /config/ssh_keys/id_rsa -o StrictHostKeyChecking=no [email protected] -t 'cat /sys/class/thermal/thermal_zone2/temp'"    
    unit_of_measurement: "°C"
    scan_interval: 29
    value_template: '{{ (value | multiply(0.001)) | round(0) }}'

But it’s not a clean solution…

Hi,

Right, this I was using also until now, but I was thinking that it is too much trouble to start passwordless SSH for few values.
Prerequisites:

  • install on Proxmox: apt install python-pip + pip install paho-mqtt
  • adapt crontab to run each 30 seconds:
* * * * *              python /root/work/nuc_info.py
* * * * * ( sleep 30 ; python /root/work/nuc_info.py )
  • have a MQTT server running (in my case is on VM running HomeAssistant)

MQTT code can be adjusted to eg. add disk space usage, or other info from Proxmox.

Good luck.

Hey. Great job!
My MQTT broker uses authorization a little bit. I also monitor the battery status in my laptop. Really great and fast solution!

import paho.mqtt.client as mqtt
import subprocess
from requests import post

#  function
def connect_msg():
    print('Connected to Broker')
# function
def publish_msg():
    print('Message Published')

# Creating client
MQTT_IP = "192.168.50.*"
MQTT_PORT = "1883"
USER_MQ = "user"
PW_MQ = "password"

# Retrieving CPUs temperatures from sensor
cpus = subprocess.check_output("sensors|grep 'Core'|awk '{print $3}'| rev | cut -c 4- | rev | cut -c2-", shell=True)
cpus = cpus.decode()
cpus = cpus.splitlines()

# 
adp1 = subprocess.check_output("cat /sys/class/power_supply/ADP1/online", shell=True)

# Topics to publih for MQTT
TOPIC_TO_PUBLISH1 = "homeassistant/sensor/NUC_system/cpu1"
TOPIC_TO_PUBLISH2 = "homeassistant/sensor/NUC_system/cpu2"
TOPIC_TO_PUBLISH3 = "homeassistant/sensor/NUC_system/Battery"

client = mqtt.Client(client_id='VM_system')

# Connecting callback functions
client.on_connect = connect_msg
client.on_publish = publish_msg

# Connect to broker
client.username_pw_set(USER_MQ,PW_MQ)
client.connect(MQTT_IP,MQTT_PORT)

# Publish a message with topic
client.publish(TOPIC_TO_PUBLISH1,cpus[0])
client.publish(TOPIC_TO_PUBLISH2,cpus[1])
client.publish(TOPIC_TO_PUBLISH3,adp1)

# Run a loop
client.loop()

@maxmaia great job!!

I’m on a Proxmox server and I was able to get cpu temp using this

cat /sys/class/thermal/thermal_zone*/temp

and the result is

-263200
27800
56000
cat: /sys/class/thermal/thermal_zone3/temp: No data available
54000

The correct CPU temp should be the third lines.

How can I adapt your code for this?

Thanks

This will give you the third line:

cat /sys/class/thermal/thermal_zone*/temp | sed -n '3 p'

and this will give you lines 2-4 of that’s what you meant.

cat /sys/class/thermal/thermal_zone*/temp | sed -n '2,4 p'
1 Like

Well, there are typically multiple files here:

ls -ltr /sys/class/thermal/thermal_zone*/temp
-r--r--r-- 1 root root 4096 Jun 12 20:00 /sys/class/thermal/thermal_zone4/temp
-r--r--r-- 1 root root 4096 Jun 12 20:00 /sys/class/thermal/thermal_zone3/temp
-r--r--r-- 1 root root 4096 Jun 12 20:00 /sys/class/thermal/thermal_zone2/temp
-r--r--r-- 1 root root 4096 Jun 12 20:00 /sys/class/thermal/thermal_zone1/temp
-r--r--r-- 1 root root 4096 Jun 12 20:00 /sys/class/thermal/thermal_zone0/temp

So, you can do just:
cat <file_name>

for the one you are interested.

1 Like

I didn’t want to have to worry about installing any additional dependencies at the Proxmox host level, so instead I was able to set up host CPU temperature tracking in Home Assistant using a shell script (requires MQTT):

#!/bin/bash

cputemp=$( cat /sys/class/thermal/thermal_zone2/temp )

curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer XXXX" \
  -d '{"payload": "'"${cputemp}"'", "topic": "pve/cpu_temp", "retain": "True"}' \
  http://xxx.xxx.xxx.xxx:8123/api/services/mqtt/publish

Substitute your thermal_zone number, add in a long-lived access token for the authorization, and fill in your IP. Then save that as cpu_temp.sh and schedule it to run in cron. It will push the CPU temperature to the pve/cpu_temp topic in MQTT. Then, you can extract it in Home Assistant with the following sensor:

  - platform: mqtt
    name: CPU Temperature
    state_topic: "pve/cpu_temp"
    value_template: "{{ value | multiply(0.001) | round(1) }}"
8 Likes

Nice alternative.
In my case the need was also to monitor used space of whole proxmox box, thus I could easily adapt similar mqtt approach to report used disks.

Makes sense, I think your approach probably scales up better if you have other things you want to report from the host to Home Assistant.

1 Like

This is by far the easiest solution I have found, thanks!

1 Like

This is just great. How to modify to push multiple value sharing the TOKEN ?
My bash programing not at the best

almost two years later, but sir, you made my day. Been trying all kind of python stuff, nothing worked.

This was fairly easy! I only changed the value_template | Round(1) to | Int because the value would always have a 0 as a decimal (which just annoys me) :rofl:

After month messing around with the code…here is what got making multiple post shorter

#!/bin/bash

ha_url="http://homeassistant_ip:8123/api/services/mqtt/publish"
ha_content="Content-Type: application/json"
ha_authorization="Authorization: Bearer XXXXX_Super_Long_Token"

hostcpu=$( /usr/bin/pvesh get /nodes/ --noborder 1 --noheader 1 | awk -F' ' '{print $3}' | sed 's/\%//')
curl -X POST -s -H "${ha_content}" -H "${ha_authorization}" --url "${ha_url}" -o /dev/null \
  -d '{"payload": "'"${hostcpu}"'", "topic": "pve/cpu", "retain": "True"}' 
  

cputemp=$( cat /sys/class/thermal/thermal_zone3/temp )
curl -X POST -s -H "${ha_content}" -H "${ha_authorization}" --url "${ha_url}" -o /dev/null \
  -d '{"payload": "'"${cputemp}"'", "topic": "pve/cpu_temp", "retain": "True"}' 

ha_authorization=''

if i try to execute your code I get an:

  File "/root/temp_script_new.py", line 5
    hostcpu=$( /usr/bin/pvesh get /nodes/ --noborder 1 --noheader 1 | awk -F' ' '{print $4}' | sed 's/\%//')
            ^
SyntaxError: invalid syntax

it is bash script. not python.

1 Like

Thanks for this useful script, I made a json version to compine the cpus in one publish:
Change the UPPERCASE variables to your needs and it will generate a message like

{ "cpu1": 28, "cpu2": 34, "cpu3": 28, "cpu4": 38 }

Here’s the script:

#!/usr/bin/python3
# nuc_info.py
# =========
import paho.mqtt.client as mqtt
import subprocess
import json

# Creating client
MQTT_IP = "192.168.XXX.XXX"
MQTT_USR = "mqtt_user"
MQTT_PW = "mqtt_password"
MQTT_PORT = 1883

SYSTEM_NAME = "pve1"
SYSTEM_PATH = "homeassistant/sensor"
TOPIC_NAME = "cpuTemp"
KEY_NAME = "cpu"

# Retrieving CPUs temperatures from sensor
cpus = subprocess.check_output("sensors|grep 'Core'|awk '{print $3}'| rev | cut -c 4- | rev | cut -c2-", shell=True)
cpus = cpus.decode()
cpus = cpus.splitlines()

json_dict = {}
for i, value in enumerate(cpus, start=1):
    cpu_key = "{}{}".format(KEY_NAME, i)
    try:
        numeric_value = float(value)
    except ValueError:
        numeric_value = None
    json_dict[cpu_key] = numeric_value

json_data = json.dumps(json_dict)

# Topics to publih for MQTT
TOPIC_TO_PUBLISH = "{}/{}/{}".format(SYSTEM_PATH, SYSTEM_NAME, TOPIC_NAME)

client = mqtt.Client(client_id=SYSTEM_NAME, clean_session=False)
client.username_pw_set(MQTT_USR, MQTT_PW)

# Connect to broker
client.connect(MQTT_IP,MQTT_PORT, 60)

# Publish a message with topic
client.publish(TOPIC_TO_PUBLISH,json_data)

# Run a loop
client.loop()

possible yaml configuration:

mqtt:
  sensor:
    - name: pve1_cpu1
      state_topic: "homeassistant/sensor/pve1/cpuTemp"
      value_template: "{{ value_json.cpu1 }}"
      device_class: temperature
      unit_of_measurement: "°C"
    - name: pve1_cpu2
      state_topic: "homeassistant/sensor/pve1/cpuTemp"
      value_template: "{{ value_json.cpu2 }}"
      device_class: temperature
      unit_of_measurement: "°C"
...

Hi, my shell script