A mixed SPS reef tank, dosed and lit by a self-built automation system rather than fixed daily programs. Chemistry (calcium, magnesium, alkalinity) is held on a peristaltic doser with schedules recalculated from actual tank measurements, and the tank's two lighting fixtures follow real solar elevation, live cloud cover and real moon phase for a reference Coral Triangle reef -- the same weather-tracking philosophy as the Heliamphora growroom, applied to a saltwater tank instead. This page documents the dosing and lighting automation and its live measured output; the photos further down are just the tank itself.
Chemistry & Dosing
Calcium and magnesium are held by a self-built multi-channel peristaltic doser on a 750L system, built on top of ReefRhythm-SmartDoser (MIT licensed, ESP32-S3 + MKS SERVO42C stepper-driven pump firmware) rather than written from scratch. Testing against this tank's own MKS SERVO42C stepper drivers surfaced several real bugs in the upstream dosing math and driver protocol -- most seriously, a low-flow calibration curve that could extrapolate the wrong direction and silently skip the runtime-shortening safety check meant for near-zero doses, and an RPM-snap case where the driver's achievable minimum speed was used without rescaling the dose runtime to match, both of which meant a small requested dose could silently run closer to a full-size one. Also fixed a UART CRC check that summed decoded values instead of the actual transmitted bytes (rejecting valid replies for any multi-byte field), and an OTA versioning bug where a build with an unset version tag could make a real firmware fix silently fail to take effect even after a "successful" update. Full writeup of all 11 fixes: Firmware Changes. Rather than a fixed daily total, each pump's per-dose amount is recalculated from an actual measured reading against target -- e.g. calcium's current schedule holds roughly 289mL/day of a CaCl2·2H2O solution (130.55g/L) split into 46 small doses rather than a few large ones, keeping the swing between doses small since large single dumps of calcium/alkalinity risk a local precipitation spike. Magnesium runs the same way, dosing a Tropic Marin Bio-Magnesium stock solution. Alkalinity is buffered separately with a NaOH solution (74g/L). Firmware updates over the air rather than needing physical access -- the build hosted here
(version v1.1.15-manual-20260920073258-manual-dose-indicator, sha256 1914ba1a...4215 in the
manifest below) is built from the source tree with all the fixes above already applied, verified
by matching that same sha256 against the local build output before publishing it -- not just
documented fixes sitting unused in a checkout somewhere:
micropython.bin,
bootloader.bin,
partition-table.bin,
manifest.
Current dosing (recalculated as measurements change, not fixed)
Element
Solution
Per dose
Doses/day
Total/day
Calcium
CaCl2·2H2O, 130.55g/L
6.29 mL
46
~289 mL
Magnesium
Tropic Marin Bio-Magnesium stock
3.08 mL
46
~142 mL
Ionic balance
Tropic Marin Part C, 47.4g/L
6 mL
40
~240 mL
Alkalinity
NaOH, 74g/L
1 mL
43
43 mL
Lighting
2x ATI Straton Flex 153 fixtures (150cm), driven by a Python script rather than the manufacturer app's own static timeline editor. Intensity follows a real solar-elevation curve computed for a reference Coral Triangle reef (Raja Ampat, Indonesia -- consistent ~12h day length, no daylight-saving shifts), then time-shifted so sunrise and sunset land at sensible local hours rather than Indonesia's own clock. On top of that:
Live cloud cover from that same reef's real weather forecast dims the tank on overcast days, floored so a fully overcast day doesn't black it out -- real diffuse light still reaches a reef underwater too.
A moon-phase-driven night cycle replaces a flat "lights off" floor, brighter near full moon and dimmer near new moon, with a printed notice during the commonly-cited post-full-moon window some SPS species use as a spawning cue.
Spectrum blends smoothly through the day -- no discrete preset jumps anywhere, including the moon-to-daylight transition -- built around the ~470nm coral fluorescence excitation peak reported in the coral photobiology literature (Bay et al. 2010), with extra UV/violet at twilight eased back at midday.
Hard-capped at 65% of the fixtures' maximum output, and the whole schedule recomputes every 15 minutes via cron rather than running a fixed program once a day.
● 10.10.3.60 last updated 2026-09-20T09:15:13+00:00 ● 10.10.3.84 last updated 2026-09-20T09:15:30+00:00
Today's Lighting Curve
The planned 0-65% intensity schedule for today, recomputed every 15 minutes from real solar elevation, the live cloud forecast, and moon phase -- this is what's actually queued up to run, not a measurement (see the PAR section below for that). Same curve drives both fixtures.
2026-09-20:
Measured Light Output (PAR)
Neither fixture has an actual photometric sensor. What's below instead comes from the fixture's own real measurement of LED driver current draw, run through ATI's own factory-calibrated current-to-PAR conversion at four fixed distances -- the exact same calculation the manufacturer's own app displays in its status bar, traced out of its source and pulled here directly. Treat it as a real, continuously-logged proxy for output good enough to catch genuine trends, not a lab-grade PUR reading: it's a per-single-lamp figure (ATI's own tooltip warns combined output from both fixtures together is "significantly higher"), and it's calibrated against ATI's factory spectrum rather than this tank's custom channel mix.
Latest reading per fixture
Fixture
Driver draw
Est. PAR @30cm
@45cm
@60cm
@75cm
10.10.3.60
68 W
204
143
102
85
10.10.3.84
64 W
192
134
96
80
Estimated PAR @60cm, both fixtures, last 48 hours: