Writing a py3bar module to display MQTT temperature data

Posted on 2020-08-30

731 words

I recently started using the i3 Window manager and have swapped the bar from the standard bar to py3bar as it is easily extendible using python scripts and is also fully compatible with your existing i3bar configuration. You can swap to it with one change of your i3config and it will just work.

The i3 status bar is a great place to show useful information and I thought it would be handy to show the temperature of my living room which is stored in MQTT at Adafruit.io. The logic is split into two parts: The first retrieves the temperature from the MQTT server and spits it out into a text file and the second part is the py3bar module that renders the temperature to the bar.

Temperature Data on my i3 Bar Temperature Data on my i3 Bar between Pomodoro Timer and CPU Usage

Start by reading their documentation on creating custom modules as it goes into more details about the required file paths, and has a sample ‘Hello World’ module to try out as well.

I think this could easily be extended to control smart lights or plugs and other IOT things as well. Python in the system bar is neat. 🤓

Part 1 - fetch-temperature.py

This script is launched at login by i3 by adding this to your i3config:

exec --no-startup-id python3 /home/user/path/to/fetch-temperature.py &

The python code is fairly simple and only relies on paho-mqtt. It reads out the data and stores it in a plain text file under .config (to keep things tidy)

import paho.mqtt.client as mqtt
import paho.mqtt.subscribe as subscribe

def on_connect(client, userdata, flags, rc):
  print("Connected with result code "+str(rc))

def on_message_print(client, userdata, message):
    temp = message.payload
    temp = temp.decode("utf-8")
    #print("%s" % ( temp))

    f = open("/home/james/.config/temperature.txt", "w")

client = mqtt.Client()

client.on_connect = on_connect
client.on_message = on_message_print


Part 2 - Py3Bar Module

This is the py3bar module and deals with displaying the temperature on the bar itself. It reads in the temperature.txt, converts it to a number, rounds it and converts it back to a string ready to print to the bar.

When data is found it will expire in 300 seconds and when data is not found it will expire and refresh in 15 seconds. My sensor posts to MQTT every 5 minutes so this works well. The only time that the file does not exist is on first run or when it is manually deleted. If this happens the bar will check every 15 seconds waiting for a new file to be created by the script in Part 1.

I should probably add some more error checking here in case the file contains things other than a simple number.

class Py3status:
    def flat_temperature(self):
        while True:
                    #open and read the file after the appending:
                    f = open("/home/james/.config/temperature.txt", "r")
                    temp = f.read()
                    temp = float(temp)
                    temp = round(temp, 2)
                    temp = str(temp)
                    return {
                            'full_text': temp,
                            'cached_until': self.py3.time_in(300)
                except IOError:
                        return {
                                'full_text': "Waiting for data",
                                'cached_until': self.py3.time_in(15)

Start a discussion on Twitter!