141 lines
7.7 KiB
Markdown
141 lines
7.7 KiB
Markdown
+++
|
|
title = "Raspberry Pi 0 W + sensors + OLED display = temperature monitoring and calendar"
|
|
date = 2022-10-05
|
|
updated = 2023-11-11
|
|
+++
|
|
|
|
<img id="hero-img" alt="OLED display showing temperature and upcoming appointments, connected to a Raspberry Pi" src="/assets/raspberry-pi-temperature-monitoring.jpg">
|
|
|
|
|
|
With this project, I monitor the temperature and humidity in my room.
|
|
Measurements are taken every 10 minutes and saved in an SQLite database.
|
|
Additionally, the display shows the upcoming appointments of the next five days: each of the 24 rows represents one hour and each pixel in a row represents 5 minutes.
|
|
In the middle, the time until the next appointment, the relative humidity and the current temperature are shown.
|
|
Below that, a graph shows the temperature of the last two days.
|
|
When activating another display mode (not active in the picture), this area of the display instead shows the next seven appointments.
|
|
|
|
### Hardware
|
|
<ul>
|
|
<li>computer: <a href="https://www.raspberrypi.com/products/raspberry-pi-zero-w/">Raspberry Pi 0 W</a></li>
|
|
<li>temperature and humidity sensor: AM2302 (wired DHT22)</li>
|
|
<li>OLED display: 1.5 inch SSD1351 (<a href="https://www.waveshare.com/wiki/1.5inch_RGB_OLED_Module">Waveshare</a>)</li>
|
|
<li>yellow push switch: TRU Components PBS-18B 701912</li>
|
|
</ul>
|
|
|
|
The components are connected to the Pi as indicated in the wiring diagram below (made using [Circuit Diagram](https://www.circuit-diagram.org/)).
|
|
|
|
<embed
|
|
class="white-svg"
|
|
type="image/svg+xml"
|
|
src="/assets/circuit.svg"
|
|
title="Wiring diagram">
|
|
|
|
Wiring of the SSD1351 to the Pi (<a href="https://pinout.xyz/pinout/spi">pinout</a>):
|
|
|
|
1. VCC ↦ 3.3V
|
|
1. GND ↦ GND
|
|
1. DIN ↦ SPI0 MOSI (GPIO 10)
|
|
1. CLK ↦ SPI0 SCLK (GPIO 11)
|
|
1. CS ↦ SPI0 CE0 (GPIO 8)
|
|
1. DC ↦ GPIO 25
|
|
1. RST ↦ GPIO 27
|
|
|
|
Wiring of the AM2302 to the RPi:
|
|
|
|
1. VCC ↦ 5V
|
|
1. second pin ↦ GPIO 26
|
|
1. third pin ↦ (unused)
|
|
1. GND ↦ GND
|
|
|
|
Wiring of the push switch to the Pi: one pin to GPIO 19, the other to 3.3V.
|
|
|
|
|
|
### Software
|
|
|
|
|
|
The Raspberry Pi 0 W is running <a href="https://www.raspberrypi.com/software/">Raspberry Pi OS</a> 11 (bullseye).
|
|
It is advisable to enable SSH and configure a WLAN network before booting the RPi for the first time.
|
|
As explained in many tutorials online, this boils down to modifying the SD card image.
|
|
Create an empty file <span class="code">/boot/ssh</span> to enable the SSH daemon, and configure the credentials of your WLAN network in <span class="code">/etc/wpa_supplicant/wpa_supplicant.conf</span>.
|
|
<a href="https://valh.io/p/raspberry-pi-configure-wlan/wifi--ssh-before-first-boot/">This blog post</a> describes how to set up the initial user and password.
|
|
Make sure to set <span class="code">dtparam=spi=on</span> in your <span class="code">/boot/config.txt</span>, otherwise the SPI connection to the OLED display will not work.
|
|
|
|
|
|
|
|
All of the following software is written in <a href="https://www.rust-lang.org/">Rust</a> and available <a href="https://github.com/FliegendeWurst/raspi-oled/">on GitHub</a>.
|
|
<a class="fancy-name" href="https://github.com/FliegendeWurst/raspi-oled/blob/master/src/bin/take_measurement.rs">take_measurements</a> requests the current temperature and humidity from the sensor.
|
|
To mitigate transmission errors, the median of five readings is used.
|
|
The final reading is saved in the specified SQLite database (mine is named sensors.db) along with the current time.
|
|
<a class="fancy-name" href="https://github.com/FliegendeWurst/raspi-oled/blob/master/src/bin/refresh_json.rs">refresh_json</a> downloads the latest calendar entries from my <a href="https://github.com/zadam/trilium/"> Trilium Notes</a> installation and saves them in a JSON file (events.json).
|
|
<a class="fancy-name" href="https://github.com/FliegendeWurst/raspi-oled/blob/master/src/bin/status_check_example.rs">status_check</a> gathers some miscellaneus status information on my other computer systems. The provided example just checks whether GitHub and GitLab are up.
|
|
<a class="fancy-name" href="https://github.com/FliegendeWurst/raspi-oled/blob/master/src/bin/display_all.rs">display_all</a> processes all of this data and displays it on the OLED.
|
|
It is run by another Python script (<a href="https://gist.github.com/FliegendeWurst/087916a7635c2690de609366517a4ae7">turn_on.py</a>) whenever the push switch is pressed.
|
|
|
|
|
|
Below is the crontab of the pi user. status_check is run every five minutes. take_measurement is run every ten minutes. Fifteen minutes into the hour, any new calendar entries are synced using refresh_json. To avoid OLED burn-in, the display is turned off every minute (if it was on previously).
|
|
|
|
```
|
|
*/5 * * * * /home/pi/status_check /home/pi/sensors.db 2>/dev/null >/dev/null
|
|
*/10 * * * * /home/pi/take_measurement /home/pi/sensors.db
|
|
15 * * * * /home/pi/refresh_json --no-weekly
|
|
* * * * * /home/pi/display_off off
|
|
```
|
|
|
|
|
|
For performance reasons (and because the Pi doesn't have enough RAM), I cross-compile these programs using <a href="https://nixos.org/">Nix</a>.
|
|
I'm certain there's a better way to do it, but the following method works for my purposes:
|
|
in my <a href="https://github.com/FliegendeWurst/nur-packages/">NUR packages</a>, run the following command to cross-compile all binaries: <span class="code">NIXPKGS_ALLOW_BROKEN=1 nix-build -A raspi-oled-cross</span>.
|
|
(Btw, this will first compile LLVM and rustc for some reason. There must be a way to avoid that...)
|
|
As always, <span class="code">./result</span> is a symlink to the build artifacts.
|
|
The binaries (and the libraries they depend on) may be copied to the Pi like this:
|
|
|
|
```
|
|
mkdir /tmp/nixstore
|
|
nix copy --extra-experimental-features nix-command flakes --no-check-sigs --to /tmp/nixstore $(readlink -f result)
|
|
rsync -r --links --info=progress /tmp/nixstore/nix pi@himbeere-null:~/
|
|
```
|
|
|
|
On the RPi itself, the binary needs to be adapted to Raspbian and placed in the proper position:
|
|
|
|
```
|
|
patchelf --set-interpreter /lib/ld-musl-armhf.so.1 nix/store/*-raspi-oled-*/bin/display_all
|
|
sudo mv nix /
|
|
```
|
|
|
|
### Enclosure
|
|
|
|
<img class="content-img-tall" alt="3D model of the case" src="/assets/raspberry-pi-case.png">
|
|
|
|
To make the whole setup look a bit nicer, I designed a casing using [OpenSCAD](https://openscad.org/).
|
|
The image on the right shows the final result as rendered by OpenSCAD ([.scad](/assets/RPi-Zero.scad)).
|
|
|
|
[Raspberry Pi 0 W - Slim Case](https://www.thingiverse.com/thing:4199739) (by OhSnap) proved to be a great base to build on.
|
|
I added some supports around it to ensure it won't topple over as easily.
|
|
Since I was too lazy to measure the dimensions of my OLED display, I extracted the relevant part of [Zoid, the Trapezoidal Under Cabinet 1.5" OLED Display](https://www.thingiverse.com/thing:3397089) (by rhattie).
|
|
Feeling a little bit fancy, I decided to add some inset icons underneath.
|
|
The pin holes will be useful to add some status LEDs later.
|
|
Because one button will soon not be enough control, I added three button holders on the top.
|
|
A library near me offers a 3D printing service so it was easy to get the case printed.
|
|
|
|
The new buttons and LEDs will need to be wired up to some unused GPIO pins.
|
|
All LEDs are connected using a single resistor since these will only turn on rarely and even more rarely at the same time.
|
|
|
|
<embed
|
|
class="white-svg"
|
|
type="image/svg+xml"
|
|
src="/assets/circuit_new.svg"
|
|
title="Wiring diagram">
|
|
|
|
To make full use of the three buttons, I came up with a simple one/two-step selection menu to get to the most important functionality.
|
|
|
|
1. Show time table and large clock
|
|
1. (unused)
|
|
2. Show temperature chart
|
|
3. Show upcoming events
|
|
2. Dismiss active action
|
|
3. Show TOTP codes
|
|
1. Next page
|
|
2. (unused)
|
|
3. Show RPi screensaver
|
|
|
|
This post will be updated soon™ to show to the final 3D print (which required some adjustments not yet mentioned). |