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-hatpackage and other packages we will need. Make sure thatI2Cwas enabled afterwards; Otherwise, runsudo raspi-configand manually turn it on in theInterfacessection 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-hatinstallation by running one or more of the Python demos at/usr/src/sense-hat/examples/python-sense-hat(pressctrl+cto 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/bindirectory, so they will not be available globally, which is good. The drawback is that~/.local/binis 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/binreachable to your user permanently, you need to appendexport PATH="$PATH:$HOME/.local/bin"to your~/.bashrcor~/.profile. -
Finally, edit the
CONFIG.inifile 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.pypython3 rpi_sensehat_mqtt.pyHowever, 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.logThen, 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 = sensehat01then 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/statusand 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/statusand has the following structure:
{ "direction" : "direction" } -
Finally, the LED connection subscribes to the following subtopic
led/cmd, as follows:downstairs/livingroom/sensehat01/led/cmdand it consumes payloads with the following structure:
{ "led_method" : [x, y, ...] }in which
led_methodis 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_methodis 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
rootpermission):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
logrotateand change the ownership toroot(this requiresrootpermission):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: falseNow 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-emuviapip3for the current user:pip3 install --break-system-packages --upgrade pip pip3 install --break-system-packages sense-emu
-
Ensure that
$HOME/.local/binis reachable in your user's$PATH:export PATH="$PATH:$HOME/.local/bin"
-
(Optional.) The command above will only make your user's
.local/bindir reachable for the duration of the current session. To permanently add it to your$PATH, append the command to your~/.bashrcor~/.profile. -
Launch the SenseHAT GUI:
sense_emu_gui & -
Now in your
rpi-sensehat-mqttdir, set (edit and save)SENSEHAT_EMULATIONinsrc/constants/constants.pyas 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/activateNow, 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-packagesflag 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.iniaccordingly.
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/