This is a brief update on some subsequent work done to my Matrix Display project.
The first thing I completed was to retire my old bus timetable parser script which was written in Golang. In its place I have written my very first Home Assistant integration! There was a bit of a learning curve for me; I hadn’t written a single line of Python until that point, but I managed to get a prototype working in an afternoon and tidied it up to a presentable state the next day. The great thing about using an integration instead of a custom script that just talks to the display is I can now show bus information in other places beside the Matrix Display, like my Home Assistant’s dashboard. I haven’t fully tidied this up; the information on my dashboard is rendered through a template, and not a custom dashboard panel, which is what is warranted. None the less, the result is perfectly adequate, in my view, and more importantly doesn’t involve writing any JavaScript:

The integration is serviceable but far from complete. It has two main limitations: it must be installed by hand and it must be configured by modifying YAML files, that is to say it has no configuration UI.
Naturally the integration is also targeted at the Matrix Display: it has a summary “sensor” for each configured bus stop which is the ETAs of the next few busses, just as the previous Go script presented the same summary string over MQTT.
My very first, of many I hope, custom Home Assistant integration has a GitHub repo. It should be useful to anyone living on the south coast of England who happens to use the busses provided by Go South Coast, and of course they have to be using Home Assistant.
Next, in Part 3 of this series I showed a picture of the main board of the display attached to an I2C sensor board. The board in question is a BME680 (PDF) breakout board. The BME680 is an interesting device; it has ability to report on:
- Temperature
- Humidity
- Air pressure
- Air quality
The sensors are factory calibrated unlike many other cheaper parts, and are therefore much more accurate.
That last sensor is intended for reporting on air particulates, Volatile Organic Compounds and the like. To be honest, its functionality and method of operation are mostly out of my comfort zone. In any case extracting an air quality reading from the raw binary data is a lot more involved than the other three, which themselves require some fairly heavy numeric processing. That is, it’s not as simple as formatting a value from a whole number and a fractional byte, like it is in the typical I2C or SPI temperature sensor. Perhaps I will look at obtaining a reading for air quality in the future, but for now only temperature, humidity and air pressure are reported on, and fed out via MQTT to Home Assistant.
Note that my Matrix Display code can be built with or without support for an attaching BME680 board. Without it the reported temperature data will come from the temperature sensor embedded in the DS3231 (PDF) RTC IC.

The cost of these little breakout boards is about 10 pounds on Amazon or eBay. I think they make a fine addition to any project that requires accurate climate data. Though I’m using I2C to connect the sensor board to the main board, the boards and the sensor itself also support SPI.
In use this works very well. The BME680 is a fantastic sensor and in my own, admittedly basic, testing seems to indicate in produces accurate numbers, and to a greater precision then all of my other climate sensors.
The last thing I’ve been working on is some improvements to the display software itself.
I’m especially pleased that the display now fades in and out as it switches between the different information screens. Previously the transition was performed in a single frame, which worked but was a little jarring. The transition is now done by fading the current screen to black and then fading the new screen in. The total transition time is about a second; it gives a nice pleasing effect.
I’ve also extended the notification mechanism and introduced a critical flag. Notification data passed over MQTT is now a JSON hash, whereas before it was a simple string. A boolean is used to indicate if the message is of “critical” importance. This is to introduce some consistency with the other notification methods in my Home Assistant setup, which include Pushover for notifications to my phone, which supports a critical flag in its message structure. Within Pushover, a critical notification will automatically repeat in the phone app until it is dismissed, and the noise can be made annoying enough that it can’t be ignored. In the case of messages scrolling across the LED matrix display the background and the message text itself will be in red, the message will scroll three times across the screen, and the beeps from the buzzer will sound a little more “urgent”. If the critical flag is not set the message appears as it did before.
The last area I’ve been working on enhancing is the utility of the display boards built in piezo buzzer.
The buzzer was and is used to announce two events:
- On an aforementioned notification message the buzzer would beep a few times to draw your attention to the screen. Two different tone sequences are now possible; one for notifications with the critical flag set, and one for when it is not set, as mentioned above.
- On motion in the porch the buzzer would also beep a few times.
It is now possible to send, via MQTT, a Ring Tone Text Transfer Language (RTTTL) tune and the buzzer will play it back.
RTTTL is what Nokia came up with to make it so people could transfer ringtones to mobile phones in the 1990s. The phones at the time were equipped only with a rudimentary piezo sounder, much like the buzzer mounted to the LED Matrix Display board.
The RTTTL format is a simple text string consisting of three parts separated by colons:
- A tune name field, which is currently unused by the Matrix Display code.
- A header consisting of 3 fields each with a value.
- The notes themselves.
The header fields, each keyed on a single letter (d, o and b):
- The default note value, from a full note to a 1/32 note.
- The default octave, from the 4th octave to the 7th.
- The beats per minute (tempo) of the tune.
The notes themselves are a list of the note letter (A to G, which might also be sharp and indicated with a following hash), along with the note value (from 1 for a full note to 32 for a 1/32 note) and an octave (from 4 to 7). If the note value or octave is omitted then the defaults, set in the header, are used.
Here is a simple tune, the first few bars of the classic rag time tune, The Entertainer:
Entertainer:d=4,o=5,b=140:8d,8d#,8e,c6,8e,c6,8e,2c6,8c6,8d6,8d#6,8e6,8c6,8d6,e6,8b,d6,2c6,p,8d,8d#,8e,c6,8e,c6,8e,2c6,8p,8a,8g,8f#,8a,8c6,e6,8d6,8c6,8a,2d6
The header sets the default note value (a quarter note), default octave (5th) and tempo (140 beats per minute).
For someone familiar with reading music (that isn’t me) it must be quite easy to “hear” the tune from the list of notes.
Writing the parsing code was simple. The error checking is fairly rudimentary; there may be corner cases missing. Certainly unit tests, if I had the inclination, would be useful. As it is my own testing will have to suffice, at least for now. The parser is wrapped in a thin C++ class, with methods to parse the header and extract the next note in the sequence.
Just because it was easy to do, notifications support a user supplied RTTTL tune. If supplied, this is played as the message scrolls across instead of the standard notification beeps. I’m unsure, currently, how I’ll take advantage of this in my Home Assistant setup, with my centralised notification script, but I’m sure I’ll come up with something.
As before, driving the buzzer is done using the PWM hardware in the RP2040 (PDF), which is the MCU used on the Pi Pico W board. The buzzer functionality runs in its own task, which is passed a message block by the MQTT task when it needs to sound a tone either because of a notification, porch motion event, or the user has a particular RTTTL tune they want played.
In use it works pretty well. I’ll update this post once I’ve made a short video showing off the new features.
The next post will get us back on the iCE40HX4 FPGA development board…