Dashboard 2 - Control Panel
Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.
Files: dashboards/dashboard_2_control_panel.yaml, packages/grow_dashboard.yaml, packages/grow_climate.yaml, packages/grow_actuators.yaml, packages/grow_irrigation.yaml, packages/grow_light.yaml, packages/grow_air.yaml, packages/grow_energy.yaml, packages/grow_alarms.yaml
Overview view (landing tab)
The first tab you land on when opening Dashboard 2 - intended as a true single-pane-of-glass view of the whole environment, so you don’t have to open every other tab just to confirm nothing needs attention.
Since Phase 9 (2026-08-28, “Environment Status” redesign): an “Environment Status” section at the top gives one line per module, each reusing the exact live state each module’s own view already reads (same entities, same conditions - condensed to a single glance-friendly line rather than that view’s fuller wording):
- The Alarms module’s own all-clear/active-alarms banner, shown first and most prominently, since Alarms already consolidates every other module’s fault flags into one place (Climate safety pause, Light/Air fault watchdogs, Irrigation failsafe, Dashboard 1 mapping issues).
- Setup - the same mapping-validation summary as before.
- Climate - control on/off, current mode, paused flag.
- Irrigation - control on/off, failsafe tripped, daily limit reached, VWC Lock active.
- Light - control on/off, Top/Under-Canopy fault flags.
- Air - control on/off, CO2 safety ceiling exceeded, each fan’s fault flag.
- Energy - whether Total/Light/Climate power tracking is set up.
Below that: the Grow Tracker card (batch/cycle name, current phase,
day in phase, flower day, expected harvest date - the read-only “where’s
the grow at” info), and small Temperature/Humidity/VPD tiles. The
editable cycle fields (Grow Cycle ID, cycle-start dates, Harvest
Completed) were moved off this view entirely as of the earlier redesign -
see “Overview redesign: Environment Status + Cycle Configuration moved
(2026-08-28)” below. Grow Tracker’s read-only fields are the same
sensor.grow_tracker_* entities from packages/grow_tracker.yaml shown
elsewhere too, plus (since the follow-up below) sensor. grow_tracker_cycle_name - a read-only mirror of the Grow Cycle ID, added
purely so this view can show the batch name without a second editable
copy of it.
Since Phase 9 (2026-08-28, “more Overview features” follow-up): below the Temperature/Humidity/VPD tiles, the Overview now also has a “Climate & Irrigation” section (a condensed combined historical chart
- Temperature/Humidity/VPD/VWC/EC - with its own 1h/6h/24h/3d/7d range selector, independent from the Climate & VPD and Irrigation views’ own selectors) and a “Light” section (Top Light / Under-Canopy live power tiles, plus the same on/off timeline the Light view has). See “Overview follow-up: combined chart, Light power/timeline, batch name, Cycle ID reset+save” further down for the full design writeup.
Scope (Climate & VPD view)
Phase 2 adds the first view of Dashboard 2 - the live control panel. This view is display-only:
- Live tiles for current Temperature, Humidity, and VPD.
- Historical charts (Temperature / Humidity / VPD together) with a time-range selector: 1h, 6h, 24h, 3 days, 7 days, and a link out to the native History page for any custom range.
No active climate control yet. Turning the dehumidifier/humidifier on or off automatically based on these readings is Phase 3. This view only reads and displays - it does not write to any actuator.
Requirements
- HACS installed, with the
apexcharts-cardcustom card added via HACS (Frontend section). Without it, the historical chart cards will show as “Custom element doesn’t exist” - the gauge tiles at the top still work without it. packages/grow_core.yamldeployed with the Phase 2 update (addssensor.grow_temperature_current/sensor.grow_humidity_current).- At minimum, Temperature and Humidity mapped on Dashboard 1 (same requirement as Phase 1) - Phase 2 does not add any new required mapping.
- Since Phase 9 (2026-08-28): the
card-mod,mushroom, andexpander-cardHACS frontend cards, for the dynamic gauge coloring, the device/Master-Control tile redesign, and the collapsible explainer notes respectively - see “Growlink polish” further down for exactly what needs each one and what happens if any is missing.expander-cardis also used on Dashboard 1 and Dashboard 3, not just this one.
How the time-range selector works
input_select.grow_chart_range (defined in packages/grow_dashboard.yaml)
holds the currently selected range. The dashboard has five pre-built
custom:apexcharts-card cards, each with a fixed graph_span (1h, 6h, 24h,
3d, 7d) wrapped in a type: conditional card that only shows when
input_select.grow_chart_range matches that range. Switching the dropdown
swaps which chart is visible - only one chart renders (and queries the
Recorder) at a time.
This design was chosen over trying to template graph_span directly inside
a single apexcharts-card instance, since Jinja-templated graph_span is not
reliably supported across apexcharts-card versions. Five small static chart
configs is more verbose but works everywhere.
“Custom” is intentionally not one of the dropdown options - there’s a
markdown card below the charts linking to Home Assistant’s native History
page (/history?entity_id=...), which already has a full date-range picker.
Rebuilding that inside apexcharts-card would duplicate functionality HA
already provides for free.
Climate Setpoints card (Phase 3)
Added below the live values, on the same “Climate & VPD” view: a “Master
Control” mushroom-tile row (Auto Control, Follow Light, Paused - see
“Master Control & fault redesign” under Growlink polish further down for
why these three moved out of the entities card), followed by an entities
card starting with a “Mode & status” section (the grow_climate_mode
selector - RH/Temp Direct vs. VPD Driven -, grow_climate_is_daytime, and
grow_climate_last_decision), then the day/night setpoint + tolerance
fields for RH/Temperature/VPD. See docs/docs/module-climate.md for what
each mode does and the safety behavior. A markdown note below the card
explains which setpoints apply to which mode, shows a 🔄 banner while the
daytime sync is active, and surfaces a warning banner when control is off
or paused.
Devices view (Phase 3)
A second view, “Devices”, with one card per mapped actuator (dehumidifier,
humidifier, AC, up to 4 top lights, up to 4 under-canopy lights, both
irrigation pumps, exhaust fan, intake fan, circulation fan, drain pump,
CO2 valve - 18 total as of Phase 7’s optional Intake Fan addition, see
docs/docs/module-light.md and docs/docs/module-air.md). Tap a card to
toggle the device by hand, regardless of what (if anything) is
automatically controlling it - useful for manual overrides, and for
verifying a device is wired/mapped correctly. Built on
switch.grow_actuator_* template switches from packages/grow_actuators.yaml
(stable proxies to whatever’s currently mapped - same pattern as the Phase 2
pass-through sensors) rather than referencing mapped entities directly, for
the same reason those sensors exist: static dashboard YAML can’t reference
“whatever is currently mapped.”
Since Phase 9’s Growlink polish (2026-08-28), these are
custom:mushroom-template-card (HACS “mushroom”) instead of the original
stock tile cards, specifically to give “not mapped” its own honest visual
language instead of looking like a fault: 🟢 green icon = on, blue-grey =
off, grey with a “Not mapped” secondary line = that function isn’t assigned
on Dashboard 1 (or the mapped device is unreachable) - deliberately never
red, since an unmapped optional slot isn’t a problem. The same conversion
was applied to the Irrigation-pump tiles, the Light/Air “Devices” grids
further down, and the Energy view’s Live Power tiles. Real faults are never
shown on any of these cards - they’re reported separately on each module’s
own Master Control card. Without the mushroom HACS card installed, these
specific cards show “Custom element doesn’t exist” (unlike card-mod,
which degrades gracefully - see “Growlink polish” further down).
Manual toggles here can be overridden by automatic climate control if it’s enabled and that device is one it manages (dehumidifier/humidifier/ AC) - the regulation automation may switch it back on its next cycle.
Irrigation & Substrate view (Phase 4)
A fourth view with everything for packages/grow_irrigation.yaml: a status
banner (control off / failsafe tripped / daily limit reached / VWC Lock
active - new 2026-08-27), a “Master Control” mushroom-tile row (Auto
Control, Failsafe, VWC Lock - since Phase 9’s broader Growlink polish, see
further down), a 2-column row with the safety-limits/status
entities card + failsafe clear button on the left and the two per-pump
schedule.* entities (tap either to open its own unlimited weekly block
editor - no fixed slot count) + pump tile buttons on the right, a
time-range-selectable historical chart overlaying substrate VWC, EC, and
both pumps’ on/off activity so you can see how watering actually affects
moisture, live substrate readings, and the manual-run section (duration,
zone, estimated volume, “Run Now” button). The safety-limits/status
entities card also has a VWC Lock section (enable toggle, threshold,
currently-locked sensor) and a lifetime delivered-volume field, added
2026-08-27 - see “VWC Lock” and “Lifetime delivered-volume tracking” in
docs/docs/module-irrigation.md. A Crop-Steering Preset card (added
2026-08-28, Phase 5/R12) sits between the P1/P2 explainer and the “Clear
Failsafe” button: a “Vegetative”/“Generative” dropdown plus an “Apply
Preset” button that bulk-sets VWC Lock Threshold, Failsafe VWC Threshold,
P1/P2 shot sizes, and Max Events/Day to that preset’s starting values -
nothing changes until Apply is tapped, and every field stays individually
adjustable afterward, see “Crop-Steering Presets” in
docs/docs/module-irrigation.md. Redesigned 2026-08-25 from an earlier
fixed-6-slot layout - see docs/docs/module-irrigation.md for why, and for
what each setting does.
Light view (Phase 6)
A fifth view with everything for packages/grow_light.yaml: a status
banner (control on/off, fault flags, last decision), a “Master Control”
mushroom-tile row (Auto Control, Under-Canopy, Top Fault, UC Fault) with a
“Status Log” entities card below it for the automation-managed Last
Decision field (since Phase 9’s broader Growlink polish, see further
down), a “Top Light” and an “Under Canopy” entities card (each a
start time + duration-in-hours pair, the same window shape as the
irrigation P1 window), “Top Light Slots” / “Under Canopy Slots” mushroom-
tile rows (4 on/off toggles each, for which of up to 4 physical lights per
group are actually in use - also converted from entities cards in the same
pass), a 4x2 tile grid for the eight light actuators
for manual override, a “Light Output” section (added 2026-08-27, optional -
live measured power, running %, and a live PPFD estimate, for both Top
Light and Under Canopy - depends on the Energy module’s per-device power
mapping from Dashboard 1; the per-group Max Wattage and PPFD calibration
inputs that used to sit in this same section moved to Dashboard 1’s “Light
Output Calibration” card on 2026-08-29, alongside the project’s other
one-time setup fields), and a simple two-row “Light Timeline” beam chart
(native history-graph card, no HACS dependency) showing when each light
group was actually on. Went through several redesigns on 2026-08-25 (a
per-grow-phase layout, a UI-created-schedule:-helper layout, a 5-range
apexcharts-card overlay for the chart, then extending from 2 to 4 lights
per group with per-slot enable toggles) before settling on this design per
direct user feedback - see docs/docs/module-light.md for the full
version history and what each setting does, including the Wattage %/PPFD
estimator added 2026-08-27.
Air & CO2 view (Phase 7)
A sixth view with everything for packages/grow_air.yaml: a status banner
(control on/off, CO2 safety banner, fault flags including Intake, last
decision), a “Master Control” mushroom-tile row (Auto Control, CO2 Dosing,
CO2 Ceiling, Exhaust/Circ./Intake/CO2 Fault - 7 tiles, since Phase 9’s
broader Growlink polish, see further down) with a “Status Log” entities
card below it for the automation-managed Last Decision field, an Exhaust
card (mode selector
- Off / Duty Cycle / Always On - plus duty-cycle length + on duration)
with an explainer of its modes and triggers (duty cycle, Climate override,
CO2 safety override - the last one applies in every mode), an Intake Fan
card (optional - no config, just shows whether it’s mapped and following
Exhaust’s decision), a Circulation card (same 3-way mode selector plus its
own independent duty cycle), a CO2 card (live ppm reading, setpoint,
tolerance, safety max) with a plain-language banner on whether a CO2
sensor is mapped yet and a sealed-room-mode banner when applicable, a
4-tile grid for manual override of the exhaust/intake/circulation/CO2-valve
actuators, and a simple beam timeline (native
history-graph, same style as the Light view) showing when each device was actually on. Built per direct user request (“lets start with the next phase air exchange and co2”) ahead of Phase 5, with CO2 dosing built fully optional/dormant since the user has no CO2 sensor or valve hardware yet; the mode selectors and Intake fan were added in a v2 follow-up (“i miss the simple option to run the circulation fans permanently… same for the exhaust fan” plus the intake fan and sealed-room-scenario requests) - seedocs/docs/module-air.mdfor the full design, especially the CO2-to- exhaust safety interlock the Phase 0 plan itself calls out as a health-risk item, and the sealed-room walkthrough.
Energy view (Phase 8)
A seventh view with everything for packages/grow_energy.yaml: a status
banner (whether Total is sourced from the Power Master meter or calculated
from mapped devices, plus which groups are tracking, last decision), a
“Cycle Baseline” entities card (a manual “reset this cycle baseline”
button, last decision - the currency selector and price per kWh/liter
fields that originally lived in this card, added 2026-08-27, moved to
Dashboard 1’s “Energy: Master Config” section on 2026-08-29), an explainer
of the power -> kWh -> cost
pipeline and per-device sub-metering, a “Live Power Draw” tile row (Total /
Light / Climate, in W - individual per-device readings are deliberately
NOT shown here, only the group totals), a “Money Spent on This Grow”
section and a “Money Spent - Lifetime” section (both Jinja-templated
markdown showing kWh + cost per group with the selected currency’s symbol,
since a template sensor’s unit_of_measurement can’t itself be templated
by currency - see docs/docs/module-energy.md), a “Nutrient Solution Cost”
section and a “Total Grow Cost (Electricity + Nutrients)” section (both
added 2026-08-27, this-cycle and lifetime figures, depends on the
Irrigation module’s lifetime volume accumulator), a banner showing how many
of each group’s devices are currently mapped (n/8 Light, n/7 Climate),
and a simple power-draw beam/line timeline (native history-graph, same
no-HACS-dependency pattern as the Light/Air views) with a note that the 3
kWh sensors can optionally be added to Home Assistant’s own native Energy
dashboard. Built per direct user request (“lets continue with the next
phase, energy. Don’t forget to add an option to put the electricity price
in either USD, Pound or Euro…”) - the sub-metering itself was redesigned
the same day, before first deployment, from one sensor per group to one
OPTIONAL sensor per individual device (Dashboard 1’s new “Energy
Sub-Metering” cards), summed automatically into Light/Climate, per direct
follow-up: “i need the option to put the sensors in for every device
individually and then put them together into usage groups.” A nutrient-cost
tracker and combined “Total Grow Cost” were added 2026-08-27 per further
follow-up (“Make a cost tracker out of it… create an option to put a
price per l for the nutrient solution”). See docs/docs/module-energy.md
for the full design, including why “cost” is disclosed as a recomputed
estimate rather than a true price-over-time integral.
Alarms view (Phase 8, second half)
An eighth view with everything for packages/grow_alarms.yaml (module M7):
a status banner (all clear, or the list of currently active alarms - fault
watchdogs from Climate/Light/Air/Irrigation, or a Dashboard 1 mapping
issue), a “Notification Channels” mushroom-tile row (7 tiles: the master
“Notifications” switch - defaults on, unlike other modules’ master
switches, since this one never commands an actuator; one push toggle per
registered mobile device; the E-Mail enable toggle - since Phase 9’s
broader Growlink polish, see further down), a “Notification Settings”
entities card (the E-Mail notify-service text field, a “Send Test
Notification” button, and the automation-managed “Last Event” log), and an
explainer covering the two possible-duplicate push devices
found during setup and how to add your own SMTP integration for the E-Mail
channel. This module doesn’t detect any new faults itself - it consolidates
what every other module already raises into one Push+Persistent+E-Mail
alert (R9), on top of (not instead of) each module’s own notification. See
docs/docs/module-alarms.md for the full design and rollout checklist.
Cameras view (Phase 9, Module M13)
A ninth view for packages/grow_camera.yaml (Module M13, decision R19):
live-monitoring tiles for up to 4 cameras in the tent - pure monitoring, no
recording, no motion detection, no security-style overlays. A “View
Settings” entities card holds the layout switcher
(input_select.grow_camera_layout: 1/2/4 Cameras) and the focus picker
(input_select.grow_camera_focus, used only by the 1-Camera layout), then
one type: conditional Markdown card per layout option shows the matching
tiles - the 1-Camera layout shows the focused slot large plus the other 3
as small thumbnails, 2-Cameras always shows Slots 1 and 2 side by side,
4-Cameras shows all 4 slots in a 2x2 grid regardless of which are actually
enabled (an unconfigured/disabled slot renders its own grey placeholder
tile rather than being hidden, so you always know the slot exists and why
it’s not showing anything).
Why Markdown cards, not picture-glance/picture-entity. Which
camera a tile shows is picked dynamically at runtime (via the
input_text.grow_camera<N>_entity_id mapping on Dashboard 1) - but stock
Lovelace cards take a literal entity: in their YAML config, they cannot
template which entity to show. Markdown is the one stock card that
templates its content: with Jinja, so each tile is Jinja that resolves
the mapped camera, then embeds Home Assistant’s own signed camera-proxy
snapshot URL (entity_picture) with a cache-busting query parameter tied
to sensor.grow_camera_refresh_tick (a trigger-based sensor ticking every
5 seconds), so the browser actually re-fetches the image on a schedule.
Known MVP tradeoff, documented on purpose: a frequently refreshing
snapshot (every ~5s), not a continuous WebRTC-grade video feed, and
tapping a tile does not open Home Assistant’s native more-info/fullscreen
dialog the way a real picture-glance card would. Continuous streaming
and native tap interactions are listed as later expansion stages, not MVP.
Each tile’s status dot mirrors sensor.grow_camera<N>_status (green =
Online, grey = Not Configured/Disabled, red = Offline). Camera
connections (stream URL, credentials, connection testing) are never
configured on this view or anywhere else in GrowAssistant - only a
reference to an already-working camera.* entity, set up through Home
Assistant’s own native integrations (Generic Camera / ONVIF / MotionEye /
go2rtc), is mapped on Dashboard 1. See module-camera.md for the full
design, the camera-setup how-to, and the rollout checklist.
Growlink polish (Phase 9)
Dynamic gauge coloring (2026-08-28, card-mod)
The native gauge card only supports monotonic 3-zone severity coloring
(green -> yellow -> red in one direction) via its severity: option. VPD’s
healthy range - and Temperature’s and Humidity’s, once Phase 3’s day/night
setpoints exist - is in the middle of its scale (too low and too high are
both bad), which a monotonic band can’t express. Fixed via the card-mod
HACS frontend card: severity: was removed from all 3 gauges on this view
and replaced with a card_mod: style: block that templates the gauge’s
--gauge-color CSS custom property live, against whichever day/night
setpoint + tolerance is currently active for that parameter (respects
input_boolean.grow_climate_is_daytime automatically) - green within
tolerance, yellow within 2x tolerance, red beyond that, grey if the source
sensor is unavailable. This is a genuine improvement over the old static
thresholds, not just a cosmetic reskin: the color now reflects the actual
currently-configured regulation target instead of a fixed number that could
drift out of sync with the setpoints. All 3 templates were dry-run tested
against mocked states (in-range/warning/error/unavailable, both day and
night) before shipping.
Requires the card-mod HACS frontend card in addition to
apexcharts-card (already required above): HACS -> Frontend -> Explore &
Add Repositories -> search “card-mod” -> Install -> add the resource if HACS
doesn’t do it automatically -> reload the dashboard. Without it, these 3
gauge cards still render and still work, they just show as plain gauges
with no dynamic coloring (the card_mod: key is silently ignored by
Lovelace if the custom element isn’t registered - it does not break the
card).
Device-tile redesign (2026-08-28, mushroom)
All 35 device/power tile cards across the Devices view, the Irrigation
pump tiles, the Light “Light Devices” grid, the Air “Air Devices” grid, and
the Energy view’s “Live Power Draw” grid were converted to
custom:mushroom-template-card. The point isn’t cosmetic - it fixes a real
ambiguity the original UX audit flagged (see CHANGELOG [0.17.0]) more
completely than the text-only clarification could: an unmapped/optional
slot now gets its own distinct color (grey, “Not mapped”) instead of
sharing the same greyed-out “unavailable” look every native tile card
uses regardless of why it’s unavailable, which visually crowded together
“not installed yet” with “something’s wrong.” 🟢 green = on, blue-grey =
off, grey = not mapped - never red, since none of these three states is a
fault. The 3 sensor-based Energy tiles (Total/Light/Climate power) follow
the same color language (amber = actively drawing power, blue-grey = zero,
grey = not mapped) and show the live value + unit as their secondary line,
same information as the old tile cards just styled consistently with the
rest.
Requires the mushroom HACS frontend card: HACS -> Frontend -> Explore
& Add Repositories -> search “mushroom” -> Install -> reload. Unlike
card-mod above, these cards do not degrade gracefully without it -
custom:mushroom-template-card is itself the card type, so a missing
install shows “Custom element doesn’t exist” on all 35 of these tiles
until it’s installed, not a fallback to plain tiles.
Deliberately not done in this pass: a broader mushroom conversion of
every other card on Dashboard 2 (the dense config/setpoint/calibration
entities cards, the Master Control toggle rows) - mushroom’s per-row chip
style doesn’t add much for dense numeric config forms, and doing it
everywhere risked a much larger, less-verified change than this bounded
device-tile slice. Scoped explicitly with the user before starting.
Superseded by the Master Control & fault redesign below - the user asked
for the broader pass next.
Master Control & fault redesign (2026-08-28, mushroom)
A third mushroom slice, done immediately after the device-tile redesign
above per direct user request (“eine breitere mushroom politur zuerst” -
a broader mushroom polish first). Converts every remaining on/off toggle
row that has a clean, unambiguous good/bad or on/off meaning, across the
Climate, Irrigation, Light, Air, and Alarms views: 32 rows total, extracted
out of their old entities: cards into new standalone “Master Control”
mushroom-tile grids (plus the Light/Air “Slots” rows, which get their own
tile grids rather than a “Master Control” label since they aren’t
control-enable toggles).
Two distinct color/interaction patterns are used, depending on what the toggle actually means:
- Enable switches (Auto Control, Follow Light, Under-Canopy, VWC Lock, CO2 Dosing, the notification channels, the light/under-canopy slot toggles): green = on, blue-grey = off, grey = unavailable; secondary line shows the capitalized state (“On” / “Off”); tappable to toggle, hold for more-info. On = good here, so green-on is correct.
- Fault/problem booleans (Paused, Failsafe, the four Air/Light fault flags, CO2 Ceiling exceeded): red = on, green = off, grey = unavailable; secondary line shows a short status word (“Active” / “Clear” / “Tripped” / “Exceeded”). These are automation-managed status flags, not user controls, so they’re not toggleable - tapping only opens more-info. On = bad here, so the color polarity is deliberately inverted from the enable-switch pattern (e.g. “Failsafe Tripped”: on is red, not green - verified by dry-run testing every affected entity’s polarity individually before shipping, since a copy-paste mistake here would have silently flipped a safety-relevant color).
Each new grid got a ”### Master Control” markdown header so it doesn’t float without context, and the two module entities cards left holding only a single automation-managed text field afterward (Light, Air) were retitled from “Master Control” to “Status Log” so the label still matches their contents.
Deliberately still excluded, and expected to stay that way: read-only
counters/sensors (Events Run Today), input_select dropdowns (Regulation
Mode, Currency), informational-but-not-clean-good/bad states (Daytime
Active, Currently Locked, P1 Window Active - these don’t map to a clear
green/red meaning), dense numeric config (setpoints, thresholds,
calibration, prices), text fields, buttons/scripts, and the Cycle
Configuration card (Grow Cycle ID + cycle-start dates) - left as plain
entities rows on purpose, per the earlier UX-audit fix’s intent to guard
that card against accidental taps; it is not getting mushroom-ified.
All 67 mushroom-template-cards on this dashboard (35 from the device-tile
slice + 32 from this slice) were re-verified together: parsed via
yaml.safe_load, every icon_color/secondary/primary/icon template
rendered against mocked on/off/unavailable/numeric states with a plain
Jinja environment, and the red/green polarity of each fault-vs-enable
entity spot-checked individually. Zero template errors.
Collapsible explainer notes (2026-08-28, expander-card)
A fourth Growlink-Politur slice, requested directly by the user (“können
wir die infos auf allen dashboards als dropdown textfelder machen, sodass
man diese nur sieht wenn man sie öffnet”) - collapse every static “how
this works” / “what this means” explainer note on all three dashboards
into a click-to-expand card, so a view shows only its live tiles/status/
controls by default. Scoped via AskUserQuestion up front on two questions:
which HACS card to use (a custom:expander-card accordion vs. a plain
native <details>/<summary> tag inside the existing markdown cards -
user chose the HACS card), and which text actually qualifies as
collapsible “info” (explainer notes only, vs. also collapsing live status/
warning banners - user chose explainer notes only, banners stay visible).
What moved and what didn’t. Every markdown card whose text reads the
same regardless of current entity state - mode explanations (“How
Regulation Mode works”), “not a fault” tile-color clarifications, safety-
limit rationale (the Cycle Configuration warning), one-time setup
instructions (Schedules), chart/history pointers, module overviews (how
the Alarms module works) - is now wrapped in a custom:expander-card,
expanded: false by default, with a short ℹ️-prefixed title as the
always-visible clickable header. Anything whose content is actually
live - is_state()/states() driven banners like the Setup Status card,
the “Automatic irrigation is OFF” / failsafe-tripped / VWC-lock-active
banner, every module’s on/off + fault-flag status line, the Energy cost
figures, the Alarms all-clear/active-alarms banner - was left exactly as
a plain, always-visible markdown card. 26 cards on Dashboard 2, plus 2
each on Dashboard 1 and Dashboard 3 (30 total) were converted.
Splitting hybrid cards. Several existing cards mixed static
explanation and live conditionals in one Jinja block - e.g. the Climate
view’s “Regulation Mode decides…” explainer, immediately followed by
{% if daytime_follows_light %}/{% if control off %}/{% if paused %}
banners in the same content: string. These couldn’t be wrapped whole
without hiding a live warning behind a click, so each was split in two:
the static sentence moved into its own expander, the live conditionals
stayed as a separate, always-visible markdown card immediately below (or
in the same position as before). This happened on the Climate & VPD view
(Regulation Mode explainer vs. sync/off/paused banners), the Air & CO2
view’s Intake Fan card (mirrors-Exhaust explanation vs. mapped/unmapped
status), and its CO2 card (dosing safety-interlock rules vs. sensor-
mapped-status/sealed-room-mode banners).
Section headers stayed untouched. Short structural markdown cards
that are just a ### Section Name heading with no body text (e.g. ”###
Master Control”, ”### Exhaust Fan”, ”#### Top Light Slots”) are not
“info” and were left as plain, always-visible markdown - collapsing a
section’s own title behind a click would hide the section itself, not an
explanation of it. Where a header previously had explainer prose folded
into the same markdown block (”### On/Off Cycle per Light Group” plus a
paragraph explaining it), the header line was kept as its own small
always-visible markdown card and only the paragraph moved into the new
expander below it.
Requires the expander-card HACS frontend card
(custom:expander-card, MelleD/lovelace-expander-card - available
directly from HACS’s default store, no custom-repository step needed:
HACS -> Frontend -> Explore & Add Repositories -> search “expander card”
-> Install -> reload). Like mushroom, this does not degrade
gracefully if missing: custom:expander-card is the card type itself, so
every collapsed note shows “Custom element doesn’t exist” instead of its
ℹ️ title until installed - no entity, control, or live banner is
affected, only these notes become temporarily unreachable.
All 30 new expander-card blocks were re-validated after every edit with
yaml.safe_load, and every markdown card’s Jinja content (97 across all
three dashboards - the pre-existing count plus these) was parsed with a
plain Jinja Environment to confirm no template syntax broke during the
splits. One mistake was caught and fixed during this pass: an early edit
to the Energy view’s cost-explainer card used a truncated copy of the
original paragraph (an artifact of a diagnostic script’s own 600-character
print limit, not the file’s actual content) as the text to replace,
which silently matched a partial-word substring and left the tail of the
original sentence dangling at the wrong indentation - caught immediately
by the next yaml.safe_load validation pass (a scanner error, not a
silent corruption) and fixed by re-reading the card’s full, real content
before re-editing.
Overview redesign: Environment Status + Cycle Configuration moved (2026-08-28)
A fifth Growlink-Politur slice, requested directly: the user wanted the Overview to actually work as a single-pane-of-glass view of the whole environment, and wanted the Cycle Configuration fields moved to the Configuration dashboard (Dashboard 1) instead of duplicated on the Overview. Scoped via AskUserQuestion on two points before touching any YAML: how to handle the Cycle Configuration move (user chose the smaller option - Dashboard 1’s existing “Grow Tracker” card already has every one of these fields, so the fix is removing the duplicate from the Overview, not restructuring Dashboard 1), and how much detail the new cross-dashboard status section should show (user chose compact text status lines per module, reusing each module’s already-live state, over either a minimal Alarms-only rollup or a full row of mushroom-style tiles).
Cycle Configuration duplication removed. The Overview’s “⚠️ Cycle
Configuration (rarely changed)” expander and its editable entities card
(Grow Cycle ID, all 4 cycle-start dates, Harvest Completed) were deleted
outright - Dashboard 1’s “Grow Tracker” card already has every one of
these fields (see dashboard-1-configuration.md), so this was a pure
duplicate, not a second place doing something new. The Overview keeps
only the read-only “Grow Tracker” card (Current Phase, Day in Phase,
Flower Day, Expected Harvest Date) - genuinely “the infos regarding the
cycle” rather than the ability to edit it. Editing the cycle now happens
in exactly one place.
New “Environment Status” section. Replaces the old single Setup+ Climate status line with a small, always-visible group of cards: a ”### Environment Status” header, the Alarms module’s own all-clear/ active-alarms banner (shown first, since it already aggregates every other module’s faults), then one consolidated card with a line per module (Setup, Climate, Irrigation, Light, Air, Energy). Each line reads the same entities each module’s own view already reads for its own status banner - not a second, parallel source of truth - condensed to a short glance-friendly phrase instead of that view’s fuller instructional wording (e.g. Irrigation’s own view says “Automatic irrigation is OFF. Enable it below once your schedules and safety limits are configured.”; the Overview just says ”⚪ off”). Devices doesn’t get a line - it’s a manual-override control page, not a monitored module with its own on/off/fault state.
All new Jinja templates were dry-run tested across representative
scenarios (everything off/clear, an active alarm, and every module on
with every fault flag simultaneously tripped) with a plain Jinja
Environment and mocked states()/is_state()/state_attr()/
has_value() - 0 template errors in any scenario, and the full-dashboard
regression check (all markdown content: blocks across all three
dashboard files parsed for Jinja syntax errors) stayed clean.
Icon-button sizing + readability fix, all mushroom-template-card tiles (2026-08-28)
Requested directly: “make the button icons on the irrigation page only
50px height and some of the icon buttons like the ones under air & Co2
master control are not readable, as most of the word cuts off.” Two
separate fixes, both via card_mod: blocks added directly to individual
custom:mushroom-template-card cards (no change to the cards’ own
primary/secondary/icon config) - mushroom-template-card renders
on top of Home Assistant’s native Tile-card internals
(<ha-card><div class="content"><ha-tile-icon>…<ha-tile-info>), and
ha-tile-info is itself a separate custom element with its own shadow
root holding the .primary/.secondary label text - reaching it needs
card_mod’s shadow-piercing key$: syntax, not a plain style: string.
Irrigation & Substrate view - compact 50px tiles. All 5
mushroom-template-card tiles on this view (the 3-card Master Control
grid: Auto Control/Failsafe/VWC Lock, and the 2-card Irrigation Pump 1/2
grid) got:
card_mod: style: .: | ha-card { height: 50px !important; min-height: 50px !important; } .content { padding: 4px 8px !important; gap: 6px !important; } ha-tile-icon$: | ha-state-icon { --mdc-icon-size: 20px; } ha-tile-info$: | .primary { font-size: 12px !important; line-height: 1.1; white-space: nowrap !important; } .secondary { font-size: 10px !important; line-height: 1.1; }Forcing ha-card to 50px overrides the card’s own default flex sizing
(normally height: 100% driven by its content, with 10px padding and a
~40px icon) without shrinking anything inside it automatically, so the
padding, icon size, and both text sizes were all reduced to fit legibly
in the smaller footprint; text stays single-line (white-space: nowrap,
same as the tile’s own default) rather than wrapping, since wrapping to
two lines would need more height than 50px allows. Only this view’s
tiles were touched - no other page’s tiles were shortened, since only
this page was named.
Text-cutoff fix - all 4-column mushroom-template-card grids. The
named example (Air & CO2’s 7-card Master Control grid: Auto Control/CO2
Dosing/CO2 Ceiling/Exhaust Fault/Circ. Fault/Intake Fault/CO2 Fault) sits
in a columns: 4 grid, the narrowest tile width used anywhere on this
dashboard - ha-tile-info’s own default CSS is
white-space: nowrap; overflow: hidden; text-overflow: ellipsis, so any
primary label too long for that width gets silently clipped rather
than wrapped or shrunk. Since every other columns: 4 grid on the
dashboard has the same narrow-tile risk and several have equally long or
longer labels, the fix was applied to all of them, not just the reported
one: Light’s 4-card Master Control grid (Auto Control/Under-Canopy/Top
Fault/UC Fault), Air’s own 4-card device-tile grid (Exhaust/Intake/
Circulation/CO2 Valve), and the Alarms view’s 7-card notification-target
grid (Notifications/iPad/iPhone 2 (older?)/iPhone 2 (active)/iPhone
(Elena)/iPhone 15 Pro (Elena)/E-Mail) - the last of these has by far the
longest labels on the whole dashboard (up to 21 characters) and was the
worst-affected even though it wasn’t the one named. The 3-column and
2-column grids elsewhere (Climate & VPD, Devices, Irrigation) were left
untouched - they weren’t reported and have noticeably more width per
tile already. Each of these 22 cards got:
card_mod: style: ha-tile-info$: | .primary { white-space: normal !important; overflow: visible !important; text-overflow: clip !important; }This lets .primary wrap onto a second line instead of truncating with
an ellipsis; it’s a pure improvement for short labels too (e.g. “iPad”,
“CO2 Valve”) since they already fit on one line and simply keep doing
so - nothing about their layout changes. These tiles are not
height-constrained the way Irrigation’s are, so the grid row is free to
grow taller to fit a two-line label instead of clipping it.
Both fixes together touch 27 mushroom-template-card cards (5 height +
22 text-wrap) via targeted line-position insertion (not a full YAML
re-parse/re-dump, to avoid disturbing any existing comments or
formatting), each insertion’s target line re-confirmed with an exact
grep before writing. Validated the same way as every prior slice:
yaml.safe_load after the edit, plus the full-file Jinja regression
check (0 syntax errors, unaffected by this change since no content:
blocks were touched) and mkdocs build --strict for the docs. Not yet
visually confirmed on the live instance - re-verify the 50px Irrigation
tiles are actually legible in practice (not just non-clipped) and that
the wrapped two-line labels on Light/Air/Alarms look acceptable, once
re-imported.
Follow-up correction: the actual “huge” Irrigation buttons were native button cards, not mushroom tiles (2026-08-28)
The previous slice’s 50px fix targeted every custom:mushroom-template-card
tile on the Irrigation view (Master Control’s Auto Control/Failsafe/VWC
Lock, and the Pump 1/2 grid) - but the user reported the “irrigation
action buttons” were still huge and attached a screenshot. The screenshot
showed a large octagon-with-exclamation icon over the text “Clear
Failsafe” - not any of the tiles fixed in the previous slice at all.
Checking the dashboard’s own YAML confirmed why: “Apply Preset”,
“Clear Failsafe”, and “Run Now” (Manual Run) were never
mushroom-template-cards - they were plain native Lovelace type: button cards, left over from before the mushroom redesign reached this
view, and native button cards render with a large default icon and
name underneath by design. The previous fix genuinely never touched
them, since it only edited existing mushroom-template-card blocks.
Fix: converted all 3 to custom:mushroom-template-card, bound to
each action’s own script.* entity (scripts have a real on/off state
while running, so this is more than a cosmetic swap) and given the same
50px card_mod treatment as every other Irrigation tile:
- Apply Preset (
script.grow_irrigation_apply_crop_steering_preset)- icon
blue-greyidle /orangewhile running, secondary text “Tap to apply” / “Running…”.
- icon
- Clear Failsafe (
script.grow_irrigation_reset_failsafe) - icon turns red with secondary “Tripped - tap to clear” wheneverinput_boolean.grow_irrigation_failsafe_trippedis actually on (the same boolean the rest of the dashboard already watches),orangewhile the clear script itself is running,blue-grey/“No failsafe active” otherwise - a real status cue added on top of the original buttons’s static look, not just a size fix. - Run Now (
script.grow_irrigation_manual_run) - same idle/running pattern as Apply Preset.
All three kept their original tap_action: call-service exactly as
before (calling the same script), and gained hold_action: more-info
for consistency with every other tile on the page. Dry-run tested the 6
new template fields (icon_color/secondary x 3 cards) across 4 scenarios
(idle, script running, failsafe tripped, failsafe tripped + running) -
all rendered correctly. yaml.safe_load and the full-file Jinja
regression check both stayed clean; no type: button cards remain
anywhere in the dashboard file. Not yet visually confirmed on the live
instance - this is a genuine root-cause fix (wrong card type, not a
missed style), but still worth confirming these three buttons are
actually compact now, and that the originally-fixed Master Control tiles
(Auto Control/Failsafe/VWC Lock) are separately confirmed OK too, since
the screenshot only showed the “Clear Failsafe” button.
Overview follow-up: combined chart, Light power/timeline, batch name, Cycle ID reset+save (2026-08-28)
Requested in the same message as the button-sizing screenshot: “i also
want to add more features to the overview like the climate & irrigation
diagramm with the option to switch between 1 hour, 6 hour, 12h, 24h, 3d,
7d. i also want to see the currently running light power and the light
on off diagramm. the grow tracker also misses the name of the current
running batch and the the batch counter has no reset or save feature on
the configuration page.” Scoped via AskUserQuestion before writing any
YAML - one combined chart chosen over two separate ones; the user
explicitly chose to skip adding a 12h range option anywhere rather
than add it to one selector only; Light power chosen as a per-group
breakdown (Top Light and Under-Canopy shown separately) rather than one
combined total; and “batch counter” was clarified by the user, on a
follow-up question, to mean the existing Grow Cycle ID field, not a new
counter entity - there is no separate counter anywhere in this project. A
second follow-up question on what “Save” should concretely do (Home
Assistant’s input_text already auto-commits on edit) came back “no
preference,” so the recommended option was used.
New “Climate & Irrigation” section. A condensed combination of the
existing Climate & VPD chart (Temperature/Humidity/VPD) and Irrigation
chart (VWC/EC) into one apexcharts-card, with its own new range selector,
input_select.grow_overview_chart_range (packages/grow_dashboard.yaml)
- same 1h/6h/24h/3d/7d options as every other range selector in this
project, deliberately not 12h, per the user’s own call to skip that
option rather than add it to just one place. Kept fully independent from
grow_chart_range(Climate & VPD) andgrow_irrigation_chart_range(Irrigation) - changing the range here never changes what those tabs show, matching this project’s existing precedent of one selector per view rather than a shared one. Built the same way as every other range-switchable chart in this project: 5 fixed-graph_spanapexcharts-cardinstances behindtype: conditionalcards (apexcharts’ own templatedgraph_spanisn’t reliably supported across versions, so this project has never relied on it). Squeezing 5 series onto one chart without it turning into visual noise needed one design decision: Humidity and VWC share one 0-100% axis (both are already percentage scales, so this isn’t a stretch), VPD keeps its own 0-3 axis on the right (as on the Climate & VPD view), and Temperature (~10-35) and EC (~0-5 mS/cm) still plot as lines but without a visible axis of their own - the same “hidden axis” technique the Climate & VPD chart already uses for Temperature/Humidity. Pump-activity overlay (present on the dedicated Irrigation chart) was left out here on purpose - the Overview’s chart is meant as an at-a-glance summary, not a full replacement for the per-domain views, and a note in a collapsed “ℹ️ About this chart” expander says so directly, pointing back to the Climate & VPD and Irrigation & Substrate tabs for full detail.
New “Light” section. Two live power tiles
(sensor.grow_light_top_power_w, sensor.grow_light_undercanopy_power_w
- the same per-group power sensors from the wattage-%/PPFD estimator
feature,
packages/grow_light.yaml) side by side, per the user’s chosen per-group breakdown, plus ahistory-graph“Light On/Off Timeline” card identical to the one already on the Light view (binary_sensor. grow_light_top_active/binary_sensor.grow_light_undercanopy_active,hours_to_show: 24) - no new entities needed, both already existed.
Batch name on the Grow Tracker card. The Overview’s Grow Tracker card
now leads with “Batch / Cycle Name”, but shows sensor. grow_tracker_cycle_name (a new trivial read-only mirror sensor,
packages/grow_tracker.yaml) rather than the real input_text. grow_tracker_cycle_id entity directly - the earlier Overview redesign
deliberately consolidated all cycle-field editing onto Dashboard 1 only,
and showing the raw input_text here would have quietly reopened a
second editable copy of it. The mirror sensor just returns “Not set”
when the field is empty, otherwise echoes the value verbatim.
Cycle ID Reset/Save (Dashboard 1 only, not this file). See
dashboard-1-configuration.md and module-grow-tracker.md for the full
writeup - two new scripts
(script.grow_tracker_save_cycle_id/script.grow_tracker_reset_cycle_id
in packages/grow_tracker.yaml) back two plain native button cards
placed directly under Dashboard 1’s Grow Tracker entities card.
Deliberately not mushroom-template-card - Dashboard 1 has stayed
free of the mushroom/card_mod HACS dependency throughout this
project, and these are low-frequency configuration actions with no
meaningful “running” state worth templating, unlike the Irrigation page’s
frequently-tapped action buttons.
Process notes. No new HACS dependency for any of this - the combined
chart reuses apexcharts-card, already required since Phase 2. Package
changes this time (packages/grow_dashboard.yaml’s new input_select,
packages/grow_tracker.yaml’s new template sensor and two scripts) mean
this slice needs an actual package redeploy and Home Assistant restart
(or the equivalent Developer Tools -> YAML reload for input_select,
Template Entities, and Scripts), not just a dashboard re-import - the
first Overview-related slice all session that wasn’t dashboard-YAML-only.
Validated the two new script message templates and the mirror sensor
across empty/set/unavailable scenarios with a plain Jinja Environment
and mocked states() - all rendered correctly; yaml.safe_load clean on
all 3 dashboard files and both touched packages; the full-dashboard
regression check (all markdown and mushroom-template-card template
fields across all 3 dashboard files) stayed at 0 syntax errors; mkdocs build --strict re-run clean. Not yet visually confirmed on the live
instance - none of this has been seen rendered for real yet.