$ cd ..

The Piquarium Project

📅 2021-12-15

923 days ago


A while ago, my Dad bought a really large aquarium. He wanted to use it to display the Symphysodon fish.

Image of the aquarium
The aquarium measures almost 180cm x 50cm

It was a functional setup, where my Dad connected a few heaters and pumps to get the water up to the ideal temperature of 30C for the fishes. However, if he wanted to check up on it while he wasn’t home, he had to call someone at home to check what the LED displays read.

Image of the pumps

And with Delhi’s winters, if a heater malfunctions the fishes could become sick, or worse, die.

I had an old Raspberry Pi lying around which I only ever used to run PiHole, long ago. And thus, the Piquarium project was born.


Image of the DS18B20 probe, a couple of Dupont connectors and a 4.7KΩ resistor

A DS18B20 probe, a couple of Dupont connectors and a 4.7KΩ resistor

Wiring diagram for the DS18B20
Wiring diagram for the DS18B20

I wanted the entire setup to be as tiny as possible, but almost every single guide for using a DS18B20 involved the use of a breadboard. I probably could have made it work but instead I decided to make that my last resort.

It seemed like the Raspberry Pi 3B+ supports having an internal Pull-Up Resistor. This post by Robert Elder and the fantastic accompanying video confirmed my findings AND proved that couple of DS18B20 probes without an external resistor could work just fine.


Rather than using a soldering iron to connect the wires from the probe, I went the unnecessarily complicated route of using a Dupont connector.

And then simply connecting the Dupont connectors to their GPIO pins:

Simple GPIO connections to the Pi
Simple GPIO connections to the Pi

Finally, to enable the pull-up resistor on GPIO pin 04, I use this Python script:

import RPi.GPIO as GPIO


To make sure it persists through restarts, I added the script as a systemd unit.

Now to actually read the values from the temperature probes:

import  glob

base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')
device_file = '/w1_slave'

def  read_temp_raw(device_file):
    f = open(device_file, 'r')
    lines = f.readlines()
    return  lines

def  read_temp():
    result = []
    for  folder  in  device_folder:
        lines = read_temp_raw(folder + device_file)
        value = lines[1].split()[-1].split("=")[1]

        value = int(value)
    result.append((folder.split('/')[-1], value))

    return  result

All readings from the sensors will be stored in the /sys/bus/w1/devices directory with each sensor having a name similar to 28-19a09fbc2 with the w1_slave file holding the values we need.

I had two sensors connected, I planned to use one for the primary tank and one for the ambient temperature.

Delivering the Data

Now that I was able to read values from the sensors, I moved on to storing it and actually making it available for processing/consumption.

The day I was looking for a solution is also when PlanetScale (a serverless database platform) entered general availability. On a whim, I decided to use their free-tier to store my temperature readings every minute from the Raspberry Pi.

PlanetScale Dashboard
PlanetScale Dashboard

For making the data available, I created a simple Telegram bot which queries the PlanetScale MySQL database. It would’ve been cleaner to have a dynamically updating website but I’m not very proficient with generating charts on the fly on the front-end. I did look into using Observable as well, but it seems I cannot embed their charts when connected to an external database.

A Chart of the Last 1 Month
A Chart of the Last 1 Month

And the bot:

The final Telegram Bot
The final Telegram Bot