Introduction: Inky_pHAT Weather Station

About: Scientist working in in-vitro diagnostics industry. Playing with all types of sensor as a spare time hobby. Aiming for simple and inexpensive tools and projects for STEM, with a bit of science and a bit of sil…

I here would like to describe a very simple and compact, Raspberry Pi Zero-based weather station, which displays the values measured by a BME280 temperature/pressure/humidity sensor on a Pimoroni Inky pHAT e-paper/e-ink display. To allow the connection of sensors and the pHAT to the GPIO of the Pi I placed a Pimorini Pico HAT hacker with two female headers attached between the GPIO and the display. The device has been used to attach several sensors, so the BME280 version described here is just an example.

Unlike LCD displays, e-ink displays keep the image even if power has been switched off. Therefore they are a very good solution if you want to display information that is updated just from time to time, especially to build low energy devices. The major benefit of the monochrome/black version of the Inky pHAT is that updating the display takes just about one second, instead of ten to fifteen seconds required by the three-color versions. See movie.

Adafruit's Blinka library allows to run Circuit Python code on the Raspberry Pi, and Circuit Python samples for a wide variety of sensors are available from Adafruit. A detailed description how to install Blinka and the Circuit Python codes can be found at the Adafruit website. The libraries I tested so far (BMP280, BME280, TSL2591, TCS34785, VEML7065, ...) were working very well, while there were minor problems in some of the example codes.

BME280 is a sensor to measure temperature, humidity and atmospheric pressure. BMP280 breakouts are available from many vendors, including Adafruit, but I here was using a cheap Chinese version. Please be aware that these are using different i2c addresses (Adafruit: 0x77, others: 0x76).

The breakout is connected to the Pi by i2c, and reading the sensor is very simple using the library and example code.


Step 1: Materials Used

A Raspberry Pi Zero, with a male header attached. But any Raspberry Pi version would do.

A Pimoroni Inky pHAT, black/monochrome version, 25€|22£|20US$, at Pimoroni.

A Pimoroni Pico HAT hacker, 2.50€|2£, with two female headers attached, one of them a booster header with longer pins. I have build two different versions, see description below.

A BME280 breakout, AZ Delivery via @ 7.50 €, with header attached.

Elongation jumper cables


A USB power pack, for mobile applications

A housing for the Pi or the device (not shown here)

Step 2: Assembly

  • Solder the female headers to the Pico HAT hacker. Before soldering, check for correct orientation.
    I have build two version of this, for different purposes. One with the down facing booster header placed in the front row and a normal, up/facing header in the back row, and a version with the down facing booster header in the back row, and a right-angle female header in the front row. See images.
    The first version allows to attach and exchange sensors and cables very easy, while the version with the inward facing header does allow to enclose Pi, sensor and Inky pHAT into a housing.
    Alternatively you may solder the cables connecting GPIO and sensor directly to the Pico HAT hacker and/or solder the Pico HAT hacker directly to the GPIO pins. In any case use the minimal amount of solder required.
  • Solder the header to the sensor, if required.
  • Stack the modified Pico HAT hacker unit on the Pi, then add the Inky pHAT. If required, insert some support, e.g. A foam block or stand-offs, for the Inky pHAT.
  • Attach the cables and the sensor, using the 3V, GND, SDA and SCL ports.
    Not all sensors will survive 5V, so please check before you connect them to 5V ports.
  • Install the Blinka library, then install the Circuit Python BME280 library from Adafruit.
  • Install the Inky pHAT library from Pimoroni.
  • Install the example Python code described in a later step and attached to this instructable.
  • Run the code.

Step 3: Using the Device

There are two options to use the device.

The code as shown here shall be started using a screen attached, but then could run without.

With minor modifications to the code you may use crontab to perform measurements at defined time points. This would allow to reduce power consumption even further. Excellent descriptions how to use crontab can be found elsewhere.

In conjunction with a power pack you can build a mobile device and use it to measure the conditions inside or outside, in the fridge, in the sauna, your humidor, the wine cellar, in a plane, ….

Using a Zero W you may not only display the values on the display, but also send them to a server or your website via WLAN, as described elsewhere.

Step 4: The BME280 Script

As mentioned before, you need to install the Adafruit Blinka and Circuit Python BME280 libraries as well as the Pimoroni Inky pHAT library.

The code first initializes the sensor and Inky pHAT, then reads the temperature, pressure and humidity values from the sensor and displays them on screen and e-ink display. Using the time.sleep() command, measurements are taken every minute. Adjust as required. By setting a language parameter, you may change the language used to display the results.

Using the Inky pHAT e-ink display, you first build the image to be displayed in memory before it finally is transferred to the screen using the command. The Inky pHAT library is simplifying the process, offering commands to draw and format text, lines, rectangles, circles or use background images.

In addition to the measured values, the time of measurement is displayed as well.

Please keep in mind that the script as well as the libraries are written in Python 3, so open and run using Py3 IDLE or equivalent.

# A script for the bme280 temperature/pressure/humidity sensor (non-Adafruit version)<br># and the inky pHAT - black version
# version Dec 01 2018, Dr H
# Requires Adafruit Blinka and Circuit Python BME280 libraries
# and the Pimoroni Inky pHAT library

import time
import datetime
import board
import busio
from adafruit_bme280 import Adafruit_BME280
from adafruit_bme280 import Adafruit_BME280_I2C

import inkyphat
import sys
from PIL import ImageFont

inkyphat.set_colour('black')  # for b/w inky phat
inkyphat.set_rotation(180)  # turn display 180°
font1 = ImageFont.truetype(inkyphat.fonts.FredokaOne, 27) # Select standard font
font2 = ImageFont.truetype(inkyphat.fonts.FredokaOne, 19) # Select standard font data

# lang ="DE" # set language parameter, default ("") -> english
lang ="EN"

i2c = busio.I2C(board.SCL, board.SDA)
bmp = Adafruit_BME280_I2C(i2c, address=0x76) # default i2c address (for Adafruit BMP280) 0x77 (default), 0x76 for chinese breakout)

#set reference pressure
# required for altitute calculation, please adjust. Standard value 1013.25 hPa
# manual input:
#reference_hPa =input ("Enter reference pressure in hPa: ") 
# or
# set pressure at starting time as reference, e.g. for  relative height measurements
time.sleep (1) # wait a second before 1st measurement
j= 0
pres_norm_sum = 0
while j in range (5): # take five measurements to define reference value
    pres_norm_sum = pres_norm_sum + bmp.pressure
    j= j+1
    time.sleep (1)
reference_hPa=(pres_norm_sum/j) # set inital measurement as reference point to enable height measurements
bmp.sea_level_pressure = float (reference_hPa)
print ()

while True:                 #runs forever, modify for crontab-version
    # measured values
    a=bmp.altitude   # calculated by adafruit library from pressure
    ts = # timestamp
    ts0_EN ='{:%Y-%m-%d}'.format(ts) # timestamp - date, EN format
    ts0_DE ='{:%d.%m.%Y}'.format(ts) # timestamp - date, German format
    ts1='{:%H:%M:%S}'.format(ts) # timestamp - time
    tmp = "{0:0.1f}".format(t)
    pre = "{0:0.1f}".format(p)
    hyg = "{0:0.1f}".format(h) 
    alt = "{0:0.1f}".format(a)
    tText = "Temp.: "
    pText_EN = "Pressure: "
    pText_DE = "Luftdruck: "
    hText_EN = "Humidity: "
    hText_DE = "rel. LF: "
    aText_EN = "Altitude: "
    aText_DE = "Höhe üNN: "  # exakt: ü. NHN, über Normal Höhen Null
    if (lang =="DE"):
        ts0 = ts0_DE
        aText = aText_DE
        pText = pText_DE
        hText = hText_DE
    else:                                    # default english
        ts0 = ts0_EN
        aText = aText_EN
        pText = pText_EN
        hText = hText_EN
    # print values to display 
    print (ts)
    print (tText, tmp, "°C")
    print (pText, pre, " hPa")
    print (hText, hyg, " %")
    print (aText, alt, " m")
    print ()
    # print values to Inky pHAT
    t1 = 5   # tab 1, frist column, simplifies optimization of layout
    t2 = 110 # tab 2, second column
    inkyphat.text((t1, 0), ts0, inkyphat.BLACK, font2) # write timestamp date
    inkyphat.text((t2, 0), ts1, inkyphat.BLACK, font2) # write timestamp time
    inkyphat.line ((t1,25, 207,25), 1,3)  # draw a line
    inkyphat.text((t1, 30), tText, inkyphat.BLACK, font2)
    inkyphat.text((t2, 30), (tmp + "°C"), inkyphat.BLACK, font2)
    inkyphat.text((t1, 55), pText, inkyphat.BLACK, font2)
    inkyphat.text((t2, 55), (pre + " hPa"), inkyphat.BLACK, font2)
    inkyphat.text((t1, 80), hText, inkyphat.BLACK, font2)
    inkyphat.text((t2, 80), (hyg + " %"), inkyphat.BLACK, font2)
#    alternatively display calculated height
#    inkyphat.text((t1, 80), aText, inkyphat.BLACK, font2)
#    inkyphat.text((t2, 80), (alt + " m"), inkyphat.BLACK, font2)
    time.sleep(51) # wait some seconds before next measurements, +19 sec per cycle
inkyphat.clear() # empty Inky pHAT display procedure,  # silence for crontab-version

Step 5: The BMP280 Script

The BMP280 is very similar to the BME280 sensor, but just measures temperature and pressure. The scripts are very similar, but you need different Circuit Python libraries. Here instead of the humidity a calculated height, based on a reference pressure, is displayed.

Attached you find the script.