The software

Pearl

Pearl is the software behind this aquarium. It reads the Apex controller, the probes and the doser, keeps the record the rest of this site is drawn from, and can switch things on and off through the Apex when there is a reason to.

Overview

Pearl runs on a Raspberry Pi next to the tank. It polls the Apex every few minutes, reads the Red Sea doser over its own local API, writes both to a database, and serves two things off that database: a private set of tools for running the aquarium, and the public pages here.

It exists because the earlier scapes left nothing behind. Maintenance decisions survived as impressions and a few photographs, and there was no way to tell from those whether anything was improving. Logging came first. Control came later, and only in places where logging had already shown it was worth doing.

Recorded Data

These are counted from the database when the page loads. If the logger stalls, the date below goes stale and you can see that it has.

14,823tank readingsover 56 days
265readings per dayroughly one every five minutes
56PAR readingsmeasured by hand
Continuously logged
Temperature, pH, conductivity, outlet states and alarm state
Recorded by hand
Water tests (36 logged) and PAR readings at each plant position
First reading
June 14, 2026
Most recent reading
August 9, 2026

Maintenance logged

  • /Filter service: 96
  • /Water change: 26
  • /Fertiliser dose: 17
  • /Note: 4
  • /pH probe calibration: 2
  • /pH probe replacement: 1

Control Architecture

Pearl can turn things on and off, but not directly. It writes what it wants to a flag, the Pi picks that up on its next poll and sets a virtual outlet on the Apex, and the Apex decides what that means for the physical relay. The water-change routine works this way, and so did CO₂ when the loop was closed. Vercel cannot reach a controller sitting on a home network, so the Pi is the bridge in both directions.

The practical effect is that the Apex is still the thing in charge. A pH floor, the permitted CO₂ window and the leak sensor are configured on the controller, so they hold whether or not Pearl is running, and a bad deploy cannot widen them. Pearl asks. The Apex is what actually decides.

Beyond that it schedules the CO₂ window, tracks how long it has been since the last water change and filter service, flags readings that sit outside their usual band, and drives a wall display so the tank can be read at a glance.

The Pearl wall display showing pH, CO₂ state, conductivity, temperature, power draw and doser levels
The wall display from the period when Pearl was holding CO₂ against a target pH drop off the morning baseline. It worked. The closed loop was tested and worked operationally, but the current system uses a fixed schedule because the pH signal is not treated as a direct CO₂ measurement in this water. It was not abandoned unfinished.

Doser Telemetry

The Red Sea ReefDose is a separate device with its own API, so Pearl reads it directly rather than through the Apex. Both heads are picked up individually: what each one doses, the schedule it runs, the millilitres it has put in today against what it was supposed to, how much is left in the container, when the head was last calibrated, and whether the device thinks it needs recalibrating.

Head 1
GLA macros, 6.3 ml/day, three doses between 10:30 and 15:30
Head 2
GLA micros, 2.5 ml/day, one dose at 08:30
Currently
Configured and calibrated, containers empty, auto-dosing off

The schedule above is what the doser is set up to run, not what it is currently running. The containers are empty and auto-dosing is off, so fertiliser is still going in by hand. That is the weakest part of the setup. Hand dosing varies, and while it varies there is no clean way to say whether a change in the tank came from light or from nutrition. Filling the containers and switching it on is the fix, and everything needed to measure whether it worked is already reporting.

Operational Limits

  • /It does not hold the safety limits. The pH floor, the CO₂ window and the leak sensor are configured on the Apex, so they survive Pearl being offline or wrong.
  • /It does not touch physical outlets. Everything it switches goes through an Apex virtual outlet, and the controller applies its own rules on top.
  • /It is not currently holding the pH loop closed. It can, and it did. A fixed window is steadier on water with no carbonate buffer.
  • /It does not drive the doser. It reads it. The ReefDose runs its own schedule, when there is anything in the containers to run.
  • /It does not publish anything that would signal whether anyone is home. Outlet detail and host addresses stay on the private side.

System Architecture

Runs on
A Raspberry Pi beside the aquarium, on the local network
Reads
A Neptune Apex controller and its probes, and a Red Sea ReefDose over its own API
Application
Next.js on Vercel, with a Postgres record behind it
Displays
A private dashboard, a wall display, and this public site
Switches
Apex virtual outlets, relayed by the Pi, applied by the controller
TankNeptune ApexProbes & outletsPi running PearlRecordThis public site
The chain, left to right, with the return path underneath. The Apex owns the outlets and the limits, Pearl reads and records, and part of that record is what you are reading now. Device addresses and control endpoints are not published.

Every system by the job it does · What the record says right now

Related