Motivation

It is winter. The air is dry. Beyond slathering my face in Burt's Bees, we have mostly suffered in this dryness. I am anti-humidifier. They seem like diva equipment. And who wants to clean them weekly? Ugh. But no more! It is time. Also, my last Pi project broke important barriers in my brain - mostly emotional - and now it seems much easier to try new Pi things. Also also, I had another Pi lying around.

Hardware setup

For this project, I used:

Note: I was unable to use the Raspberry Pi 3b case that comes with this CanaKit kit - the Enviro pHat doesn't fit under the case's middle layer. Word to the wise!

Software setup

This was a bit of a journey.

First, I downloaded the latest version of the Raspberry Pi operating system - specifically, the Raspberry Pi OS with desktop. I flashed it onto the micro-SD card using balenaEtcher. After inserting that SD card into the Pi, as well as attaching all the peripherals (monitor, keyboard, mouse, power), I powered it on and then shaved the yak that is installing everything. At the end of this part of the journey, you have a perfectly serviceable little Linux desktop that I believe all children around 5 years old should have. Free Pis for all kids!

Second, well... I spent a lot of time being ridiculous and tinkering with the shell and dotfiles of the Pi. I just want a comfortable programming environment, dammit! This meant first copying over my .vimrc... and then just going whole hog and copying over all my .dotfiles, installing zsh (z-shell), installing ohmyzsh.sh, and generally futzing. The main learning here was that installing things on OSX means using brew a lot (e.g. brew install whatever), while the Raspberry Pi OS - given it's a type of Debian system, like Ubuntu (the most popular (?) Linux OS) - used a lot of sudo apt get install. Other than that, this part was basically smooth sailing and not much to report.

Third was getting acquainted with the actual software for the Enviro. I relied heavily on this tutorial from the creators, Getting Started with Enviro+, not to be confused with this very similarly titled tutorial for their older model. HEHHHH. Yeah, I definitely got confused. And that's the main thing I learned in this Pi project - that these projects are small and often changing and so it takes a bit of detective work to figure out how all the pieces go together. Which was fun! Very gratifying!

Anyway, the pieces I ended up needing were the enviroplus-python library (Pimoroni has, again, a very similar one, enviro-phat, which I won't link because then you will get confused. I'm pretty sure enviroplus-python is the one we should be using, at least at this point in time.)

More hardware

So this library was super interesting. It basically installed a bunch of other Pimoroni Python packages which related to the sensors on the pHat (pHAT? HAT? read more here...). These sensors are, specifically:

  • A BME280 sensor which records temperature, humidity, and pressure. I believe the official docs are here.
  • An LTR-559 light and (optical) proximity sensor. I believe the official docs for that are these.

There's also a tiny microphone and LED screen, though I haven't explored those almost at all yet. More to come on those!

And more software

The main questions I had, after running through the enviroplus-python off-the-shelf examples, was what were the units on these sensors? The proximity sensoring, especially, was kinda baffling. The numbers get very "big" (in the thousands) if you put your hand over the sensor, and quite low (down to zero) if you don't. So, thousands of... what?

It turned out finding the answer to this question was not straightforward, and the official answer was basically an "uhhhh 🤷". This GitHub issue includes the Pimoroni thoughts on the matter and the official docs basically say it's "count". Though count of what?!

A brief digression on how the optical sensor works

I dove into this a little bit. The LTR-559 is an optical sensor. (There are other types of proximity sensors that use other parts of the electromagnetic spectrum to "see" if there's an object in front of them.) An optical sensor works by using light - it measures the reflected light, as far as I can tell. So the numbers the sensor is returning are a "count" (according to the official docs), which the Pimoroni authors think is either the number of LED pulses the sensor emitted that returned an object (e.g. "I shot out 500 pulses and 499 of them reflected light back, so your number is 499"?) or the actual "number of light units", typically measured as a lux (wiki - a measure of "luminous flux per unit area").

Either way, big numbers from that sensor = lots of reflected light = something is close.

This YouTube video by Modern Robotics Inc gives a very nice and thorough (and digestible) explanation.

Final Software: the actual little script

To start with, I just wanted to start collecting the data for some of our rooms. For now, I'm just writing that data to a CSV file that the Pi is holding, and every so often I ssh into the Pi and check on it. I've been noodling over the idea of (1) making the data more stream-y (Kafka?) and/or (2) making a web UI (like the Pi-hole!) using Flask and Bokeh (Bokeh so pretty...).

#!/usr/bin/env python3

import time
import csv
from datetime import datetime

from ltr559 import LTR559
from bme280 import BME280

ltr = LTR559()  
bme = BME280()

header = ['datetime', 'light', 'proximity', 'temperature', 'humidity']
data_file = 'data/room.csv'

try:

    # Write the header once
    with open(data_file, 'w') as f:
        writer = csv.writer(f)
        writer.writerow(header)

    while True:
        f = open(data_file, 'a')

        writer = csv.writer(f)

        today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

        ltr.update_sensor()
        lux = ltr.get_lux()
        prox = ltr.get_proximity()
        temp = bme.get_temperature()
        pres = bme.get_pressure()
        hum = bme.get_humidity()

        writer.writerow([today, f"{lux:.2f}", f"{prox:.2f}", f"{temp:.2f}", f"{hum:.2f}"])

        time.sleep(60)
        f.close()

except KeyboardInterrupt:
    pass

The units for the other sensor readings (apart from proximity) are:

Interpreting the results

My brain is in Fahrenheit, but I have a general sense of Celsius (20 is comfortable! 0 is freezing! 40 is hotttt). I have no similar sense for luxes, hectopascals, and even relative humidity. The relative humidity in the rooms we measured has always been around ~17%. Which seems awfully low. But what does that mean? Apparently the Sahara Desert is typically around 25%. What the heck.

Oh yeah, and I need to compensate for the heat of the Raspberry Pi, as this Pimoroni example shows.


Conclusion

Well, this was a lot of fun, despite what my initial Pi pessimism ("is it all just off the shelf?!"). I do feel like my creativity has been unlocked and I'm learning lots of little things as well (hectopascals!); those were the two things I was after (learning, creativity). I'm very pumped to keep tinkering with this and to BUY MORE PIIIIIIS.


This post is part 2 of the raspberry_pi series:

  1. Setting up the Pi-hole (finally!)
  2. Pi project #2: Indoor environment monitor