so i have a fluval aquasky plant communicating with ha via an esp32board.
i also have a colocast background light that i paired via local tuya. decided to build a controller. that synce the lights to each other and the sun and created biome presets. most of it works except for the storms.
automations
- id: aos_master_engine_v2026_final_sync
alias: "π Aquarium OS 2.0: Master Controller"
description: "Unified Brain for WRGB and Background"
mode: restart
trigger:
- platform: time_pattern
seconds: "/5"
- platform: state
entity_id:
- input_boolean.weather_sync
- input_boolean.storm_active
action:
# βͺ WHITE CHANNEL
- action: number.set_value
target:
entity_id: number.fluvalble_bigtank_channel_white
data:
value: >
{% if is_state('input_boolean.storm_active', 'on') %} 0
{% elif is_state('input_boolean.weather_sync', 'on') %} {{ states('sensor.aquarium_live_white') | int(0) }}
{% else %} 500 {% endif %}
# π΅ BLUE CHANNEL
- action: number.set_value
target:
entity_id: number.fluvalble_bigtank_channel_blue
data:
value: >
{% if is_state('input_boolean.storm_active', 'on') %} 0
{% elif is_state('input_boolean.weather_sync', 'on') %} {{ states('sensor.aquarium_live_blue') | int(0) }}
{% else %} 500 {% endif %}
# π΄ RED CHANNEL
- action: number.set_value
target:
entity_id: number.fluvalble_bigtank_red
data:
value: >
{% if is_state('input_boolean.storm_active', 'on') %} 0
{% elif is_state('input_boolean.weather_sync', 'on') %} {{ states('sensor.aquarium_live_red') | int(0) }}
{% else %} 500 {% endif %}
# π’ GREEN CHANNEL
- action: number.set_value
target:
entity_id: number.fluvalble_bigtank_channel_green
data:
value: >
{% if is_state('input_boolean.storm_active', 'on') %} 0
{% elif is_state('input_boolean.weather_sync', 'on') %} {{ states('sensor.aquarium_live_green') | int(0) }}
{% else %} 500 {% endif %}
# π BACKGROUND LED SYNC
- if:
- condition: state
entity_id: input_select.aquarium_atmosphere
state: "Auto"
# ADDED: Only sync if a storm is NOT running
- condition: state
entity_id: input_boolean.storm_active
state: "off"
then:
- action: light.turn_on
target:
entity_id: light.background_led_bigtank_backlight
data:
rgb_color: >
{% set r = state_attr('sensor.aquarium_atmosphere_engine', 'rgb')[0] | default(255) | int %}
{% set g = state_attr('sensor.aquarium_atmosphere_engine', 'rgb')[1] | default(141) | int %}
{% set b = state_attr('sensor.aquarium_atmosphere_engine', 'rgb')[2] | default(227) | int %}
{% if r == 255 and g == 141 and b == 227 %}
{{ [100, 200, 255] }}
{% else %}
{{ [r, g, b] }}
{% endif %}
brightness_pct: 60
- alias: "AOS: Stochastic Storm Trigger"
description: "Syncs the Master Controller to the Storm switch with the correct entity name"
trigger:
- platform: state
entity_id: input_boolean.storm_active
action:
- if:
- condition: state
entity_id: input_boolean.storm_active
state: "on"
then:
- service: automation.turn_off
target:
entity_id: automation.aquarium_os_2_0_master_controller
else:
- service: automation.turn_on
target:
entity_id: automation.aquarium_os_2_0_master_controller
- alias: "AOS: Update Storm Schedule"
description: "Updates the dashboard timer for the next storm"
trigger:
- platform: state
entity_id: input_boolean.storm_active
from: "on"
to: "off"
action:
- service: input_datetime.set_datetime
target:
entity_id: input_datetime.aquarium_next_storm
data:
timestamp: >
{# Sets next storm to a random time between 6 and 24 hours from now #}
{{ (as_timestamp(now()) + range(21600, 86400) | random) }}
- alias: "Aquarium: Master Atmosphere Controller"
id: "aquarium_master_atmosphere_controller"
mode: restart
trigger:
- platform: state
entity_id: input_select.aquarium_atmosphere
action:
- repeat:
while:
- condition: template
value_template: >
{{ states('input_select.aquarium_atmosphere') != 'Auto' and
is_state('input_boolean.storm_active', 'off') }}
sequence:
- choose:
# π₯ FIREPLACE (Faster flicker)
- conditions:
- condition: template
value_template: "{{ 'Fireplace' in states('input_select.aquarium_atmosphere') }}"
sequence:
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [255, 60, 0], brightness_pct: 80, transition: 1.5}
- delay: 1.5
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [180, 30, 0], brightness_pct: 35, transition: 2}
- delay: 2
# π VOLCANO / VENT (Slow heavy magma pulse)
- conditions:
- condition: template
value_template: "{{ 'Volcano' in states('input_select.aquarium_atmosphere') or 'Vent' in states('input_select.aquarium_atmosphere') }}"
sequence:
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [255, 10, 0], brightness_pct: 90, transition: 5}
- delay: 5
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [80, 0, 0], brightness_pct: 15, transition: 8}
- delay: 8
# π DEEP WATER
- conditions:
- condition: template
value_template: "{{ 'Deep' in states('input_select.aquarium_atmosphere') or 'Abyss' in states('input_select.aquarium_atmosphere') or 'Bioluminesc' in states('input_select.aquarium_atmosphere') or 'Midnight' in states('input_select.aquarium_atmosphere') or 'Reef' in states('input_select.aquarium_atmosphere') }}"
sequence:
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [0, 0, 150], brightness_pct: 20, transition: 8}
- delay: 8
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [20, 20, 200], brightness_pct: 45, transition: 8}
- delay: 8
# πΏ BIOME
- conditions:
- condition: template
value_template: "{{ 'Jungle' in states('input_select.aquarium_atmosphere') or 'Forest' in states('input_select.aquarium_atmosphere') or 'Mangrove' in states('input_select.aquarium_atmosphere') or 'Mediterranean' in states('input_select.aquarium_atmosphere') }}"
sequence:
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [20, 110, 20], brightness_pct: 50, transition: 8}
- delay: 8
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [90, 130, 35], brightness_pct: 30, transition: 8}
- delay: 8
# βοΈ WEATHER
- conditions:
- condition: template
value_template: "{{ 'Storm' in states('input_select.aquarium_atmosphere') or 'Thunder' in states('input_select.aquarium_atmosphere') or 'Peak' in states('input_select.aquarium_atmosphere') or 'Mist' in states('input_select.aquarium_atmosphere') or 'Arctic' in states('input_select.aquarium_atmosphere') }}"
sequence:
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [255, 255, 255], brightness_pct: 100, transition: 0.1}
- delay: {milliseconds: 100}
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [30, 30, 60], brightness_pct: 10, transition: 3}
- delay: "{{ range(4, 15) | random }}"
# π
SKY
- conditions:
- condition: template
value_template: "{{ 'Sun' in states('input_select.aquarium_atmosphere') or 'Hour' in states('input_select.aquarium_atmosphere') or 'Dew' in states('input_select.aquarium_atmosphere') or 'Chill' in states('input_select.aquarium_atmosphere') or 'Sahara' in states('input_select.aquarium_atmosphere') or 'Caribbean' in states('input_select.aquarium_atmosphere') }}"
sequence:
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [255, 110, 0], brightness_pct: 65, transition: 15}
- delay: 15
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [255, 45, 0], brightness_pct: 40, transition: 15}
- delay: 15
# π‘ VIBE
- conditions:
- condition: template
value_template: "{{ 'Tokyo' in states('input_select.aquarium_atmosphere') or 'Party' in states('input_select.aquarium_atmosphere') or 'Algae' in states('input_select.aquarium_atmosphere') or 'Movie' in states('input_select.aquarium_atmosphere') or 'Feeding' in states('input_select.aquarium_atmosphere') }}"
sequence:
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [255, 0, 255], brightness_pct: 95, transition: 2}
- delay: 2
- action: light.turn_on
target: {entity_id: light.background_led_bigtank_backlight}
data: {rgb_color: [0, 255, 255], brightness_pct: 95, transition: 2}
- delay: 2
- delay: 1```
- alias: "Aquarium: Force Thunderstorm on Switch"
id: aquarium_force_thunderstorm_switch
mode: single
trigger:
- platform: state
entity_id: input_boolean.storm_active
from: "off"
to: "on"
action:
- action: input_select.select_option
target:
entity_id: input_select.aquarium_atmosphere
data:
option: "Thunderstorm
heres my template
# π§ AQUARIUM OS 2.0 - SCIENTIFIC ENGINE
- sensor:
# βοΈ SOLAR ENGINE
- name: "Aquarium Solar Intensity"
unique_id: aos_solar_v2026_final
unit_of_measurement: "pts"
state: >
{% set rise = today_at("06:17").timestamp() %}
{% set sunset = today_at("19:55").timestamp() %}
{% set now_ts = now().timestamp() %}
{% if rise <= now_ts <= sunset %}
{% set noon = rise + ((sunset - rise) / 2) %}
{{ (((now_ts - rise) / (noon - rise)) * 1000) | int if now_ts <= noon else (1000 - (((now_ts - noon) / (sunset - noon)) * 1000)) | int }}
{% else %} 0 {% endif %}
# π¦οΈ MODIFIERS
- name: "Aquarium Environment Modifier"
unique_id: aos_env_mod_final
state: >
{% set w = states('weather.kccr') %}
{% if is_state('input_boolean.storm_active', 'on') %} 0.0
{% elif is_state('input_boolean.weather_sync', 'on') %}
{% if w in ['cloudy', 'partlycloudy', 'fog'] %} 0.6
{% elif w in ['rainy', 'pouring', 'snowy'] %} 0.4
{% else %} 1.0 {% endif %}
{% else %} 1.0 {% endif %}
# π§ͺ BIOME DICTIONARY (Full Library)
- name: "Aquarium Biome Dictionary"
unique_id: aos_biomes_v2026_final
state: >
{% set m = states('input_select.aquarium_mode') or states('input_select.aquarium_mode_2') %}
{{ m | lower | trim if m not in ['unknown', 'unavailable', 'none', ''] else 'midday peak' }}
attributes:
# Raw Ratios: [White, Blue, Red, Green]
channels: >
{% set map = {
'amazon basin': [1.0, 0.4, 0.2, 0.1],
'blackwater': [0.2, 0.2, 0.8, 0.0],
'lake malawi': [1.0, 0.9, 0.1, 0.0],
'tanganyika rock': [0.9, 1.0, 0.0, 0.0],
'indo-pacific reef': [0.4, 1.0, 0.1, 0.0],
'australian river': [0.8, 0.5, 0.4, 0.2],
'mangrove swamp': [0.6, 0.5, 0.5, 0.2],
'peat swamp': [0.1, 0.2, 0.7, 0.5],
'coldwater stream': [0.7, 0.9, 0.1, 0.0],
'brackish estuary': [0.6, 0.6, 0.3, 0.1],
'plant growth': [0.5, 0.4, 1.0, 0.2],
'high tech': [1.0, 0.8, 0.9, 0.5],
'low tech': [0.5, 0.4, 0.3, 0.1],
'algae scrubber': [0.0, 0.1, 1.0, 0.0],
'breeding': [0.3, 0.3, 0.2, 0.1],
'fry growout': [0.7, 0.6, 0.4, 0.2],
'quarantine': [0.4, 0.2, 0.1, 0.0],
'midday peak': [1.0, 1.0, 1.0, 1.0],
'golden hour': [0.6, 0.1, 1.0, 0.0],
'deep blue': [0.0, 1.0, 0.0, 0.0],
'moonlight only': [0.0, 0.3, 0.0, 0.0],
'stormy sky': [0.3, 0.3, 0.4, 0.1],
'cloudy day': [0.5, 0.5, 0.5, 0.2]
} %}
{{ map.get(this.state, [1.0, 1.0, 1.0, 1.0]) }}
description: >
{% set desc = {
'amazon basin': 'Dense jungle canopy; warm, high-intensity white.',
'blackwater': 'Tannin-stained; dim, tea-colored tint with low white.',
'lake malawi': 'Rift Valley clarity; crisp, high-alkalinity bright white.',
'tanganyika rock': 'Deep water rock shelf; cool-spectrum white.',
'indo-pacific reef': 'Oceanic depth; actinic blue/white blend.',
'australian river': 'Clear outback waters; balanced midday brightness.',
'mangrove swamp': 'Intertidal zone; morning and evening bias.',
'peat swamp': 'Dim swamp floor; extra dim with red/green bias.',
'coldwater stream': 'Mountain runoff; low intensity cool white.',
'brackish estuary': 'Coastal mix; cloudy/natural spectral shift.',
'plant growth': 'Photosynthetic peak; pink/red heavy spectrum.',
'high tech': 'CO2 optimization; maximum PAR output.',
'low tech': 'Algae prevention; gentle lighting for slow growth.',
'algae scrubber': 'Refugium growth; targeted red spectrum.',
'breeding': 'Low stress; soft, non-stressful lighting.',
'fry growout': 'Development mode; extended daylight hours.',
'quarantine': 'Recovery mode; dim, antiseptic lighting.',
'midday peak': 'Solar noon; 100% burst for 1 hour.',
'golden hour': 'Sunset transition; warm orange glow.',
'deep blue': 'Nighttime actinic; heavy blue spectrum.',
'moonlight only': 'Lunar simulation; blue channel at 2-5%.',
'stormy sky': 'Low pressure simulation; dim with random flicker.',
'cloudy day': 'Overcast simulation; neutral grey/dim white.'
} %}
{{ desc.get(this.state, 'Standard spectrum for selected biome.') }}
target_values: >
{% set c = this.attributes.channels %}
W: {{ (c[0]*100)|int }}% | B: {{ (c[1]*100)|int }}% | R: {{ (c[2]*100)|int }}% | G: {{ (c[3]*100)|int }}%
# π¨ ATMOSPHERE ENGINE (The Complete 30)
- name: "Aquarium Atmosphere Engine"
unique_id: aquarium_master_atmosphere_engine
state: >
{% set a = states('input_select.aquarium_atmosphere') %}
{{ a | lower | trim if a not in ['unknown', 'unavailable', 'none', ''] else 'auto' }}
attributes:
description: >
{% set desc = {
'auto': 'System-managed lighting based on solar/lunar cycle.',
'manual': 'Static neutral white; all animations paused.',
'feeding time': 'High-visibility white for inspection/feeding.',
'movie mode': 'Deep dimming to reduce room glare.',
'amazon jungle': 'Dense canopy greens; slow organic breathing.',
'boreal forest': 'Cooler pine greens with filtered sunlight.',
'mangrove': 'Coastal root-zone teal and earthy greens.',
'mediterranean': 'Bright coastal turquoise and high-intensity white.',
'deep sea': 'Abyssal blue; slow, heavy depth pressure pulse.',
'abyss': 'Near-total darkness with faint deep-blue shimmer.',
'bioluminescent': 'Neon teal and electric blue pulses.',
'midnight': 'Moonless night; minimal visibility.',
'reef blue': 'Actinic blue spectrum for coral/color pop.',
'thunderstorm': 'Dark blue-grey with erratic white lightning.',
'stormy peak': 'High-altitude grey with rapid flicker.',
'highland mist': 'Soft, foggy white with low-contrast shifts.',
'arctic': 'Freezing pale blue and white shimmer.',
'sunrise': 'Early morning pink and soft orange transition.',
'golden hour': 'Deep sunset orange; heavy warm saturation.',
'morning dew': 'Crisp, cool-toned morning light.',
'evening chill': 'Deepening purple and blue twilight.',
'sahara': 'High-heat desert yellow and harsh orange.',
'caribbean': 'Shallow water cyan and vibrant turquoise.',
'mangrove sunset': 'Deep fiery orange hitting coastal greens.',
'volcano': 'Heavy magma pulse; deep red to cooling embers.',
'volcanic vent': 'Intense localized red heat pulse.',
'fireplace': 'Cozy hearth flicker; warm orange and red jumps.',
'neon tokyo': 'Vibrant synthwave pulse; pink and cyan shift.',
'party': 'High-energy cycle through the full RGB spectrum.',
'algae scrubber': 'Pure growth spectrum; specialized heavy red.'
} %}
{{ desc.get(this.state, 'Dynamic lighting effect active.') }}
target_rgb: >
{% set map = {
'amazon jungle': [20, 110, 20], 'boreal forest': [30, 80, 30], 'mangrove': [40, 120, 50],
'mediterranean': [200, 255, 255], 'deep sea': [0, 0, 150], 'abyss': [10, 10, 80],
'bioluminescent': [0, 255, 150], 'midnight': [5, 5, 40], 'reef blue': [0, 100, 255],
'thunderstorm': [30, 30, 60], 'stormy peak': [50, 50, 80], 'highland mist': [150, 150, 180],
'arctic': [200, 220, 255], 'sunrise': [255, 100, 50], 'golden hour': [255, 120, 0],
'morning dew': [180, 200, 150], 'evening chill': [100, 100, 150], 'sahara': [255, 180, 50],
'caribbean': [0, 200, 200], 'mangrove sunset': [255, 80, 30], 'volcano': [255, 10, 0],
'volcanic vent': [180, 20, 0], 'fireplace': [255, 60, 0], 'neon tokyo': [255, 0, 255],
'party': [200, 0, 200], 'algae scrubber': [0, 255, 0], 'feeding time': [255, 255, 255],
'movie mode': [20, 20, 20], 'manual': [255, 255, 255], 'auto': [150, 150, 150]
} %}
{{ map.get(this.state, [255, 255, 255]) }}
# π LIVE CHANNELS
- name: "Aquarium Live White"
unit_of_measurement: "pts"
state: >
{% set solar = states('sensor.aquarium_solar_intensity') | float(0) %}
{% set env = states('sensor.aquarium_environment_modifier') | float(1.0) %}
{% set multi = state_attr('sensor.aquarium_biome_dictionary', 'channels')[0] | float(1.0) %}
{{ (solar * env * multi) | int }}
- name: "Aquarium Live Blue"
unit_of_measurement: "pts"
state: >
{% set solar = states('sensor.aquarium_solar_intensity') | float(0) %}
{% set env = states('sensor.aquarium_environment_modifier') | float(1.0) %}
{% set multi = state_attr('sensor.aquarium_biome_dictionary', 'channels')[1] | float(1.0) %}
{{ (solar * env * multi) | int }}
- name: "Aquarium Live Red"
unit_of_measurement: "pts"
state: >
{% set solar = states('sensor.aquarium_solar_intensity') | float(0) %}
{% set env = states('sensor.aquarium_environment_modifier') | float(1.0) %}
{% set multi = state_attr('sensor.aquarium_biome_dictionary', 'channels')[2] | float(1.0) %}
{{ (solar * env * multi) | int }}
- name: "Aquarium Live Green"
unit_of_measurement: "pts"
state: >
{% set solar = states('sensor.aquarium_solar_intensity') | float(0) %}
{% set env = states('sensor.aquarium_environment_modifier') | float(1.0) %}
{% set multi = state_attr('sensor.aquarium_biome_dictionary', 'channels')[3] | float(1.0) %}
{{ (solar * env * multi) | int }}
# π LUNAR ENGINE
- name: "Aquarium Lunar Intensity"
unique_id: aos_lunar_v2026_final
unit_of_measurement: "pts"
state: >
{% set moon_rise = today_at("19:55").timestamp() %}
{% if now().timestamp() >= moon_rise %} 100 {% else %} 0 {% endif %}
# βοΈ STORM ENGINE
- name: "Aquarium Storm Active"
unique_id: aos_storm_active_final
state: "{{ is_state('input_boolean.storm_active', 'on') }}"
- name: "Aquarium Storm Probability"
unique_id: aos_storm_prob_final
unit_of_measurement: "%"
state: >
{% if is_state('input_boolean.aquarium_random_storms', 'on') %} {{ range(1, 101) | random }}
{% else %} 0 {% endif %}
# π BACKGROUND SPECTRAL SYNC
- name: "AOS Background Spectral Sync"
unique_id: aos_bg_color_sync_v2
state: >
{% if states('sensor.aquarium_solar_intensity') | int(0) > 0 %} Day {% else %} Night {% endif %}
attributes:
rgb_color: >
{% set r = (states('sensor.aquarium_live_red') | int(0) * 0.255) | round(0) %}
{% set g = (states('sensor.aquarium_live_green') | int(0) * 0.255) | round(0) %}
{% set b = (states('sensor.aquarium_live_blue') | int(0) * 0.255) | round(0) %}
{{ [r, g, b] }}
- name: "55g Tank Temperature"
unique_id: aquarium_55g_temp_sensor
unit_of_measurement: "Β°F"
device_class: temperature
state: "{{ states('input_number.55g_tamp') | float(77) }}"
here are my helpers
# π¦οΈ Master Overrides
weather_sync:
name: "βοΈ Global Weather Sync (KCCR)"
icon: mdi:weather-partly-cloudy
random_storms:
name: "β‘ Enable Stochastic Thunderstorms"
icon: mdi:flash
# π Maintenance toggles
feeding_mode_55g:
name: "π 55g Feeding Mode (Kills Filters for 15m)"
icon: mdi:fish
# π§ͺ Hardware Toggles
uv_sterilizers_55g:
name: "π¦ 55g UV Sterilizers Override"
icon: mdi:lightbulb-fluorescent-tube
storm_active:
name: "Aquarium Storm Active Toggle"
icon: mdi:weather-lightning```
selects
# π BUS A: The 55g Fluval Biological Spectrum
aquarium_mode:
name: "π 55g Biological Biome"
icon: mdi:earth
options:
- "Amazon Basin"
- "Blackwater"
- "Lake Malawi"
- "Tanganyika Rock"
- "Indo-Pacific Reef"
- "Australian River"
- "Mangrove Swamp"
- "Peat Swamp"
- "Coldwater Stream"
- "Brackish Estuary"
- "Plant Growth"
- "High Tech"
- "Low Tech"
- "Algae Scrubber"
- "Breeding"
- "Fry Growout"
- "Quarantine"
- "Midday Peak"
- "Golden Hour"
- "Deep Blue"
- "Moonlight Only"
- "Stormy Sky"
- "Cloudy Day"
# π BUS B: The Background Atmosphere Strip
aquarium_atmosphere:
name: "π 55g Background Atmosphere"
icon: mdi:led-strip
options:
- "Auto"
- "Manual"
- "Feeding Time"
- "Movie Mode"
- "Amazon Jungle"
- "Boreal Forest"
- "Mangrove"
- "Mediterranean"
- "Deep Sea"
- "Abyss"
- "Bioluminescent"
- "Midnight"
- "Reef Blue"
- "Thunderstorm"
- "Stormy Peak"
- "Highland Mist"
- "Arctic"
- "Sunrise"
- "Golden Hour"
- "Morning Dew"
- "Evening Chill"
- "Sahara"
- "Caribbean"
- "Mangrove Sunset"
- "Volcano"
- "Volcanic Vent"
- "Fireplace"
- "Neon Tokyo"
- "Party"
- "Algae Scrubber"