115 lines
6.3 KiB
HTML
115 lines
6.3 KiB
HTML
<!DOCTYPE html>
|
|
<head>
|
|
<title>Raspberry Pi temperature monitoring + calendar</title>
|
|
<meta charset="utf8">
|
|
<link rel="shortcut icon" href="favicon.ico">
|
|
<link rel="stylesheet" href="main.css">
|
|
</head>
|
|
|
|
<body>
|
|
<h1 id="header"><img src="favicon.ico" id="favicon"/><a href="/">FliegendeWurst's corner of the WWW</a></h1>
|
|
|
|
<h2>Raspberry Pi 0 W + sensors + OLED display = temperature monitoring and calendar</h2>
|
|
|
|
<article>
|
|
|
|
<img id="hero-img" alt="OLED display showing temperature and upcoming appointments, connected to a Raspberry Pi" src="./raspberry-pi-temperature-monitoring.jpg"/>
|
|
|
|
<p>
|
|
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.
|
|
</p>
|
|
<h3>Hardware</h3>
|
|
<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.
|
|
|
|
<embed
|
|
type="image/svg+xml"
|
|
src="circuit.svg"
|
|
title="Wiring diagram" />
|
|
|
|
<p>
|
|
Wiring of the SSD1351 to the Pi (<a href="https://pinout.xyz/pinout/spi">pinout</a>):
|
|
<ol>
|
|
<li>VCC ↦ 3.3V</li>
|
|
<li>GND ↦ GND</li>
|
|
<li>DIN ↦ SPI0 MOSI (GPIO 10)</li>
|
|
<li>CLK ↦ SPI0 SCLK (GPIO 11)</li>
|
|
<li>CS ↦ SPI0 CE0 (GPIO 8)</li>
|
|
<li>DC ↦ GPIO 25</li>
|
|
<li>RST ↦ GPIO 27</li>
|
|
</ol>
|
|
Wiring of the AM2302 to the RPi:
|
|
<ol>
|
|
<li>VCC ↦ 5V</li>
|
|
<li>second pin ↦ GPIO 26</li>
|
|
<li>third pin ↦ (unused)</li>
|
|
<li>GND ↦ GND</li>
|
|
</ol>
|
|
Wiring of the push switch to the Pi: one pin to GPIO 19, the other to 3.3V.
|
|
</p>
|
|
|
|
<h3>Software</h3>
|
|
|
|
<p>
|
|
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.
|
|
</p>
|
|
|
|
<p>
|
|
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.
|
|
</p>
|
|
|
|
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).
|
|
<pre>
|
|
*/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
|
|
</pre>
|
|
|
|
<p>
|
|
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:
|
|
<pre>
|
|
mkdir /tmp/nixstore
|
|
nix copy --extra-experimental-features nix-command --extra-experimental-features flakes --no-check-sigs --to /tmp/nixstore $(readlink -f result)
|
|
rsync -r --links --info=progress /tmp/nixstore/nix pi@himbeere-null:~/
|
|
</pre>
|
|
On the RPi itself, the binary needs to be adapted to Raspbian and placed in the proper position:
|
|
<pre>
|
|
patchelf --set-interpreter /lib/ld-linux-armhf.so.3 nix/store/*-raspi-oled-*/bin/display_all
|
|
sudo mv nix /
|
|
</pre>
|
|
|
|
</p>
|
|
|
|
<div class="entry-footer">Posted 5th October 2022</div>
|
|
|
|
</article>
|