Sunday, 6 July 2025

Add MQTT subscription functionality to existing Publisher

 Context:

I have a Raspberry Pi Zero W on my desk. Attached to the Pi is a Sense Hat and an LCD screen.

The purpose of which is to show the current temperature, Humidity, Pressure and Time.

The python code was written a few years ago by my grandfather, based on research from other peoples code. Once I inherited it, I cleaned up the code a little (adding the time feature, which replaced the temperature in Fahrenheit) and its just been sat on my desk looking cool.

I decided I wanted to pass the temperature reading to home assistant for reasons.

I did a bit of research and found the paho.mqtt.client python module and imported that into my code.

import paho.mqtt.client as mqtt

I added the broker details and the topic:

#MQTT broker settings
broker_address = "<IP_ADDRESS>"
broker_port = 1883
topic = "homeassistant/sensor/office_temperature"


Defined the connection event:

#callback when connection to the broker is established
def on_connect(client, userdata, flags, rc):
       print("connected with result code "+str(rc))


Initialised the client:

#Initialise MQTT Client
client = mqtt.Client()
client.on_connect = on_connect
client.username_pw_set(username="mqtt_user",password="<password>")

#Connect to the broker
client.connect(broker_address, broker_port, 60)


#Publish temperature to MQTT topic
   client.publish(topic, temp1)


Then from within the MQTT Explorer in home assistant, we can see the topic and the data:



To get this as a sensor in home assistant, add an addition to the configuration.yaml

mqtt:
  sensor:
      - name: "Office Temperature"
        state_topic: "homeassistant/sensor/office_temperature"

and voila:


 Expanding:

Since having Solar panels and battery storage from Enphase installed, I now have the array entities within home assistant via the enphase extension so I can set up pretty dashboards like this:

The "Sun Solar Elevation" entity is from the Sun Integration, which gives me an rough idea of where the sun is and to use for other automation's.

It may sound obvious "just look out the window", but I live in England and the weather dictates that its not always that straightforward:


I already have an old android tablet sat on the other side of my desk, which displays the above dashboard, but I wanted to add a line on to the Pi's LCD display to show the battery's current charge level.
As I already have the broker details and connection in place within the python code, it should be pretty straight forward, right?

I started by adding an automation which triggers an MQTT: Publish action when the battery status changes:

alias: Enphase Battery Value
description: ""
triggers:
  - entity_id:
      - sensor.encharge_492452003617_battery
    trigger: state
conditions: []
actions:
  - data:
      qos: 0
      retain: false
      topic: homeassistant/sensor/enpbatt
      payload: "{{ states('sensor.encharge_492452003617_battery') }}"
    action: mqtt.publish
mode: single

now, when the battery charge level changes, we see it in the MQTT Explorer:





Now to add the subscription, save the message payload to a variable and output to the LCD display:

#callback when subsciption to the topic is established
def on_subscribe(client, userdata, mid, granted_qos):
   print("Subscribed: "+str(mid)+" "+str(granted_qos))

#callback when message from the topic is received
def on_message(client, userdata, msg):
   #print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload))
       global battmess
       battmess=str(msg.payload)

#Initialise MQTT Client
client = mqtt.Client()
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_message = on_message


#Connect to the broker
client.connect(broker_address, broker_port, 60)
client.subscribe(topic_battery,2)


#Publish temperature to MQTT topic
   client.publish(topic, temp1)
   client.loop_start()

I took me a really long time to work out why the variable was not being populated, whenever I started the script, the variable was empty.
I realised that the message is not sent (and thus the variable updated) until the state changes, so there was no message.
Queue me turning on all the things to trigger a change in the charge level and finally:


No comments:

Post a Comment