The open-source multispectral colorimeter for aquarium water testing
One device. Every parameter. Lab-grade precision.
Aquarium water testing is stuck in the 1990s. You buy a $60 Hanna Checker for each parameter — Nitrate, Phosphate, Calcium, Alkalinity — and end up spending $300–500 on single-wavelength photometers that can't talk to each other.
OpenChecker replaces them all with one device.
| Hanna Checker | OpenChecker | |
|---|---|---|
| Sensor | 1 LED + 1 photodiode | 18-channel spectral sensor (380–1000nm) |
| Parameters | 1 per device ($60 each) | All parameters, one device |
| Dark subtraction | ❌ | ✅ Per-channel dark frame |
| Dynamic range | Fixed | Adjustable gain (0.5×–2048×) |
| Connectivity | None | WiFi + embedded SPA + cloud |
| Calibration | Factory only | User-calibratable + community profiles |
| Data | Lost forever | Stored locally + synced to cloud |
| Price | $60–90 × N parameters | < $50 total BOM |
OpenChecker uses the AS7343 18-channel spectral sensor (ams-OSRAM) and the Beer-Lambert Law to measure the concentration of any substance that produces a color change with a reagent.
┌─────────────┐
│ White LED │ (high CRI >95, constant current driver)
│ Source │
└──────┬──────┘
│ light
┌──────▼──────┐
│ Cuvette │ (Hanna-compatible, 16mm Ø)
│ + Sample │
│ + Reagent │
└──────┬──────┘
│ transmitted light
┌──────▼──────┐
│ AS7343 │ 18 spectral channels
│ Sensor │ 3-pass SMUX
└──────┬──────┘
│ I²C
┌──────▼──────┐
│ ESP32 WROOM │ Firmware + SPA + WiFi
└─────────────┘
Measurement flow:
- Insert blank cuvette (distilled water) → dark + blank reading
- Add reagent to sample, wait for color development
- Insert sample cuvette → spectral reading
- Beer-Lambert calculation → concentration result
- Result displayed on TFT + SPA, stored locally, synced to cloud
We are building in public. The hardware is being designed, the firmware architecture is defined, and seam tests are written. Join us at the ground floor.
Status Legend:
- ✅ HW Validated: Fully tested on physical hardware.
- 🟡 Stub / Partial: Software tests (stubs) passing or partially validated (needs full hardware test).
- 🔴 Unvalidated: Not yet tested or currently failing on hardware.
| Seam | Component | Tests | Status |
|---|---|---|---|
| SEAM-00 | Bus & GPIO validation | 12 | 🟡 Stub |
| SEAM-01 | AS7343 Spectral Sensor | 11 | 🔴 Unvalidated (sensor responde no I²C; driver stub) |
| SEAM-02 | TFT Display | 6 | 🟡 Stub |
| SEAM-03 | Rotary Encoder | 7 | ✅ HW Validated |
| SEAM-04 | Buzzer | 6 | ✅ HW Validated |
| SEAM-05 | LED Source | 4 | 🟡 Stub |
| SEAM-06 | DS18B20 Temperature | 4 | ✅ HW Validated |
| SEAM-07 | DS3231 RTC | 5 | ✅ HW Validated |
| SEAM-08 | WiFi | 3 | ✅ HW Validated |
| SEAM-09 | LittleFS Storage | 8 | ✅ HW Validated |
| Phase | Description | Status |
|---|---|---|
| Phase 0 | Hardware bringup — validate every component with seam tests | 🔨 In progress |
| Phase 1 | Firmware MVP — state machine, calibration, API, embedded SPA | 📋 Planned |
| Phase 2 | Cloud — Supabase sync, multi-device, shared profiles | 📋 Planned |
| Phase 3 | Community profiles — marketplace, validated calibrations, global dataset | 📋 Planned |
| Phase 4 | Community platform — see Vision below | 🔮 Future |
| Phase 5 | Companion mobile app — see Vision below | 🔮 Future |
OpenChecker is not just a device — it's an ecosystem for aquarium science.
A web platform where aquarists connect, share, and learn:
- 🧪 Shared test results — publish your water parameters with photos of your tank
- 📊 Calibration profiles — community-validated calibrations for every reagent brand
- 🐠 Aquarium gallery — showcase your tank with its water quality history
- 🏪 Store locator — find local shops that stock reagents and OpenChecker kits
- 🎓 Consultant network — connect with experienced reefers for advice
- 📈 Global dataset — anonymized water quality data powering ML models for the hobby
- 🏆 Leaderboard — most consistent water quality, most tests shared, top contributors
A native mobile app that pairs with your OpenChecker:
- 📱 BLE + WiFi connection to device
- 📸 Photo-linked results — snap a photo of your tank with each test
- 🔔 Test reminders — "Time to test Alkalinity!"
- 📊 Trend charts — track parameters over weeks/months
- 🤝 Social sharing — share results with your reef club or consultant
- 🔄 Cloud sync — same data on device, SPA, app, and platform
- MCU: ESP32 WROOM (4MB Flash) — same board as Solarium
- Framework: Arduino via PlatformIO
- Sensor: AS7343 (18-channel spectral, I²C @ 0x39)
- Storage: LittleFS (JSONL + atomic writes)
- API: ESPAsyncWebServer (REST + WebSocket)
- Testing: Unity framework, TDD Strangler Fig methodology
- Framework: Preact 10.x + TypeScript
- Bundler: Vite (gzipped for ESP32)
- Styling: TailwindCSS 3.x
- Design System: Based on Solarium LED controller
- Backend: Supabase (PostgreSQL + Auth + RLS)
- Sync: Offline-first with queue and conflict resolution
| Component | Model | Est. Cost |
|---|---|---|
| MCU | ESP32 WROOM DevKit (4MB) | $5 |
| Spectral Sensor | AS7343 breakout | $12 |
| Display | TFT IPS 1.8" 160×128 (ST7735) | $4 |
| RTC | DS3231 module + CR2032 | $3 |
| Temperature | DS18B20 waterproof | $2 |
| Encoder | Rotary encoder with button (KY-040) | $2 |
| LED | White LED CRI>95 + constant current driver | $5 |
| Buzzer | Passive piezo 3.3V | $1 |
| PCB + 3D case | Custom | ~$5 |
| Total | ~$39 |
Connect components to the ESP32 WROOM as shown below. This matches firmware/src/config/pins.h and firmware/platformio.ini.
ESP32 WROOM DevKit
┌──────────────────┐
│ │
│ GPIO 21 ── SDA ─┤──── I²C Bus (AS7343 + DS3231)
│ GPIO 22 ── SCL ─┤──── I²C Bus (AS7343 + DS3231)
│ │
│ GPIO 23 ── MOSI┤──── TFT Display (VSPI)
│ GPIO 18 ── SCLK┤──── TFT Display (VSPI)
│ GPIO 13 ── CS ┤──── TFT Display (safe — was GPIO 5)
│ GPIO 14 ── DC ┤──── TFT Display (safe — was GPIO 2)
│ GPIO 4 ── RST ┤──── TFT Display
│ GPIO 19 ── BL ┤──── TFT Backlight PWM (safe — was GPIO 15)
│ │
│ GPIO 32 ── CLK ┤──── Rotary Encoder (A)
│ GPIO 33 ── DT ┤──── Rotary Encoder (B)
│ GPIO 25 ── SW ┤──── Rotary Encoder (Button)
│ │
│ GPIO 26 ── PWM ┤──── Buzzer (passive piezo)
│ GPIO 27 ── PWM ┤──── LED Source (via MOSFET/Driver)
│ GPIO 16 ── DQ ┤──── DS18B20 (1-Wire, 4.7kΩ pull-up)
│ GPIO 17 ── INT ┤──── AS7343 Interrupt (active low)
│ │
│ 3.3V ──────────┤──── Sensor/RTC VCC
│ GND ───────────┤──── Common Ground
│ 5V (USB) ──────┤──── TFT VCC / LED Driver
└──────────────────┘
| ESP32 GPIO | Function | Component | Notes |
|---|---|---|---|
| I²C Bus | |||
| GPIO 21 | SDA | AS7343 + DS3231 | Shared bus, 4.7kΩ pull-ups to 3.3V |
| GPIO 22 | SCL | AS7343 + DS3231 | Shared bus, 4.7kΩ pull-ups to 3.3V |
| SPI (VSPI) | |||
| GPIO 23 | MOSI | TFT ST7735 | Data to display |
| GPIO 18 | SCLK | TFT ST7735 | Clock |
| GPIO 13 | CS | TFT ST7735 | Chip select — safe GPIO (was GPIO 5 strapping) |
| GPIO 14 | DC | TFT ST7735 | Data/Command — safe GPIO (was GPIO 2 strapping) |
| GPIO 4 | RST | TFT ST7735 | Reset (active low) |
| GPIO 19 | BL | TFT ST7735 | Backlight PWM — safe GPIO (was GPIO 15 strapping) |
| Encoder | |||
| GPIO 32 | CLK (A) | KY-040 | Internal pull-up enabled |
| GPIO 33 | DT (B) | KY-040 | Internal pull-up enabled |
| GPIO 25 | SW | KY-040 | Button, internal pull-up |
| Peripherals | |||
| GPIO 26 | PWM | Buzzer | Passive piezo (LEDC CH0) |
| GPIO 27 | PWM | LED Source | Via MOSFET/driver (LEDC CH2) |
| GPIO 16 | DQ | DS18B20 | 1-Wire, 4.7kΩ pull-up to 3.3V |
| GPIO 17 | INT | AS7343 | Active low, 10kΩ pull-up to 3.3V |
⚠️ Strapping Pin Safety (ESP32 WROOM):
- GPIO 0, 2, 5, 12, 15 are strapping pins — the chip reads them at power-on to decide boot mode. Never connect peripherals that may pull these to unexpected levels during boot.
- GPIO 2 must be LOW at boot — an external pull-up (e.g., TFT DC line) will prevent flash boot.
- GPIO 5 controls flash timing — an active-low CS during boot is a lottery.
- GPIO 15 must be HIGH at boot — a transistor pulling BL LOW will brick startup.
- GPIO 34–39 are input-only — do not use for outputs.
- GPIO 6–11 are connected to internal flash — never use.
- GPIO 1, 3 are UART0 (serial debug) — avoid if possible.
🔌 I²C Level Shifter:
- SDA/SCL exit the ESP32 at 3.3V and connect to the DS3231 directly (3.3V tolerant).
- Before reaching the AS7343, they must pass through a bidirectional level shifter to step down to 1.8V. The AS7343 will be damaged by 3.3V I²C signals.
======================= DOMÍNIO 3.3V ======================= || ====== DOMÍNIO 1.8V ======
┌─────────────┐ ┌──────────┐ ┌───────────────┐ ┌─────────────┐
│ ESP32 WROOM │ │ DS3231 │ │ LEVEL SHIFTER │ │ AS7343 │
│ │ │ (RTC) │ │ (Bidirecional)│ │ (Sensor) │
│ GPIO 21 SDA ├───┬───┤ SDA ├───┬──┤ HV1 LV1 ├────────┤ SDA │
│ GPIO 22 SCL ├───┼───┤ SCL ├───┼──┤ HV2 LV2 ├────────┤ SCL │
│ GPIO 17 INT ├───┼───┼──────────────┼──┤ HV3 LV3 ├────────┤ INT │
│ │ │ │ │ │ │ │ │ │
│ 3.3V ├───┼───┤ VCC (3.3V) └──┤ HV_VCC │ ┌────┤ VDD (1.8V) │
│ GND ├───┼───┤ GND │ LV_VCC ├───┤ │ │
└──────┬──────┘ │ └─────┬────┘ │ GND GND │ │ │ GND │
│ │ │ └───┬────────┬──┘ │ └───┬─────────┘
│ │ │ │ │ │ │
│ │ └───────────────┘ │ │ │
=======│==========│==================================│======│========│==========
│ │ │ │ │
│ ┌──────┴────────┐ │ │ │
└───┤ VIN VOUT ├─────────────────────────┼──────┘ │
│ Regulador LDO │ │ │
│ (Gera 1.8V) │ │ │
│ GND ├─────────────────────────┴───────────────┘
└───────────────┘
We welcome contributions at every level:
| You are... | You can... |
|---|---|
| Aquarist | Test reagents, validate results, suggest parameters |
| Embedded dev | Write drivers, optimize sensor readings, port to new MCUs |
| Frontend dev | Build the SPA, design calibration UI, create data visualizations |
| PCB designer | Design the production PCB, optimize layout |
| 3D designer | Design the optical chamber, cuvette holder, enclosure |
| Data scientist | Build ML models for auto-calibration, spectral analysis |
| Technical writer | Improve documentation, write assembly guides |
- Read the PRD v2.4 — the complete product spec
- Read the Phase 0 FSD — current implementation plan
- Check Issues for
good first issuelabels - Read CONTRIBUTING.md for development workflow
- 🏆 Your name on a scientific instrument used by aquarists worldwide
- 📚 Learn: ESP32, spectral analysis, Beer-Lambert, IoT, Preact, Supabase
- 🌊 Impact: Help thousands of aquarists keep healthier tanks
- 💼 Portfolio: Real hardware + firmware + full-stack — impressive on any resume
| Document | Description |
|---|---|
| PRD v2.4 | Complete Product Requirements Document |
| FSD Phase 0 | Hardware Bringup — TDD Strangler Fig with 65 seam tests |
OpenChecker uses a triple-license structure to keep everything open:
| Component | License | File |
|---|---|---|
| Firmware & Software | GPL-3.0 | LICENSE |
| Hardware designs | CERN-OHL-S-2.0 | LICENSE-HARDWARE |
| Documentation | CC BY-SA 4.0 | LICENSE-DOCS |
"OpenChecker" is a trademark. You may fork, modify, and sell kits — but you must publish your source code and cannot use the OpenChecker name without permission.
- ams-OSRAM — AS7343 spectral sensor
- Hanna Instruments — Inspiration and reference for cuvette compatibility
- IO Rodeo Open Colorimeter — Pioneer in open-source colorimetry
- Solarium / ReefLightNeoV2 — Architectural patterns and design system
Built with 🧪 for the reef keeping community
If this project helps your tank thrive, give it a ⭐