This post was written with love by Andy Herd, without any AI.
The problem
I’ve had solar panels on my house for about 5 years now. I got them not for purely financial reasons. Instead, my main motivation was to try and do something positive about my impact on the planet: to try and reduce my dependence on fossil fuels. Despite working from home most of the time, I really struggle to make the best of my renewable power. I really need a nudge to say “hey there’s free power now” to remind me to go and make the best of it. I haven’t had this signal and so most of the time the majority of the energy I generate goes back to the grid. In other words, my solar panels haven’t been working for me as well as they could.
Also, despite choosing to only buy 100% renewable energy, the national grid doesn’t work like that. Even though I have a heat pump and so I use mostly electricity and virtually no gas, there are still fossil fuels being burned to heat my home. Scotland’s doing pretty good at renewable energy. But, still, there are periods of high demand in the national grid which exceed the renewables capacity. When this happens, it’s known as the grid being “dirty”. By changing our consumption habits to spread this demand out, we can reduce our dependence on fossil fuels. Yet, again, there’s something missing: I really need a signal of some kind at the exact moment it’s happening to prompt me to take action.
What to do about it?
I set out to build something to give me a nudge when I have an opportunity to change my behaviour. We can distil the paragraphs above into two use cases:
- Hey, you’ve got a surplus of generated electricity just now. You can go and put the dishwasher or washing machine or whatever on and it’s basically free.
- The grid is dirty just now and you’re using lots of power. See if you can turn the power down for a bit.
I spend a lot of time at my desk at home. My original idea had been to build a little app to send me info on an e-ink screen. But that idea stalled and it spent most of the time gathering dust on a shelf. So I pivoted in direction and instead bought a thermal receipt printer to live on my desk, and set out to build something to dispatch a little message to the printer whenever there’s an opportunity to change my behaviour. The sound of something being printed is just enough to grab my attention for a moment.
It took me a little while to figure it all out. I figure this might be useful to others. So I’m sharing what I built in the hope that it makes it easier for others to change their behaviour and we can all use less fossil fuels.
We’ll be using a technology called MQTT which is intended for low-bandwidth lightweight publish/subcribe applications. It’s perfect for internet of things (IoT) applications.
Shopping list
We need a few components. Here’s what I used. The precise make and model of computer and printer don’t really matter too much:
- There’s a company called Hildebrand/ Glow who make a little in home display (”IHD”). It’s got more capabilities than the IHD which my electricity company sent me. Notably it can send messages over MQTT on a local network. It’s £70 at the time of writing. https://shop.glowmarkt.com/products/display-and-cad-combined-for-smart-meter-customers
- A small computer of some kind to run an MQTT server which will receive messages and run some scripts to print the messages. Despite the availability of the pi v5 which is a bit more powerful, I chose a raspberry pi model 4b, 1GB RAM. It’s a little underpowered but that’s ok for now. Considering its capabilities, it’s wonderfully cheap at £42.60 including a power supply.
- A micro SD card which will be our “hard drive” for our pi. £8.99 for a £64 GB card. That’ll do.
- A thermal printer. Nice thing about thermal printers is they don’t need any ink, they print quickly, and they can also print very small messages. I chose a Star TSP100ii receipt printer, which is often used at the tills in stores. A thing to watch out for is that the features of these models seem to often have either usb or ethernet connectivity, sometimes not both. I chose USB connectivity. At the time of writing there are a variety of similar models available on ebay for £30-40.
- Some till receipt paper. I got an enormous box of it for £15. This should keep me going for a good few years. I chose EPISENT paper which is free of BPA.
- We need a local wifi network running and having the admin password available is probably the easiest way of finding out our IP address of the raspberry pi.
- I chose to set up raspberry pi os in “headless” mode, i.e. accessed through only an ssh terminal. This means that the operating system has far less overhead as there’s no need to run a full desktop environment. Though it relies on having another computer of some kind to be able to launch the ssh sessions from. I’m using a laptop running macOS for this. I’ll call this our “main laptop” for the purpose of this article.
I already had a wifi and a laptop. The rest of the parts for this project cost me approximately £157.
This article focuses a lot on getting a printer up and running, but the outputs could easily be directed to another place. If printing doesn’t suit you then feel free to skim over all of that and just have a nosy at my scripts. https://github.com/herdingdata/thermal-print-utils
If you’re running windows, I’m sorry to hear that. Many of the commands will probably be different on your environment. Hopefully this post gives you enough of an idea of what I’m doing to be able to figure out how this translates to your environment.
Setting up a new raspberry pi
I’m starting from scratch with a completely new pi and a fresh install of Raspberry Pi OS. From our main laptop:
- Download, install and open raspberry pi imager https://www.raspberrypi.com/software/
- Connect the SD card.
- Choose device → raspberry pi 4
- Operating system “choose OS” → select “other” → then choose “raspberry pi os lite (64 bit)”
- Choose storage → select your SD card
- Press “next”. We’ll then get a prompt to edit settings. We definitely want to edit settings. There are a couple of things we need to do here:
- We input the SSID and password for our wifi so that our pi can see the network.
- We choose a username and password which we’ll use to login. My username is
andyrpi
. - I also like to choose an ssh hostname, but this is optional.
Once it’s done we can put the microSD card into our pi and connect the power. If we log in to our router’s admin interface (likely something like https://192.168.1.1 in a browser) we should see that our raspberry pi has been given an IP address. Take a note of this IP address, for example mine is 192.168.1.67
.
Because we’ll be setting up a new MQTT server, we need to assign our pi a static IP address. This will enable us to configure other devices (like our glow IHD) to send MQTT messages to a known destination. The exact steps to do this vary depending on your router.
Now we should be able to login to our pi:
ssh andyrpi@192.168.1.67
# we'll then be prompted for the password we set
Optional: ssh config makes connecting easier
I like choosing a fictional scifi spacecraft for all my computing devices. “Little star trolley” seems apt for this low-powered little computer:
A small craft admired by both Ford and Zaphod, who spotted it in the car park outside Milliways. It was small but extraordinary, and “pretty much a rich kid’s toy”. It resembled nothing so much as a paper dart, about twelve feet long, and was made of thin yet tough metal foil. At the rear end was a small horizontal two-man cockpit, and it also contained a tiny charm-drive engine, which was not capable of moving the craft at any great speed. (source)
We need an ssh key for our main laptop. You may already have a public key stored at ~/.ssh/id_rsa.pub
. If not, you can generate one. From our main laptop:
# generate an ssh public/private key pair
ssh-keygen
# now we copy that key to our pi
ssh-copy-id andyrpi@192.168.1.67
Edit ~/.ssh/config
to look something a little like this
Host littlestartrolley
Hostname 192.168.1.67
User andyrpi
Port 22
IdentityFile /Users/andy.herd/.ssh/id_rsa
Now we can do the following to connect:
ssh littlestartrolley
Installing our print drivers
macOS
First I wanted to check my “new” (used) printer was working.
I downloaded the “CUPS driver for macOS” from the manufacturer. https://starmicronics.com/support/products/tsp100iiu-support-page/
I installed the driver and added the printer. I think I might have set it as default accidentally.
Save literally anything to a text file, which for this example we will call hello.txt
The bash command lp [filename]
will chuck it to the printer
echo "hello" > hello.txt
lp hello.txt
Wow… that worked! That was easier than I expected: so far it’s the least faff of setting up of any printer I’ve ever owned in my life! This bodes well…
Raspberry Pi
Ok now let’s see if we can get this thing installed on a raspberry pi.
First we grab the linux driver. I downloaded the linux cups driver to my main laptop. https://starmicronics.com/support/products/tsp100iiu-support-page/
Now we chuck the file onto pi using scp
# from main laptop
scp /Users/andy.herd/Downloads/Star_CUPS_Driver-3.15.0_linux.tar.gz andyrpi@192.168.1.67:~
My first impression was that this driver seems to be intended for systems which run rpm
. Which is… not included in raspbian/raspberry pi OS. It took a little searching to figure out the best way to proceed.
I found a few forum posts from people who had also struggled to install the driver. For example this thread https://forums.raspberrypi.com/viewtopic.php?p=212825 talked about the need to comment out two lines:
@if ! (ls /usr/lib | grep libcups.* > /dev/null); then echo "libcups not available - exiting"; exit 1; fi
@if ! (ls /usr/lib | grep libcupsimage.* > /dev/null); then echo "libcupsimage not available - exiting"; exit 1; fi
… after some research I discovered that I didn’t need to do this step. I guess Star have updated the driver since this post of 12 years ago. I was able to find the source code from within the downloaded archive and install it directly.
Ok here’s how I installed it:
ssh littlestartrolley
# install cups, which is a linux tool for printing
sudo apt-get install cups
# I'm not entirely sure if we need all three of these on the next line but I had them installed and it worked ¯\_(ツ)_/¯
sudo apt-get install libcups2-dev libcupsimage2-dev cups-bsd
# extract the file
cd Star_CUPS_Driver-3.15.0_linux/Driver
tar -xvf Star_CUPS_Driver-3.15.0_linux.tar.gz
cd Star_CUPS_Driver-3.15.0_linux/SourceCode
#now extract the source code that's inside
tar -xvf Star_CUPS_Driver-src-3.15.0.tar.gz
cd Star_CUPS_Driver/
# install
sudo make
sudo make install
At this point we have the drivers installed, but we do not have a print queue. So we still have a bit more to do before we can print. The output of the last step above mentions this:
Add printer queue using OS tool, http://localhost:631, or http://127.0.0.1:631
I only have ssh access to my py. Substituting localhost with the IP address of my and attempting to navigate to that web address from my main laptop did not work. So, I need another tool to be able to add this print queue.
Many, many searches later I learned that lpadmin
is the tool for editing print settings, and lpstat
is a useful tool for finding information about what’s going on.
At this point, make sure that your printer is plugged in to a USB port on your raspberry pi!
Some resources which might help:
- Some CUPS terminal commands (though, annoyingly, no chat about printer queues) https://www.cups.org/doc/admin.html
- Some documentation about CUPS print queues https://wiki.debian.org/CUPSPrintQueues#lpadmin
- The commands
man lpadmin
andman lpstat
were pretty helpful: they show all the available parameters. - The command
lsusb -v
shows some useful info. I dunno how it’s useful. But I’m keeping it here in case it comes in handy.
The docs for CUPS print queues mention that we need to run this command:
lpadmin -p <queue_name> -v <device-uri> -m <PPD_or_everywhere_or_driverless_or_raw> -E
… which is… not particularly helpful? How do I find those bits of information?!? Many more searches and trial/error later I discovered the following:
- Print queue name is made up, it can be anything you like. I chose
star_tsp100ii_cut
- The device uri is prefixed with
usb://
and can be found in the output ofsudo lpinfo -v
(as long as your printer is plugged in) - The
PPD_or_everywhere_or_driverless_or_raw
is a path which essentially contains the drivers.“PostScript Printer Description (PPD) files are created by vendors to describe the entire set of features and capabilities available for their PostScript printers.” (source)
The documentation of man lpadmin
shows us these clues:
-v "device-uri"
Sets the device-uri attribute of the printer queue. Use the -v option with the lpinfo(8) command to get
a list of supported device URIs and schemes.
-m model
Sets a standard PPD file for the printer from the model directory or using one of the driver interfaces.
Use the -m option with the lpinfo(8) command to get a list of supported models. The model "raw" clears
any existing PPD file and the model "everywhere" queries the printer referred to by the specified IPP de‐
vice-uri. Note: Models other than "everywhere" are deprecated and will not be supported in a future ver‐
sion of CUPS.
Ok, so let’s grab the device URI from sudo lpinfo -v
andyrpi@littlestartrolley:~ $ sudo lpinfo -v
file cups-brf:/
network ipp
network beh
direct usb://Star/TSP143%20(STR_T-001)
network https
network ipps
network socket
network http
network lpd
And we also we grab the ppd file from sudo lpinfo -m
(below is an excerpt):
star/sp742.ppd Star SP700 Cutter (SP742)
star/sp747.ppd Star SP700 Cutter (SP747)
star/sp712.ppd Star SP700 Tear Bar (SP712)
star/sp717.ppd Star SP700 Tear Bar (SP717)
star/tsp143.ppd Star TSP100 Cutter
star/tsp113.ppd Star TSP100 Tear Bar
star/tsp143gt.ppd Star TSP100GT Cutter
star/tsp113gt.ppd Star TSP100GT Tear Bar
It’s kinda weird that Star seem to use the model names TSP100 and TSP143 interchangeably. Even though my printer is a TSP100, the driver to use was TSP143.
Finally, we now have enough information to create our print queue. Here are the commands I used:
# create the print queue
sudo lpadmin -p star_tsp100ii_cut -v "usb://Star/TSP143%20(STR_T-001)" -m "star/tsp143.ppd Star TSP100 Cutter" -E -P /usr/share/cups/model/star/tsp113.ppd
# set our new print queue as the default queue
sudo lpadmin -d star_tsp100ii_cut
So… are we done here? Can we print now?
lpstat -t
# scheduler is running
# system default destination: star_tsp100ii_cut
# device for star_tsp100ii_cut: usb://Star/TSP143%20(STR_T-001)
# star_tsp100ii_cut accepting requests since Wed 19 Jun 2024 22:02:51 BST
# printer star_tsp100ii_cut is idle. enabled since Wed 19 Jun 2024 22:02:51 BST
echo "hello file" > hello.txt
lp hello.txt
echo "hello echo" | lp -s
… yes! Our printer does indeed work!
Image alt: A photo of two very small printouts on receipt paper which are chained together. One says “hello file”. The other says “hello echo”.
Let’s get MQTT running
Our glow/hildebrand energy meter IHD can send MQTT messages on a local network. But, first we need a server to run MQTT so that we have a destination for these messages to be sent to.
This pi is probably underpowered: it’s a model 4b 1gb. But let’s see if we can get away with using it to host MQTT anyway.
I ran the following commands to install mqtt. If you’re in need of a bit more information, there’s a nice blog post with lots more detail here. https://randomnerdtutorials.com/how-to-install-mosquitto-broker-on-raspberry-pi/
# install
sudo apt install -y mosquitto mosquitto-clients
# enable service
sudo systemctl enable mosquitto.service
# test it's working (don't worry about error: address already in use, we'll fix in a mo)
mosquitto -v
# give it some config
sudo nano /etc/mosquitto/mosquitto.conf
# add these at end:
listener 1883
allow_anonymous false
# ok we need a user. Let's create one called glow_ihd and one for andy
# after we enter these commands we are prompted to enter a password
sudo mosquitto_passwd -c /etc/mosquitto/passwd glow_ihd
# the -c tells it to create a brand new file, so we omit that in order to add a second user
sudo mosquitto_passwd /etc/mosquitto/passwd andy
sudo reboot
# more config
sudo nano /etc/mosquitto/mosquitto.conf
# this line at TOP
per_listener_settings true
# and this at bottom
password_file /etc/mosquitto/passwd
sudo systemctl restart mosquitto
sudo systemctl status mosquitto
Great. I think we have an MQTT server now? Let’s configure the glow IHD to send MQTT messages. We’ll need the ip address we reserved earlier and the glow mqtt credentials we just created. There’s a nice blog post here about which settings to change. https://www.speaktothegeek.co.uk/2022/06/hildebrand-glow-update-local-mqtt-and-home-assistant/
We should now be able to subscribe to our topic and see some messages getting posted every 10 seconds or so. Topics are hierarchical in MQTT. The #
in the topic name is an MQTT hint to say “subscribe to all subtopics”.
# subscribe to topic
mosquitto_sub -d -t 'glow/#' -u andy -P redacted
You can press ctrl + c
to interrupt this command. The output is showing us a few things:
- We have a device id as the second level of the hierarchy. Take a note of this id.
- We’re getting messages to several topics:
glow/[device id]/STATE
,glow/[device id]/SENSOR/electricitymeter
andglow/[device id]/SENSOR/gasmeter
- There’s loads of data here! We can see the amount of energy I’m consuming right now, and various stats about import and export over different time periods. This is useful!
I really would like to get TLS set up so that I can add a layer of encryption, however I haven’t found any options in the glow IHD to be able to configure this. So I’m doing without for now. If anyone from Hildebrand/Glow is reading this: thank you for building such a useful product & please add this feature!
If you’re having any difficulty getting MQTT up and running, I highly recommend posting some test messages manually. You can make up any random topic to post to. There are many apps available which made this very easy to do from an ipad.
Now the fun bit: we’ve got all the infrastructure running and we can print some useful content
I wrote a little collection of bash scripts as utilities to print things. These aren’t the most well-polished of scripts. But they do the job. https://github.com/herdingdata/thermal-print-utils
It took a lot of self-diligence to use purely linux OS tools instead of leaning to my usual goto of python. But we’re running a pi with very little resources, so let’s keep it simple.
Side note: I found someone else has built a similar collection of scripts. There are a lot of features in here! I didn’t have much luck running these with my printer – many of the settings didn’t have any effect. But they might be useful for other models of thermal printers. https://github.com/michaelkitson/escpos.sh
Get our utils scripts checked out onto our pi
From our pi:
# generate an ssh key
ssh-keygen
cat ~/.ssh/id_rsa.pub
# now chuck the key onto github in https://github.com/settings/keys
sudo apt install git
git clone git@github.com:herdingdata/thermal-print-utils.git
# we now have a directory with our scripts at ~/thermal-print-utils
There are no further installation steps, all we need is the scripts to exist on our pi.
Print a thing: print_txt.sh
When you have some text and you just want to print it. This script:
- Expects a filepath to be its only argument.
- Adds a timestamp as the first line.
- Pads the first line of the file inside some hash symbols to emphasise the title.
- Wraps everything nicely at 28 characters, which is how many characters I can get in my 80mm receipt paper.
- Sends everything to the default printer.
echo "some text" > hello.txt
echo "maybe a second line of a message to show off how well we're wrapping content" >> hello.txt
./thermal-print-utils/print_txt.sh hello.txt
Image alt:
A photo of a receipt which is not a receipt. It starts with a timestamp of 2024-06-23 15:20:39. The rest of the text reads:
############################
some text
############################
maybe a second line of a
message to show off how
well we’re wrapping content
Print information about the current electricity usage: print_elec_now.sh
This script waits up to 10 seconds for an MQTT message and then chucks the entire message to our printer.
We need a bit of config to provide the script with authentication credentials for MQTT, and also the glow device id we took a note of earlier so that we know which topic to subscribe to.
I created a new file ~/mqtt_creds
which looks a little like this:
export MQTT_USER=replaceme # we created this user earlier
export MQTT_PASS=REDACTED_REPLACEME
export GLOW_DEVICE=REDACTED_REPLACEME # the glow device id we took a note of earlier
To run the script:
source mqtt_creds && ~/thermal-print-utils/mqtt/print_elec_now.sh
Example: https://mastodon.scot/@herdingdata/112651028181278105
Image alt: A piece of receipt paper which is not a receipt. The first line is a header with the date. Then there is a title surrounded by # symbols for emphasis which reads “ELEC NOW: 0.313 kW”.
Below there is some json data showing my export and import kWh by day, week and month. I have folded the paper to redact the MPAN id.
Prompt when there’s free electricity now: print_free_power_prompt.sh
Now we’re getting to the useful bit: a prompt when there’s free energy right now and you can go and put on some home appliances.
We rely on the same MQTT & glow authentication as the previous step.
To run the script:
source mqtt_creds && ~/thermal-print-utils/mqtt/print_free_power_prompt.sh
Example: https://mastodon.scot/@herdingdata/112655005477435232
Image alt: A picture of a receipt that’s not a receipt. It’s still in the tray of the receipt printer. Because… a store receipt printer is a totally normal thing to have on one’s desk.
The text on the paper reads:
2024-06-21 15:01:14
############################
ELEC NOW: 0 kW
############################
—————————-
ZOMG
YOU HAVE FREE
POWER
—————————-
Prompt to reduce demand when the grid is “dirty”: print_high_intensity_prompt.sh
Ok this next bit required one more piece of information: the current carbon intensity of the grid right now. Conveniently the UK National Grid already have an API for this. It requires no authentication and it gave me precisely the information I needed. https://api.carbonintensity.org.uk
We could use the carbon intensity data for the whole of the UK, but there’s regional data available so it makes sense to use the most detailed data available. We need one additional line of config in ~/mqtt_creds
:
# in addition to the 3 lines which we already added:
export POSTCODE=EH1 # First section of postcode. 3-4 characters. E.g. NW1
There are a few things going on in this script:
- As before, we download an MQTT message with our current consumption
- We set an arbitrary threshold of 0.5 kW for usage. This is a little more than my usual base load for the house. But it’s low enough that if I’m running an appliance such as my heat pump or the oven, the threshold will be exceeded.
- We download the 24 hour carbon intensity forecast from the national grid. From this response, we parse a couple of useful pieces of information:
- What is the carbon intensity right now? If it’s
moderate
,high
orvery high
this is high enough to warrant a message. - We also grab the forecast for carbon intensity for the next few hours. In other words, if we turn appliances off for a while, when will it be ok to turn them back on again?
- What is the carbon intensity right now? If it’s
To run the script:
source mqtt_creds && ~/thermal-print-utils/mqtt/print_free_power_prompt.sh
Example: https://mastodon.scot/@herdingdata/112655664002543088
(This image doesn’t make much sense with the electricity usage now being 0 and the carbon intensity being low – I’ve disabled the if conditional for testing purposes – but you get the idea).
Image alt: A receipt that’s not a receipt. The full text reads:
2024-06-21 17:49:42
############################
USE LESS ENERGY NOW IF POSS
############################
Elec now: 0 kW
Grid carbon now: very low
6hr intensity forecast:
time ,intensity
17:30,very low
18:00,very low
18:30,very low
19:00,very low
19:30,very low
20:00,very low
20:30,very low
21:00,very low
21:30,very low
22:00,very low
22:30,very low
23:00,very low
Schedule these scripts to run regularly
We’re almost at the end now. We have one last thing to do: set up a schedule to run our scripts regularly. For this we use crontab.
- At the top of the hour between 7am – 10pm on a weekday, tell me if I have free power
- Every 15 minutes between 7am – 10pm, give me a nudge to reduce my power consumption if I’m using a lot and the grid is dirty.
For editing crontab files it’s worth mentioning that we can’t rely on the ~
shortcut to refer to our home directory, and we also don’t have source
available but we can use .
instead.
# to edit our cron schedule
crontab -e
# here are the two lines I added
0 7-22 * * 1-5 . /home/andyrpi/mqtt_creds && /home/andyrpi/thermal-print-utils/mqtt/print_free_power_prompt.sh >> /var/log/cron
0,15,30,45 7-22 * * * . /home/andyrpi/mqtt_creds && /home/andyrpi/thermal-print-utils/mqtt/print_high_intensity_prompt.sh >> /var/log/cron
Summary
Here’s what we did:
- Provisioned a new raspberry pi
- Installed our thermal printer drivers
- Created an MQTT server on our raspberry pi
- Configured our glow IHD to send MQTT messages
- We scheduled some scripts to periodically print us messages to prompt us to change our behaviour.
Did we achieve what we set out to do? Let’s look back at the use cases we wanted to tackle:
- Hey, you’ve got a surplus of generated electricity just now. You can go and put the dishwasher or washing machine or whatever on and it’s basically free. YES ✅
- The grid is dirty just now and you’re using lots of power. See if you can turn the power down for a bit. YES ✅
Thanks for reading. I hope that sharing this post and the accompanying code helps make it easier for others to reduce our dependence on fossil fuels.