This automation optimizes your aquarium’s light and heater to make the most of PV surplus during the day and reduce power consumption after sunset. It’s designed for clear, reliable scheduling with sensible fallbacks—so your tank stays stable while your energy bill stays low.
What it does
- Uses daytime PV to run lighting and maintain temperature efficiently
- Switches to a night-time eco mode to cut load after sunset
- Keeps logic simple and transparent (easy to tweak in YAML)
Important: Temperature first
Fish and plants are sensitive to rapid temperature swings. Even small daily spikes or drops can stress the ecosystem. Please:
- Monitor water temperature with a reliable sensor; set alerts for out-of-range values.
- Aim for gradual changes (avoid frequent on/off cycles).
- Improve insulation/cover (tight lid, reduced drafts, stable room temp) to keep heat in.
- Size the heater appropriately; overspec’d heaters can cause overshoot.
Safety note: Always test changes at a low-risk time and watch the tank closely for a few days. If temperature deviates, prioritize stability over savings by relaxing the eco schedule.
Script:
Go to Settings → Automations & Scenes → Scripts → + Add Script.
ScriptName: script.aquarium_verify_after_30_minutes
Use your own entity IDs. In this example and below:
- Water temperature:
sensor.sonoff_1002215fd9_temperature - Aquarium heater (switch):
switch.aquarium_heizung_none - Aquarium heater power sensor:
sensor.aquarium_heizung_leistung - Aquarium light 1 (switch):
switch.aquarium_licht_none - Aquarium light 1 power sensor:
sensor.aquarium_licht_leistung - Aquarium light 2 (switch):
switch.nanoaqua_licht_none - Aquarium light 2 power sensor:
sensor.nanoaqua_licht_leistung - NotifyGroup mobiles: notify.iphones
alias: "Aquarium: Verify after 30 minutes"
description: "Prüft 30 Min. nach dem Schalten den gewünschten Zustand und korrigiert ggf. + Push"
mode: parallel
sequence:
# 1) 30 Minuten warten
- delay: "00:30:00"
# 2) Eingaben absichern + Ist-Zustand lesen
- variables:
ent: "{{ entity | default('') }}"
desired: "{{ desired_state | default('') }}"
reas: "{{ reason | default('verification') }}"
current: "{{ states(ent) if ent else 'unknown' }}"
# 3) Nur agieren, wenn ent & desired sinnvoll sind
- choose:
- conditions:
- condition: template
value_template: >
{{ ent != '' and desired in ['on','off'] and current != desired }}
sequence:
# 3a) Korrektur durchführen
- choose:
- conditions: "{{ desired == 'on' }}"
sequence:
- service: switch.turn_on
target:
entity_id: "{{ ent }}"
- conditions: "{{ desired == 'off' }}"
sequence:
- service: switch.turn_off
target:
entity_id: "{{ ent }}"
# 3b) Push mit Status + Leistungen
- service: notify.iphones
data:
title: "Aquarium: Korrektur ({{ reas }})"
message: >-
{{ ent }} war '{{ current }}', sollte '{{ desired }}' sein – korrigiert.
Temp: {{ states('sensor.sonoff_1002215fd9_temperature') }}°C |
Heizung: {{ states('switch.aquarium_heizung_none') }} ({{ states('sensor.aquarium_heizung_leistung') }} W) |
Licht1: {{ states('switch.aquarium_licht_none') }} ({{ states('sensor.aquarium_licht_leistung') }} W) |
Licht2: {{ states('switch.nanoaqua_licht_none') }} ({{ states('sensor.nanoaqua_licht_leistung') }} W)
Code-Sprache: PHP (php)
Automatiion – light off
alias: "[AQUARIUM] Licht AUS (-60m vor Sonnenuntergang)"
description: ""
triggers:
- event: sunset
offset: "-01:00:00"
trigger: sun
conditions: []
actions:
- target:
entity_id:
- switch.aquarium_licht_none
- switch.nanoaqua_licht_none
action: switch.turn_off
- data:
entity: switch.aquarium_licht_none
desired_state: "off"
reason: lights_off
action: script.aquarium_verify_after_30_minutes
- data:
entity: switch.nanoaqua_licht_none
desired_state: "off"
reason: lights_off
action: script.aquarium_verify_after_30_minutes
mode: singleCode-Sprache: CSS (css)
Heating on
alias: "[AQUARIUM] Heizung EIN (+60m nach Sonnenaufgang)"
description: ""
triggers:
- event: sunrise
offset: "01:00:00"
trigger: sun
conditions: []
actions:
- target:
entity_id: switch.aquarium_heizung_none
action: switch.turn_on
- data:
entity: switch.aquarium_heizung_none
desired_state: "on"
reason: heater_on
action: script.aquarium_verify_after_30_minutes
mode: singleCode-Sprache: CSS (css)
Heating off
alias: "[AQUARIUM] Heizung AUS (-30m vor Sonnenuntergang)"
description: ""
triggers:
- event: sunset
offset: "-00:30:00"
trigger: sun
conditions: []
actions:
- target:
entity_id: switch.aquarium_heizung_none
action: switch.turn_off
- data:
entity: switch.aquarium_heizung_none
desired_state: "off"
reason: heater_off
action: script.aquarium_verify_after_30_minutes
mode: singleCode-Sprache: CSS (css)
Reconcile
alias: "[AQUA] Reconcile: Zustände an Zeitplan anpassen"
description: "Stellt nach Neustart/Offline-Phase die Sollzustände wieder her (robust)."
mode: restart
trigger:
- platform: homeassistant
event: start
- platform: time_pattern
minutes: "/15"
condition: []
variables:
now_local: "{{ now() }}"
# Sun-Times sicher in lokale Datetimes umwandeln
next_rising: "{{ as_local(as_datetime(state_attr('sun.sun','next_rising'))) }}"
next_setting: "{{ as_local(as_datetime(state_attr('sun.sun','next_setting'))) }}"
# 'heutiges' Sunrise/Sunset ableiten:
sunrise_today: >-
{% set nr = next_rising %}
{% if nr.date() == now().date() %}
{{ nr }}
{% else %}
{{ nr - timedelta(days=1) }}
{% endif %}
sunset_today: >-
{% set ns = next_setting %}
{% if ns.date() == now().date() %}
{{ ns }}
{% else %}
{{ ns - timedelta(days=1) }}
{% endif %}
# Zeitfenster laut Anforderung:
heater_on_from: "{{ sunrise_today + timedelta(hours=1) }}"
heater_off_at: "{{ sunset_today - timedelta(minutes=30) }}"
lights_on_from: "{{ today_at('09:30:00') }}"
lights_off_at: "{{ sunset_today - timedelta(hours=1) }}"
# Sollzustände jetzt:
want_heater_on: "{{ now_local >= heater_on_from and now_local < heater_off_at }}"
want_lights_on: "{{ now_local >= lights_on_from and now_local < lights_off_at }}"
action:
- choose:
- conditions: "{{ want_heater_on and is_state('switch.aquarium_heizung_none','off') }}"
sequence:
- service: switch.turn_on
target:
entity_id: switch.aquarium_heizung_none
- conditions: "{{ not want_heater_on and is_state('switch.aquarium_heizung_none','on') }}"
sequence:
- service: switch.turn_off
target:
entity_id: switch.aquarium_heizung_none
- choose:
- conditions: "{{ want_lights_on and (is_state('switch.aquarium_licht_none','off') or is_state('switch.nanoaqua_licht_none','off')) }}"
sequence:
- service: switch.turn_on
target:
entity_id:
- switch.aquarium_licht_none
- switch.nanoaqua_licht_none
- conditions: "{{ not want_lights_on and (is_state('switch.aquarium_licht_none','on') or is_state('switch.nanoaqua_licht_none','on')) }}"
sequence:
- service: switch.turn_off
target:
entity_id:
- switch.aquarium_licht_none
- switch.nanoaqua_licht_none
Code-Sprache: PHP (php)
Lights on
alias: "[AQUARIUM] Licht EIN (09:30)"
description: ""
triggers:
- at: "09:30:00"
trigger: time
conditions: []
actions:
- target:
entity_id:
- switch.aquarium_licht_none
- switch.nanoaqua_licht_none
action: switch.turn_on
- data:
entity: switch.aquarium_licht_none
desired_state: "on"
reason: lights_on
action: script.aquarium_verify_after_30_minutes
- data:
entity: switch.nanoaqua_licht_none
desired_state: "on"
reason: lights_on
action: script.aquarium_verify_after_30_minutes
mode: single
Code-Sprache: CSS (css)
7. Alarm if water is too cold (this example 22 degrees)
alias: "[AQUARIUM] Alarm: Temperatur unter 22°C"
description: ""
triggers:
- entity_id: sensor.sonoff_1002215fd9_temperature
below: 22
trigger: numeric_state
conditions: []
actions:
- data:
title: "Aquarium: Temperatur-Alarm (<22°C)"
message: >-
Temp: {{ states('sensor.sonoff_1002215fd9_temperature') }}°C. Heizung:
{{ states('switch.aquarium_heizung_none') }} ({{
states('sensor.aquarium_heizung_leistung') }} W). Licht1: {{
states('switch.aquarium_licht_none') }} ({{
states('sensor.aquarium_licht_leistung') }} W). Licht2: {{
states('switch.nanoaqua_licht_none') }} ({{
states('sensor.nanoaqua_licht_leistung') }} W).
action: notify.iphones
mode: single
Code-Sprache: JavaScript (javascript) 
