🇫🇷 Français · 🇬🇧 English
Autonomous backup battery monitoring and management system for Red Sea reef aquariums (ReefWave, ReefRun, DC Skimmer, DC Pump).
- Battery monitoring via INA226 (I2C, primary) + Victron BLE (optional auxiliary for charger state)
- Instant outage detection via 230V relay on GPIO
- Progressive pump degradation — SoC-based levels auto-computed from a target autonomy
- Per-device control — each ReefWave / ReefRun / Skimmer gets its own intensity per level
- 3-level network failover — normal Wi-Fi → rejoin → autonomous hotspot
- Push notifications — via ntfy.sh (free, no account required) + 4G LTE failover
- 4G internet gateway — when hotspot is active, routes ReefBeat traffic through 4G so the Red Sea mobile app keeps working
- Home Assistant integration — MQTT auto-discovery (10 sensors + charger if Victron)
- MQTT buffer with replay — data during HA outage is never lost
- Auto-detection — scans your network for ReefBeat devices during setup
- Self-update — checks GitHub for new versions, HA update entity with "Install" button
- Scheduled reboot — automatic RPi reboot via cron, skipped if on battery
- Bilingual — FR/EN interface based on system locale
- Quick install
- Hardware mounting levels
- Configuration
- Home Assistant
- Battery test blueprint
- Push notifications
- Project structure
- Troubleshooting
curl -sL https://raw.githubusercontent.com/Elwinmage/reefbeatEnergyBackup/main/install.sh | sudo bashThe installer:
- Downloads the latest release
- Enables I2C on the Pi if needed (
raspi-config nonint do_i2c 0) - Installs
python3-rpi-lgpio(Pi 5 / kernel 6.6+ compatible) and Python dependencies - Launches the interactive wizard which:
- Scans the network for ReefBeat devices
- Retrieves Wi-Fi SSID and MAC addresses from your devices
- Auto-detects your Raspberry Pi model
- Computes SoC levels from a target autonomy (12h, 24h…)
- Configures battery, INA226 monitoring + optional Victron, MQTT
- Installs and enables the systemd service
- Optionally starts the service immediately
The installer creates a systemd service called reefbeat-energy-backup:
# Status
sudo systemctl status reefbeat-energy-backup
# Start / stop / restart
sudo systemctl start reefbeat-energy-backup
sudo systemctl stop reefbeat-energy-backup
sudo systemctl restart reefbeat-energy-backup
# Live logs
sudo journalctl -u reefbeat-energy-backup -f
# Disable auto-start on boot
sudo systemctl disable reefbeat-energy-backupTo reconfigure at any time:
python3 ~/scripts/reefbeatEnergyBackup/configure.py
sudo systemctl restart reefbeat-energy-backupThe system is built in three levels, each adding functionality. You can start at level 1 and upgrade progressively.
Goal: provide battery backup for pumps during power outages, without monitoring or automation.
| Component | Suggested model | Approx. price |
|---|---|---|
LiFePO₄ battery 24V 60Ah (24V/5A charger included) |
Kepworth 24V 60Ah | ~260 € |
Jack adapter for ReefWave |
5.5 × 2.1 mm barrel jack to bare wires | ~5 € |
IP68 4-pin connector for ReefRun/Skimmer |
IP68 4-pole connector | ~5 € |
| Wiring (2.5 mm² red/black wire, crimps, heatshrink, 15A fuse) | — | ~20 € |
Level 1 budget: ~290 €
🔊 Noise note: the charger included with the Kepworth battery has an active cooling fan that is relatively noisy. If you plan to install it near a living area, place it further away (utility room, garage) or go directly to level 3 with the Victron Blue Smart charger, which is much quieter (passive cooling at low charge).
230 V
│
▼
┌─────────────┐
│ Charger │
│ 24V 5A inc. │ ← included with battery
└──────┬──────┘
│ 24V DC
▼
┌─────────────┐
│ Battery │
│ LiFePO₄ │ ← stores energy
│ 24V 60Ah │
└──────┬──────┘
│ 24V DC (with 15A fuse)
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌───────┐ ┌────────┐ ┌─────────┐
│ReefRun│ │ReefWave│ │DC Skim. │
│+pumps │ │ jack │ │connect. │
└───────┘ └────────┘ └─────────┘
The principle: the battery sits in series between the charger and the loads. It is constantly maintained at full charge by the charger (included with the Kepworth battery) in float mode, and automatically supplies power when mains drops — no switch, no electronics in between.
- ReefWave: uses the 5.5 × 2.1 mm barrel jack connector (positive center)
- ReefRun and DC Skimmer: use the IP68 4-pin waterproof connector (the pump includes its own regulator, raw 24V is fine)
- The included charger stays plugged in permanently: it automatically switches to float mode once full charge is reached
| Pin | Connection |
|---|---|
| Center pin (inside) | +24V |
| Outer sleeve | GND (−) |
Standard positive-center polarity. Solder or crimp a 2.5 mm² red wire to the center pin and a black wire to the sleeve.
| Pin | Color | Connection |
|---|---|---|
| 1 (red) | Red | +24V |
| 2 (red) | Red | +24V |
| 3 (white) | Black | GND (−) |
| 4 (white) | Black | GND (−) |
⚠️ Important distinction:
- DC Skimmer (single motor): you only need to wire pins 1 and 3 (+24V and GND). Pins 2 and 4 can be left unconnected.
- Return pump (ReefRun): you must wire all 4 pins — pins 1+2 for +24V, pins 3+4 for GND. The return pump draws more current and uses both pin pairs to distribute the load. Wiring only 2 pins risks overheating the connector.
🔴 CRITICAL — verify with a multimeter before connecting to the battery!
- Set your multimeter to DC voltage mode
- Touch the probes to pins 1 (+) and 3 (−) on your assembled cable
- Connect momentarily to the battery
- Verify you read +24V to +28V (not negative!)
- A reversed polarity will destroy the ReefBeat controller instantly
Double-check every cable before first use. There is no second chance.
⚠️ Safety: a 15A fuse on the battery + pole, right after the battery, is mandatory. This rating matches the 2.5 mm² cable capacity (~16A max) and provides comfortable margin against typical peak consumption of ~9A (2× ReefWave 45 + ReefRun 12000 + Skimmer + Pi). In case of a short circuit on the load side, this is what saves the battery (and your house).
🔧 DC Skimmer cup full sensor issue: when powered by the LiFePO₄ battery (26-27V instead of the original 24V), the skimmer's cup full sensor becomes unreliable — it triggers false "cup full" alarms even after recalibration. This is a hardware limitation of the probe at higher voltage.
Recommended fix: add a LM2596 DC-DC buck converter (~2€) between the battery bus and the skimmer only, adjusted to 24.0V output.
Wire it to the skimmer's IP68 connector (pins 1+3 only). Then recalibrate the cup sensor via the ReefBeat app, the ha-reefbeat-component integration, or the ha-reef-card. The ReefWave and ReefRun stay connected directly to the battery — they work fine at 26-27V.
- Power continuity during outages (autonomy ~6-12h depending on your pumps)
- No intervention needed when power cuts
- No monitoring, no degradation: pumps run at 100% until the battery is empty
- No visibility on battery state
- No degradation management: battery drains fast, everything shuts off at once
- Risk of repeated deep discharge → accelerated aging
Goal: add real-time battery monitoring, automatic outage detection, and progressive pump degradation based on SoC. This is the recommended level for a permanent installation.
| Component | Suggested model | Approx. price |
|---|---|---|
INA226 module 0-36V/20A (2 mΩ onboard shunt) |
Fasizi INA226 20A | ~14 € |
Raspberry Pi 3 B+ (or newer) |
Pi 3 B+ 1GB at Kubii | ~40 € |
| 16 GB class 10 microSD + Pi USB power supply | — | ~15 € |
| DC-DC converter 24V → 5V 3A for the Pi | Step-down buck regulator | ~8 € |
Finder 40.61.8.230.4000 relay (230V coil, 1 NO/NC) |
Finder 40.61 | ~12 € |
Finder 95.95.3 DIN socket |
Finder 95.95.3 | ~8 € |
| 35 mm DIN rail (10 cm) + small electrical enclosure | — | ~15 € |
Additional budget: ~112 € — Cumulative level 2 budget: ~402 €
230 V ─────┬───────────────┐
│ │
▼ ▼
┌─────────────┐ ┌──────────┐
│ Charger │ │ Relay │
│ Victron 24V │ │ Finder │
└──────┬──────┘ │ 40.61 │
│ 24V │ coil │
▼ │ 230V │
┌─────────────┐ └────┬─────┘
│ Battery │ │ NO/NC
│ LiFePO₄ │ │ contact
└──────┬──────┘ │
│ 24V │
┌──────────────┐ │
│ Shunt INA226 │ │
└──┬───────┬───┘ │
I2C │ │ 24V │
SDA/SCL│ ▼ │
│ ┌────────────┐ │
│ │DC-DC 24V→5V│ │
│ └─────┬──────┘ │
│ │ 5V │
│ ▼ │
│ ┌────────────┐ │
└─│Raspberry Pi│◄───┘
│ GPIO 26 │ GPIO state
│ GPIO 2 SDA│
│ GPIO 3 SCL│
└────────────┘
│
▼
ReefRun / ReefWave / DC Skimmer
INA226 shunt wiring (most important):
The INA226 module must be in series on the battery + pole, between the battery and all loads. This is what allows it to measure net current in/out.
Battery (+) ──► [IN+ shunt INA226 IN−] ──► Bus + 24V ─┬─► Charger (output)
├─► DC-DC to Pi
├─► ReefRun
├─► ReefWave
└─► DC Skimmer
Battery (−) ──────────────────────────► Bus − (common)
The shunt sees:
- positive current = battery is discharging (supplying loads)
- negative current = battery is charging (from charger)
Outage detection relay wiring:
The Finder 40.61.8.230 is a mains voltage absence detector: its coil is powered by 230V, its NO/NC contacts switch when mains drops.
| Socket 95.95.3 terminal | Connection |
|---|---|
| A1 | 230V Phase |
| A2 | 230V Neutral |
| 11 (common) | Pi GND (Pin 39) |
| 12 (NC) | Pi Pin 37 (GPIO 26, with internal pull-up) |
Mains OK → coil energized → NC contact open → GPIO reads 1 (pulled to 3.3V). Outage → coil drops → NC contact closes → GPIO pulled to GND, reads 0.
Pi → INA226 connections (4 wires):
| Pi GPIO | INA226 |
|---|---|
| Pin 1 (3.3V) | VCC |
| Pin 6 (GND) | GND |
| Pin 3 (GPIO 2 SDA) | SDA |
| Pin 5 (GPIO 3 SCL) | SCL |
- Real-time monitoring: battery voltage, current, power, SoC via coulomb counting
- Outage detection in < 1 second via the relay
- Automatic degradation: ReefWaves drop to 70%, then 50%, then 10% as SoC decreases; skimmer turns off in survival mode; etc.
- Configuration snapshots: at outage, original pump config is saved to disk; on power restore, it's restored identically
- MQTT buffer: while HA is down (which almost always happens during a real outage), measurements are stored locally and replayed when the broker comes back → you get the complete discharge curve in HA
- Network failover: if the Wi-Fi router also goes down, the Pi switches to hotspot mode to stay reachable
Goal: add remote charger monitoring, a connected circuit breaker for scheduled discharge tests, and 4G LTE backup for notifications when all networks are down.
The three additions of this level are independent — you can install any combination of them:
| Addition | Purpose | Can be installed alone? |
|---|---|---|
| 🔌 Victron BLE charger | Silent charger + charger state in HA | ✅ Yes |
| ⚡ Connected circuit breaker | Automated discharge tests from HA | ✅ Yes |
| 📶 4G LTE module | Notifications + ReefBeat cloud access when Wi-Fi is down | ✅ Yes |
| Component | Suggested model | Approx. price |
|---|---|---|
Victron Blue Smart IP22 24/12 (replaces Kepworth charger — silent + BLE) |
Victron Blue Smart IP22 24/12 | ~155 € |
Connected Wi-Fi circuit breaker 16A with meter |
Tongou TO-Q-SY1-JWT | ~30 € |
SIM7600G-H 4G HAT (recommended — integrated on the Pi, RNDIS) |
Kubii SIM7600G-H HAT | ~75 € |
DC-DC 24V→5V 5A module (required if using SIM7600 HAT — the battery USB alone can't power both) |
DC-DC Buck 9-36V to 5.2V 5A | ~2.50 € |
Or alternatively to the SIM7600:
| Component | Suggested model | Approx. price |
|---|---|---|
Huawei E3372h-320 4G USB dongle (plug-and-play, no extra power needed) |
Huawei E3372h-320 | ~40 € |
| USB tethering from a smartphone (no extra hardware, phone powered via RPi USB) | — | 0 € |
Maximum additional budget: ~262 € (all three with SIM7600) — Cumulative level 3 budget: ~664 €
230 V ──► [Tongou Wi-Fi breaker] ──┬──────────────┐
│ │
▼ ▼
┌─────────────┐ ┌──────────┐
│ Charger │ │ Relay │
│Victron BLE │ │ Finder │
│24/12 Smart │ │detection │
└──────┬──────┘ └────┬─────┘
│ 24V │
▼ │
┌─────────────┐ │
│ Battery │ │
└──────┬──────┘ │
│ 24V │
[shunt INA226] │
│ │
▼ │
(loads) │
│
┌──── Wi-Fi ───┐ │
│ │ │
▼ ▼ │
Home Assistant Raspberry Pi
(Tongou GPIO 26 ◄┘
integration) │
│ USB │
│ BLE ▼
▼ ┌───────────┐
Victron charger │ Huawei │
(real-time) │ E3372h │
│ 4G LTE │
└───────────┘
Tongou TO-Q-SY1-JWT circuit breaker:
A DIN-rail modular breaker controlled via Wi-Fi (Tuya protocol, integrable with HA via Local Tuya or the official Tuya Cloud integration). It also provides real-time kWh / V / A measurement — useful to verify the charger switches to battery when simulating an outage.
Wiring: the breaker is installed just before the Victron charger and the Finder relay. When you switch it off from HA, it's exactly like a real power outage:
- The charger stops providing power
- The Finder relay sees the voltage absence → contact switches
- The Pi sees the outage via GPIO and immediately triggers degradation
Victron Blue Smart IP22 24/12 charger (with BLE):
Replaces the Kepworth charger included with the battery. Besides adding Bluetooth Low Energy, it is significantly quieter: passive cooling at low charge, the fan only kicks in at full charge above 8A. Ideal if the system is installed in a living area.
Publishes to HA:
- Charger state (
storage/bulk/absorption/float) - Real-time output voltage and current
- Error codes (overheat, battery voltage out of range…)
Configuration: retrieve the encryption key from the VictronConnect app (Settings → Product Info → Instant Readout → "Show"), enter it in the configuration wizard.
SIM7600G-H 4G HAT (recommended):
The SIM7600G-H HAT (~75€) connects to the Raspberry Pi via USB. LTE Cat4 150 Mbps, global bands, with GNSS positioning.
The wizard automatically configures it in RNDIS mode — the module appears as a USB network interface (usb0) with DHCP. No PPP, QMI, or AT commands needed for data after initial setup.
First-time setup (handled by the wizard):
- Configure APN:
AT+CGDCONT=1,"IP","your_apn" - Switch to RNDIS:
AT+CUSBPIDSWITCH=9011,1,1 - Module reboots →
usb0appears with IP via DHCP
After initial setup, the module boots automatically in RNDIS mode at every RPi startup — fully autonomous.
⚡ Power note: the battery's built-in USB port can power the Pi alone (~2.1A), but not both the Pi and the SIM7600 HAT. When using the SIM7600, power the RPi via USB through a DC-DC 24V→5V 5A buck module (~2.50€) connected to the battery's +24V bus.
Testing: python3 test_sim7600.py runs a complete diagnostic (serial, SIM, signal, network, connectivity).
LTE monitoring: every 10 minutes (configurable), the system queries the modem via AT commands and publishes to HA: signal strength (dBm), signal quality, operator, network type (4G/3G/2G), SIM status, modem model, firmware, IMEI, IP, and connectivity status.
The E3372h-320 (~40€) is a simpler plug-and-play option. Just plug it into the Pi's USB port with an active SIM card — it creates a virtual Ethernet interface (eth1), no configuration needed. HiLink web interface at http://192.168.8.1.
🔑 SIM PIN: during setup, the wizard detects if the SIM requires a PIN, enters it, and proposes to disable it permanently. Strongly recommended — without it, the modem cannot reconnect after a power cycle.
If you don't want to buy a modem, you can use a smartphone connected via USB as a 4G/5G modem. Enable USB tethering on the phone (Settings → Network → Hotspot → USB tethering), plug it into the RPi, and the wizard will detect it. The phone is powered via USB from the RPi (which is on battery), so it stays charged during the outage.
4G internet gateway for ReefBeat devices (all three LTE options): when the RPi hotspot is active, the RPi acts as a NAT router — it forwards internet traffic from the ReefBeat devices (connected to the hotspot) through 4G. The Red Sea mobile app keeps working during a power outage.
- Remote mains control to the battery from HA
- Scheduled discharge tests: see the blueprint section
- Full charger visibility (mode, current, errors)
- Total consumption measurement in kWh via the Tongou breaker
- Notifications even when everything is down via 4G LTE
- Red Sea mobile app keeps working during outages (4G gateway)
- LTE telemetry in HA — signal, operator, network type, SIM status, IMEI
Goal: double (or more) battery capacity for longer outages.
The simplest and safest method is adding one or more identical batteries in parallel. LiFePO₄ batteries with internal BMS (like the Kepworth 24V 60Ah) natively support parallel operation.
| Component | Approx. price |
|---|---|
| 1× identical LiFePO₄ 24V 60Ah battery | ~260 € |
| 2× interconnect cables 2.5 mm² (50 cm red + 50 cm black, crimped) | ~10 € |
| 1× inline 15A fuse (one per additional battery) | ~3 € |
Budget per +60 Ah: ~273 €
Bus + (to charger and loads)
▲
│
┌─────────────┼─────────────┐
│ │ │
[fuse] [fuse] [fuse]
15 A 15 A 15 A
│ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
│ Bat #1 │ │ Bat #2 │ │ Bat #3 │
│24V 60Ah │ │24V 60Ah │ │24V 60Ah │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└─────────────┼─────────────┘
│
▼
Bus − (common)
- Identical batteries only: same brand, same model, ideally same age. Mixing batteries of different capacities or ages overworks the weakest one → accelerated aging.
- Initial balancing: before connecting in parallel, charge each battery individually to 100% and verify they are at the same voltage (±0.1V). Otherwise, equalization will occur through high current between batteries → risk of melting crimps.
- Equal cross-section cables: if one battery has a longer or thinner cable, it will discharge less → permanent imbalance.
- One fuse per battery, not a single common fuse: if one battery fails, only that one is isolated.
- No change to the INA226 shunt: it stays on the common bus and sees the total combined current from both batteries — exactly what we want for SoC.
For a typical setup (2× ReefWave 45 + 1× ReefRun 12000 + DC Skimmer + Pi):
| Configuration | Usable capacity | 24h target autonomy |
|---|---|---|
| 1× 60 Ah | 1228 Wh | achievable (estimated 32h) |
| 2× 60 Ah | 2457 Wh | comfortable (estimated 60h+) |
| 3× 60 Ah | 3686 Wh | luxurious (90h+) |
⚠️ Re-run theconfigure.pywizard after adding a battery to update the total capacity inconfig.json. The scenario calculation will account for it automatically.
The configure.py wizard is interactive and bilingual (FR/EN based on locale). It guides through several steps:
- Network — Wi-Fi SSID confirmation (read from NetworkManager)
- ReefBeat device detection — automatic subnet scan, select devices to back up
- Outage detection — relay GPIO (recommended) or current monitoring
- Battery — pack capacity (Ah)
- Monitoring — INA226 (mandatory, auto-detected on I2C) + Victron BLE (optional)
- Backup mode — choose between:
- Auto (recommended): set a target autonomy, the wizard detects the Pi, asks about auxiliary loads, and computes optimal SoC levels + intensities
- Simple: a single backup speed for everything
- MQTT — Home Assistant connection settings
- Push notifications — ntfy.sh topic + 4G LTE failover (E3372h or tethering) + NAT gateway
- Scheduled reboot — automatic RPi reboot via cron (skipped if on battery)
- Polling interval
The result is saved in config.json and can be edited manually if needed.
All sensors appear automatically in HA after MQTT discovery configs are published.
| Sensor | Description |
|---|---|
sensor.reef_battery_voltage |
Battery voltage (V) |
sensor.reef_battery_current |
Current (A, + = discharging) |
sensor.reef_battery_power |
Power (W) |
sensor.reef_battery_soc |
State of Charge (%) |
sensor.reef_battery_power_state |
mains / battery |
sensor.reef_battery_pump_intensity |
Average pump intensity (%) |
sensor.reef_battery_runtime |
Estimated runtime (h) — always shows "if power cuts now" |
sensor.reef_battery_outage_duration |
Current outage duration (min) |
sensor.reef_battery_network_mode |
client / rejoin / hotspot |
sensor.reef_battery_monitor_source |
ina226 |
If Victron BLE is configured (level 3):
| Sensor | Description |
|---|---|
sensor.reef_battery_charger_voltage |
Charger output voltage (V) |
sensor.reef_battery_charger_current |
Charger output current (A) |
sensor.reef_battery_charger_state |
bulk / absorption / float / storage |
sensor.reef_battery_charger_error |
no_error / … |
If 4G LTE is configured (level 3):
| Sensor | Description |
|---|---|
sensor.reef_battery_lte_signal |
Signal strength (dBm) |
sensor.reef_battery_lte_signal_quality |
Signal quality (0-31 RSSI scale) |
sensor.reef_battery_lte_operator |
Operator name (e.g. Orange F) |
sensor.reef_battery_lte_network_type |
Network type (LTE/HSPA+/EDGE/GSM) |
sensor.reef_battery_lte_sim_status |
SIM status (ready/pin_required/absent) |
sensor.reef_battery_lte_connected |
Internet reachable via 4G (ON/OFF) |
sensor.reef_battery_lte_ip |
LTE interface IP address |
sensor.reef_battery_lte_model |
Modem model |
sensor.reef_battery_lte_manufacturer |
Modem manufacturer |
sensor.reef_battery_lte_firmware |
Modem firmware version |
sensor.reef_battery_lte_imei |
Modem IMEI |
LTE sensors are updated every 10 minutes (configurable via lte_monitor.check_interval_min in config.json).
During an outage, HA and the MQTT broker are almost always unavailable (they're on the same infrastructure as the mains). The service writes all measurements to /var/lib/reefbeat-energy-backup/mqtt/messages.jsonl and replays them automatically when the broker comes back → you get the complete curve after the fact, with no gaps.
Optional configuration in config.json:
"mqtt": {
"buffer_dir": "/var/lib/reefbeat-energy-backup/mqtt",
"buffer_retention_days": 7
}When a power outage is detected and the home router goes down, here is the complete sequence:
Power outage detected (relay GPIO, instant)
│
▼ wait 30s (configurable, for router UPS to stabilize)
│
├── Step 1: ping ReefBeat controllers via Ethernet (eth0)
│ │
│ ├── OK → Ethernet still works (all switches survived)
│ │ → reduce pump intensity via eth0, done
│ │
│ └── FAIL → Ethernet down (a switch between RPi and router lost power)
│
├── Step 2: scan Wi-Fi for home SSID
│ │
│ ├── FOUND → router is alive (on UPS) but a switch died
│ │ → RPi connects to home Wi-Fi (wlan0)
│ │ → controls ReefBeat via Wi-Fi
│ │ → monitors: if Wi-Fi drops later → go to Step 3
│ │
│ └── NOT FOUND → router is already dead
│ → go to Step 3
│
└── Step 3: create mirror hotspot (same SSID + password on wlan0)
│
├── ReefBeat devices auto-reconnect to RPi hotspot
│ (they already know the SSID/password)
│
├── RPi controls pumps locally via HTTP API
│
├── If 4G modem (E3372h or USB tethering) is available:
│ │
│ ├── NAT enabled: hotspot (wlan0) → 4G (eth1/usb0)
│ │
│ ├── ReefBeat → Red Sea cloud → mobile app ✅
│ │
│ └── ntfy.sh notifications via 4G → your phone ✅
│
└── If no 4G:
└── Local control only (pumps managed, no internet)
⏳ During the outage, the system continuously monitors:
│
├── Battery SoC → adjusts pump intensity (eco → survival → critical)
├── Wi-Fi availability → if home Wi-Fi reappears, switch back from hotspot
└── 4G connectivity → route notifications and ReefBeat traffic
Power restored (relay GPIO, instant)
│
├── Hotspot deactivated (if active), NAT rules cleaned
│
├── RPi reconnects to Ethernet (eth0) when switches come back
│ (automatic — Linux prioritizes eth0 over wlan0)
│
├── ReefBeat devices reconnect to home router Wi-Fi
│
├── Pump configuration restored to pre-outage nominal
│
├── MQTT buffer replayed → HA gets the complete discharge curve
│
└── ntfy notification: "Power restored after Xh, SoC Y%"
Receive alerts directly on your phone without Home Assistant, using the free ntfy.sh service.
Setup:
- Install the ntfy app (Android / iOS)
- Subscribe to your topic (configured during wizard setup)
- That's it — notifications are sent automatically on power outage
Notification events (only triggered during outages):
- ⚡ Power outage detected (with SoC and estimated runtime)
- ✅ Power restored (with outage duration)
- 🟡🟠🔴 Pump level changes (eco → survival → critical)
- 🚨 Battery critically low (repeated alerts every 60s)
- 📡 Network failover status
Priorities: outage = high (sound), critical = urgent (persistent alarm), info = default (silent)
Test from the command line:
python3 test_notif.py # Simple test
python3 test_notif.py --type outage # Simulate power outage
python3 test_notif.py --type critical # Simulate critical battery (alarm)
python3 test_notif.py --type restored # Simulate power restored
python3 test_notif.py --lte # Force send via 4G modem
python3 test_notif.py --message "Hello" # Custom messageAvailable only with level 3 (Tongou circuit breaker required).
This Home Assistant blueprint periodically triggers a real discharge test: it switches off the mains breaker for 40 minutes, observes the discharge curve, and compares it to the forecast computed by the scenario.
Scheduled date (e.g.: last Sunday of the month, every 3 months)
│
▼
Is "user" detected at home?
│
├─── No ──► Test silently cancelled
│
└─── Yes
│
▼
Actionable HA notification on phone
"Run battery test for 40 min?"
(no timeout: waits for explicit response)
│
├─── Decline ──────────────► Cancelled
│
└─── Accept
│
▼
Breaker OFF
Initial SoC / voltage / power saved
Forecast computed (power × duration / capacity)
│
▼
Wait 40 min, OR immediate abort if voltage < threshold
(service switches to battery mode,
MQTT buffer records everything)
│
▼
Breaker ON
│
▼
3-axis analysis:
📊 Forecast: actual SoC consumed vs prediction
🔋 Voltage profile: final voltage in LFP plateau?
⏱ Extrapolated autonomy to 20% SoC
│
▼
Summary notification to phone + HA log
- In Home Assistant, go to Settings → Automations & Scenes → Blueprints
- Click Import Blueprint (bottom right)
- Paste this URL:
https://raw.githubusercontent.com/Elwinmage/reefbeatEnergyBackup/refs/heads/main/blueprints/reef_battery_test.yaml - Click Preview then Import
- Go to Automations → + Create Automation → Use a Blueprint
- Select reefbeat⚡Backup — Battery Test
- Fill in: schedule, person, notification service, breaker switch, SoC/voltage/power sensors, battery capacity, test duration, tolerance, emergency voltage threshold
install.sh Installer (curl | bash)
configure.py Interactive wizard
config.example.json Default template
config.json Your configuration (generated by wizard)
main.py Main service loop
monitor.py INA226 backend + Victron BLE auxiliary
outage.py Outage detection (relay GPIO)
hotspot.py 3-level network failover
controller.py Pump control + outage orchestration
notifier.py Push notifications (ntfy.sh + 4G LTE)
lte_monitor.py LTE modem telemetry (MQTT sensors)
test_notif.py CLI notification tester
test_reefbeat.py CLI ReefBeat equipment tester
test_sim7600.py CLI SIM7600G-H 4G module tester
updater.py Self-update module (GitHub + HA update entity)
update.py CLI update tool
VERSION Current version number
mqtt_buffer.py MQTT buffer with replay
power_estimation.py Power tables + scenario builder
ble_scan.py Victron BLE scanner (used by wizard)
setup.py Dependency installer
docs/
images/ Component images for documentation
blueprints/
reef_battery_test.yaml HA battery test blueprint
| Command | Description |
|---|---|
python3 configure.py |
Reconfigure (re-run the wizard) |
python3 test_reefbeat.py |
Test ReefBeat device communication |
python3 test_reefbeat.py --read |
Read current state of all devices |
python3 test_reefbeat.py --test-all |
Full test cycle (read → change → verify → restore) |
python3 test_sim7600.py |
Test SIM7600G-H 4G module (serial, SIM, signal, connectivity) |
python3 test_notif.py |
Test push notifications |
python3 update.py |
Check for updates |
python3 update.py --install |
Install available update |
python3 ble_scan.py |
Scan for Victron BLE devices |
python3 setup.py --check |
Verify dependencies and hardware |
The wizard can set up an automatic RPi reboot via cron to prevent long-term stability issues (memory leaks, zombie processes). The reboot is skipped automatically if the system is running on battery — it checks the relay GPIO before rebooting.
Configuration example (via wizard):
- Interval: every day (1-30 days configurable)
- Time: 01:00 (any HH:MM)
- Cron job:
/etc/cron.d/reefbeat-reboot - Check script:
/usr/local/bin/reefbeat-reboot-check.sh
To disable manually:
sudo rm /etc/cron.d/reefbeat-rebootAn update entity appears automatically in HA (update.reef_battery_update). It shows the current and latest version, with an Install button when an update is available — just like any HA add-on.
The service checks GitHub every 6 hours (configurable). After clicking "Install", the update is downloaded, config.json is backed up, and the service restarts automatically.
cd ~/scripts/reefbeatEnergyBackup
# Check for updates
python3 update.py
# Install update
python3 update.py --install
# Force reinstall
python3 update.py --force
# Show current version
python3 update.py --versionYou can visualize the battery system's power flows in a Home Assistant dashboard using Power Flow Card Plus (HACS → Frontend).
The card shows real-time power flows between the grid (mains), the battery, and the individual pumps (ReefWave gyres, ReefRun return pump, DC Skimmer) with dynamic icons that change based on pump state.
Add these template sensors to your configuration.yaml to aggregate pump speeds for the Power Flow Card. Adapt entity IDs to match your devices:
template:
- sensor:
# The icon is NOT defined here because
# `power-flow-card-plus` doesn't read the entity icon; it will
# be injected dynamically at card level by
# `config-template-card` (see below). Adapt entity IDs.
- name: "RSWave Gyre 1 Speed"
unique_id: rswave_gyre1_speed
unit_of_measurement: "%"
state: >
{% set f = states('sensor.rswave45_<your_wave1_id>_intensite_marche_avant') | float(0) %}
{% set r = states('sensor.rswave45_<your_wave1_id>_intensite_marche_arriere') | float(0) %}
{{ [f, r] | max | round(0) }}
attributes:
direction: >
{% set f = states('sensor.rswave45_<your_wave1_id>_intensite_marche_avant') | float(0) %}
{% set r = states('sensor.rswave45_<your_wave1_id>_intensite_marche_arriere') | float(0) %}
{% if f > 0 %}→ fwd{% elif r > 0 %}← rev{% else %}■{% endif %}
- name: "RSWave Gyre 2 Speed"
unique_id: rswave_gyre2_speed
unit_of_measurement: "%"
state: >
{% set f = states('sensor.rswave45_<your_wave2_id>_intensite_marche_avant') | float(0) %}
{% set r = states('sensor.rswave45_<your_wave2_id>_intensite_marche_arriere') | float(0) %}
{{ [f, r] | max | round(0) }}
attributes:
direction: >
{% set f = states('sensor.rswave45_<your_wave2_id>_intensite_marche_avant') | float(0) %}
{% set r = states('sensor.rswave45_<your_wave2_id>_intensite_marche_arriere') | float(0) %}
{% if f > 0 %}→ fwd{% elif r > 0 %}← rev{% else %}■{% endif %}power-flow-card-plus only supports a static icon per individual node (discussion #355). To switch icons based on pump state (redsea:gyre-off/min/med/max, redsea:pump-on/off, redsea:skimmer-on/off), wrap the card with config-template-card (HACS → Frontend): the wrapper re-evaluates ${...} variables whenever a listed entity changes state and passes the finalised config to the child card.
Full working example (adapt entity IDs to your devices):
type: custom:config-template-card
variables:
GYRE1_ICON: |
(() => {
const v = Math.max(
parseFloat(states['sensor.rswave45_<your_wave1_id>_intensite_marche_avant'].state) || 0,
parseFloat(states['sensor.rswave45_<your_wave1_id>_intensite_marche_arriere'].state) || 0
);
if (v <= 0) return 'redsea:gyre-off';
if (v < 35) return 'redsea:gyre-min';
if (v < 70) return 'redsea:gyre-med';
return 'redsea:gyre-max';
})()
GYRE2_ICON: |
(() => {
const v = Math.max(
parseFloat(states['sensor.rswave45_<your_wave2_id>_intensite_marche_avant'].state) || 0,
parseFloat(states['sensor.rswave45_<your_wave2_id>_intensite_marche_arriere'].state) || 0
);
if (v <= 0) return 'redsea:gyre-off';
if (v < 35) return 'redsea:gyre-min';
if (v < 70) return 'redsea:gyre-med';
return 'redsea:gyre-max';
})()
PUMP_ICON: |
parseFloat(states['number.rsrun_<your_pump_id>_pump_1_vitesse'].state) > 0
? 'redsea:pump-on' : 'redsea:pump-off'
SKIMMER_ICON: |
parseFloat(states['number.rsrun_<your_pump_id>_pump_2_vitesse'].state) > 0
? 'redsea:skimmer-on' : 'redsea:skimmer-off'
entities:
- sensor.rswave45_<your_wave1_id>_intensite_marche_avant
- sensor.rswave45_<your_wave1_id>_intensite_marche_arriere
- sensor.rswave45_<your_wave2_id>_intensite_marche_avant
- sensor.rswave45_<your_wave2_id>_intensite_marche_arriere
- number.rsrun_<your_pump_id>_pump_1_vitesse
- number.rsrun_<your_pump_id>_pump_2_vitesse
card:
type: custom:power-flow-card-plus
title: Reef Battery Backup
entities:
battery:
entity: sensor.reef_battery_backup_puissance
state_of_charge: sensor.reef_battery_backup_soc_batterie
name: LiFePO4 Battery
icon: mdi:battery
invert_state: true
color:
consumption: "#4caf50"
production: "#ff9800"
display_state: two_way
show_state_of_charge: true
state_of_charge_unit: "%"
state_of_charge_decimals: 0
home:
entity: sensor.reef_battery_backup_energie_consommee
name: Aquarium
icon: mdi:fishbowl-outline
color_value: true
grid:
entity: sensor.reef_battery_backup_tension_chargeur
name: Mains
icon: mdi:transmission-tower
color_value: true
display_state: one_way
individual:
- entity: sensor.rswave_gyre_1_speed
name: Gyre 1
color: "#00bcd4"
icon: ${GYRE1_ICON}
unit_of_measurement: "%"
display_zero: true
secondary_info:
template: |
{{ state_attr('sensor.rswave_gyre_1_speed', 'direction') }}
- entity: sensor.rswave_gyre_2_speed
name: Gyre 2
icon: ${GYRE2_ICON}
color: "#00bcd4"
unit_of_measurement: "%"
display_zero: true
secondary_info:
template: |
{{ state_attr('sensor.rswave_gyre_2_speed', 'direction') }}
- entity: sensor.rsrun_return_pump_speed
name: Return pump
icon: ${PUMP_ICON}
color: "#2196f3"
unit_of_measurement: "%"
display_zero: true
- entity: sensor.rsrun_skimmer_speed
name: Skimmer
icon: ${SKIMMER_ICON}
color: "#ff2030"
unit_of_measurement: "%"
display_zero: true
clickable_entities: true
display_zero_lines:
mode: show
transparency: 50
use_new_flow_rate_model: true💡 The
redsea:gyre-*,redsea:pump-*andredsea:skimmer-*icons come from the ha-reefbeat-component custom icons pack.
ReefWave devices are "cloud-slave" — they are the only ReefBeat devices controlled by the Red Sea cloud rather than locally.
When reefbeat⚡Backup changes a ReefWave's wave program during an outage (reducing intensity, switching to uniform flow), it uses the local HTTP API which works perfectly — the device changes its behavior immediately.
However, the Red Sea cloud and mobile app are unaware of this change. The cloud still believes the ReefWave is running its original schedule. This means:
During an outage:
- ✅ The ReefWave physically runs at the reduced intensity (local API works)
- ✅ Home Assistant sees the correct state (reads from the device directly)
⚠️ The ReefBeat mobile app shows the old schedule (reads from the cloud)
When power is restored:
- ✅ reefbeat⚡Backup restores the original wave program from its snapshot
- ✅ The device, Home Assistant, and the mobile app are all back in sync
- ✅ No manual intervention needed
In practice, this is not a problem: during an outage, you're not managing wave programs from the app anyway. The important thing is that the pumps physically run at the right intensity, and that everything is restored correctly when power returns.
💡 This limitation only affects ReefWave. ReefRun (return pumps, skimmers) are controlled locally and stay in sync with the app at all times.
See TROUBLESHOOTING.md for common issues:
Failed to add edge detection→ installpython3-rpi-lgpio- INA226 reads
0.000A→ verify shunt is wired in series - Victron
'Scanner' has no attribute 'scan'→ incompatiblevictron-bleversion - MQTT discovery sensors missing → check credentials and
base_topic runtime_hshows-1.0→ update to latest version (fixed)
MIT
- ha-reefbeat-component — Home Assistant integration for Red Sea ReefBeat devices
- ha-reef-card — Lovelace card for reef tank management



















