This is a Python application for the Raspberry Pi (RPi) that allows interfacing with the SenseHAT over MQTT.
Of note, the project is a fork of mirkodcompataretti's rpi-sense-hat that ended up being heavily modified to reflect my own idea of implementation, which can be illustrated as follows:
That is, the rpi-sensehat-mqtt
application publishes sensor and joystick data to the MQTT broker to be consumed by a home automation server (e.g., Home Assistant). In addition, it also subcribes to an LED topic to display payloads published to the broker. For instance, when a home automation publishes a message to the LED topic, the SenseHAT will consume and display it on the LED matrix.
Note
PEP668 makes it so pip
won't install packages outside a virtual environment if packages are being managed by an external package manager (e.g., apt
, apk
). In order to do so anyway, you need to use the --break-system-packages
flag when running pip install
. The instructions below have been edited accordingly. If you don't want to do that, then the alternative is to use your OS package manager to install the requisites or better yet, use a virtual environment (e.g., conda, venv
).
This application can be installed in two non-exclusive ways. In the first and more typical scenario, you own a SenseHAT module and a compatible RPi board and want to use rpi-sensehat-mqtt
to interface with the SenseHAT over MQTT. In the second and less typical case, you either do not own a RPi or the SenseHAT or both but you want to run a virtual SenseHAT on your Linux desktop environment and interface with it over MQTT. If your case is latter one, then take a look at the section Emulator; otherwise, keep on reading.
For the installation procedure, it is assumed that your Raspberry Pi is running the latest version of the Raspberry Pi OS but the instructions might be compatible with similar distributions for the RPi. To install and use rpi-sensehat-mqtt
, follow the procedures detailed next:
-
If you have not attached the SenseHAT to the RPi yet, go ahead and turn off your RPi and attach the SenseHAT to it. It is strongly recommended to use a male-to-female, 40-pin GPIO extension cable to connect your SenseHAT to the RPi; otherwise, sensor data will be unreliable due to the close proximity to the RPi, which has multiple heat sources (e.g., CPU). Then, log into the CLI of your RPi using your standard user (e.g.,
pi
) or if running a desktop environment, open a terminal. -
Run the commands below to install the
sense-hat
package and other packages we will need. Make sure thatI2C
was enabled afterwards; Otherwise, runsudo raspi-config
and manually turn it on in theInterfaces
section of the utility. You will need to reboot your RPi for the changes to take effect.sudo apt update sudo apt install sense-hat git python3 python3-pip # reboot for the changes to take effect sudo reboot now
-
Test the
sense-hat
installation by running one or more of the Python demos at/usr/src/sense-hat/examples/python-sense-hat
(pressctrl+c
to stop):python3 /usr/src/sense-hat/examples/python-sense-hat/rainbow.py
-
(Optional.) Callibrate the magnetometer. This will install many additional packages and will take some time to complete.
-
Go to your user's home directory and clone this repository:
cd ~ git clone https://github.com/cgomesu/rpi-sensehat-mqtt.git cd rpi-sensehat-mqtt/
-
Update Python's package manager (
pip
) and install the required packages fromrequirements.txt
:pip3 install --break-system-packages --upgrade pip pip3 install --break-system-packages -r requirements.txt
You might notice that this will install the additional packages in your user's
~/.local/bin
directory, so they will not be available globally, which is good. The drawback is that~/.local/bin
is not part of the default$PATH
, which is where your OS will look for executables. To fix this in the current session, run the following:export PATH="$PATH:$HOME/.local/bin"
To make
~/.local/bin
reachable to your user permanently, you need to appendexport PATH="$PATH:$HOME/.local/bin"
to your~/.bashrc
or~/.profile
. -
Finally, edit the
CONFIG.ini
file to match your preferences. This is were most of the configuration options are stored for users to edit.cd ~/rpi-sensehat-mqtt/ nano CONFIG.ini
You should be all set at this point. Head to Usage to learn the specifics about how to run the main logic and interface with the SenseHAT via MQTT.
The main logic is in the rpi_sensehat_mqtt.py
script and most of the configurable variables (e.g., MQTT address and credentials, sensor publish resolution) are in the CONFIG.ini
INI file. You must edit the latter before running the former. (Advanced usage variables can be found in src/constants/constants.py
and as constants in individual modules. Do not change them unless you know what you are doing.)
The main script can be executed in two ways, namely by using the shebang or calling python3
directly:
./rpi_sensehat_mqtt.py
python3 rpi_sensehat_mqtt.py
However, if you run the main script from the CLI, you might notice that it won't output any meaningful messages there. Instead, all messages are logged into logs/rpi_sensehat_mqtt.log
. So, if this is the first time running the script or you are still configuring its options, then open another terminal and make it follow new messages added to the log file whil you run the main logic:
tail -f ~/rpi-sensehat-mqtt/logs/rpi_sensehat_mqtt.log
Then, go back to the previous terminal and run the main script. Your SenseHAT should disaply the welcome_message
on the LED matrix once it has initialized.
If the application closes without you sending an interrupt signal (e.g., ctrl+c
), there's likely a configuration issue. Check the log messages to learn about what the script is doing and any error messages. By default, it will only store INFO
level messages. If you need a more verbose log, edit LOG_LEVEL
to 'DEBUG'
instead.
Once you get the application running successfully, take a look at Run as a Service and Log Rotation to make it run automatically in the background and have your OS manage the log file. The specifics about the MQTT payloads are described next.
The main purpose of this application is to interface with the SenseHAT via MQTT. By default, it will publish/subscribe to the following topic level structure:
zone/room/client_name
in which zone
, room
, and client_name
can be configured in CONFIG.ini
. For example, if the CONFIG.ini
contains
zone = downstairs
room = livingroom
client_name = sensehat01
then the application will publish/subscribe to the following topic:
downstairs/livingroom/sensehat01
As outlined before, the application creates three independent connections with the MQTT broker, namely (a) one to publish sensor data, (b) one to publish joystick directions, and (c) one to subscribe to a LED matrix sub-topic. In all three cases, payloads must be in JSON (or be a dict
or key:value pairs) data format. The specifics of each are explained next.
-
The payload of the sensor connection is published to the following subtopic
sensor/status
, as follows:downstairs/livingroom/sensehat01/sensor/status
and has the following structure:
{ "time" : "time_value", "pressure" : "pressure_value", "temperature" : { "from_humidty" : "temp_value", "from_pressure" : "temp_value" }, "humidity" : "humidity_value", "gyroscope" : { "pitch" : "pitch_value", "roll" : "roll_value", "yaw" : "yaw_value" }, "compass" : { "north" : "north_value" }, "acceleration" : { "x" : "x_value", "y" : "y_value", "z" : "z_value" }, }
-
The payload of the joystick connection is published to the following subtopic
joystick/status
, as follows:downstairs/livingroom/sensehat01/joystick/status
and has the following structure:
{ "direction" : "direction" }
-
Finally, the LED connection subscribes to the following subtopic
led/cmd
, as follows:downstairs/livingroom/sensehat01/led/cmd
and it consumes payloads with the following structure:
{ "led_method" : [x, y, ...] }
in which
led_method
is the name of a valid LED matrix setter method of a SenseHat object (e.g.,"show_message"
) and the list[x, y, ...]
is a list of parameter values to be passed to such a method (["Hello!"]
,[255,0,0]
). This is organized in such a way because the logic will check whether theled_method
is valid and then pass its value as*args
(unnamed expansion) to the method.Of note, the payload can contain more than one method as well and they will be executed sequentially:
{ "led_method1" : [], "led_method2" : [x,y,r,g,b] }
Here is an example of payload consumed by the LED client and what it displays on the LED matrix as a result:
{ "load_image" : ["/home/pi/rpi-sensehat-mqtt/assets/battery/battery-75.png"], }
(Other battery states I made are in
assets/battery/
. Checkassets/pixel_art/
for addtional images that can be displayed on the LED matrix.)
To run rpi_sensehat_mqtt.py
in the background, you can make use of the systemd unit file in the systemd/
dir. To enable and start it, follow these instructions:
-
(Optional.) Edit the unit file to your liking and double check the paths to ensure they are pointing to the right ones--namely, check the paths in
ExecStart
.cd ~/rpi-sensehat-mqtt/systemd/ nano rpi_sensehat_mqtt.service
-
Enable the unit file and start it (requires
root
permission):sudo systemctl enable "$HOME"/rpi-sensehat-mqtt/systemd/rpi_sensehat_mqtt.service sudo systemctl start rpi_sensehat_mqtt.service
-
You may check its status afterwards:
systemctl status rpi_sensehat_mqtt.service
And remember to take a look at its logs if the service is not running correctly.
If the service is up and running, you are all set here.
The rpi_sensehat_mqtt.py
script stores log messages in the logs/rpi_sensehat_mqtt.log
file and if unchcked, such a file will grow forever. You can always manually remove old entries but this is best done by making use of your OS log rotation utility, namely logrotate
. To do so, follow the steps next:
-
(Optional.) Edit the preconfigured logrotate file to your liking. Of note, if you're not following the guide here and placed the log files elsewhere, make sure to point to their correct location in the logrotate file.
cd ~/rpi-sensehat-mqtt/logrotate.d/ nano rpi_sensehat_mqtt
-
(Optional.) Test your logrotate cofiguration file:
logrotate -d rpi_sensehat_mqtt
which should print something like this:
WARNING: logrotate in debug mode does nothing except printing debug messages! Consider using verbose mode (-v) instead if this is not what you want. reading config file ../logrotate.d/rpi_sensehat_mqtt Reading state from file: /var/lib/logrotate/status error: error opening state file /var/lib/logrotate/status: Permission denied Allocating hash table for state file, size 64 entries Handling 1 logs rotating pattern: /home/pi/rpi-sensehat-mqtt/logs/rpi_sensehat_mqtt.log weekly (3 rotations) empty log files are not rotated, log files >= 1048576 are rotated earlier, old logs are removed considering log /home/pi/rpi-sensehat-mqtt/logs/rpi_sensehat_mqtt.log Creating new state Now: 2023-01-03 11:39 Last rotated at 2023-01-03 11:00 log does not need rotating (log has already been rotated)
-
Create a symlink of logrotate file to the directory monitored by
logrotate
and change the ownership toroot
(this requiresroot
permission):sudo ln -s "$(pwd)"/rpi_sensehat_mqtt /etc/logrotate.d/rpi_sensehat_mqtt sudo chown root rpi_sensehat_mqtt
That is it. The log file should be rotated automatically during the next logrotate run--this is usually done automatically by your OS.
In this section, I described how to integrate rpi-sensehat-mqtt
with a few home automation applications.
In Home Assistant (HASS), there are many ways to integrate with MQTT devices. For manual MQTT integrations, one must edit the configuration.yaml
file to add new mqtt:
YAML entries for the device. To illustrate, we can create a new sensor entity for pressure and temperature from humidity by adding the following to the HASS configuration.yaml
:
# Example configuration.yaml entry
mqtt:
sensor:
- name: "SenseHAT - Pressure"
state_class: measurement
device_class: pressure
state_topic: "downstairs/livingroom/sensehat01/sensor/status"
unit_of_measurement: "hPa"
value_template: |-
{{ value_json.pressure }}
- name: "SenseHAT - Temperature"
state_class: measurement
device_class: temperature
state_topic: "downstairs/livingroom/sensehat01/sensor/status"
unit_of_measurement: "°C"
value_template: |-
{{ value_json.temperature.from_humidity }}
Interacting with the led device, however, is a little bit more complicated because you need to configure HASS to send specific payloads (see Usage). This is best done by first writing Scripts in your HASS instance that make use of the mqtt.publish
service. Then, whenever customizing your dashboard or automation, you can call such scripts to publlish the desired payloads. Here is an example of script to turn off the LED matrix:
# Example configuration.yaml entry
script:
sensehat_led_clear:
alias:
sequence:
- service: mqtt.publish
data:
topic: "downstairs/livingroom/sensehat01/led/cmd"
payload: |-
{"clear" : ""}
retain: false
Now you can call the sensehat_led_clear
script from within your HASS dashboard (or via an automation) in order to clear the LED matrix on the SenseHAT.
If you do not own a RPi or a SenseHAT or both, you can emulate the SenseHAT on pretty much any system via the SenseHAT Emulator. This is particularly useful for development but you can also use your virtual SenseHAT to send (and to receive) messages from the MQTT broker just as if you had a physical SenseHAT. Check the sense-emu
installation instructions and give it a try.
In apt
based distros (e.g., Debian, Ubuntu, Rasbperry Pi OS), this can be done via terminal as follows:
-
Install prerequisites:
sudo apt install python3 python3-pip python3-gi python3-gi-cairo
-
Install
sense-emu
viapip3
for the current user:pip3 install --break-system-packages --upgrade pip pip3 install --break-system-packages sense-emu
-
Ensure that
$HOME/.local/bin
is reachable in your user's$PATH
:export PATH="$PATH:$HOME/.local/bin"
-
(Optional.) The command above will only make your user's
.local/bin
dir reachable for the duration of the current session. To permanently add it to your$PATH
, append the command to your~/.bashrc
or~/.profile
. -
Launch the SenseHAT GUI:
sense_emu_gui &
-
Now in your
rpi-sensehat-mqtt
dir, set (edit and save)SENSEHAT_EMULATION
insrc/constants/constants.py
as follows:SENSEHAT_EMULATION = True
You are done. Now just run rpi-sensehat-mqtt.py
as described in Usage and interface with the SenseHAT via the GUI (sense_emu_gui
).
For development, it's recomended to create a virtual environment to manage packages and then use the sensehat emulator. On the projet root directory, run the following to create the virtual environment and activate it:
python3 -m venv .venv/
source .venv/bin/activate
Now, proceed with the standard pip3
installs described in Install and Emulator but observe the following notes:
-
There's no need to use the
--break-system-packages
flag here because we are indeed using a virtual environment. -
The venv will ignore system-wide packages required for running the emulator but we can fix this issue by installing a few of its requirements inside the venv as follows:
# build dependencies sudo apt install libgirepository1.0-dev # install gi on the local env pip3 install PyGObject
Launch the emulator:
sense_emu_gui &
You gonna need both a MQTT broker/server and client to properly debug stuff. My suggestion is to use one of the various public servers out there (e.g., HiveMQ, Mosquitto) and use MQTT Explorer as client. If you are going to use the latter, make sure to edit the Advanced options in the connection window as follows:
- Remove the global
#
and sysSYS/#
topics; - Set a topic for your own temporary use, such as
downstairs/livingroom/sensehat01/#
; - Configure your
CONFIG.ini
accordingly.
Note
This should go without saying but do not publish personal info on public servers and do not abuse the service. Public servers are for temporary testing.
Start developing. When you are done, deactivate and delete the virtual environment:
deactivate
rm -rf .venv/