From d5cbc160cff95059587185cf601a1ced0ab73b77 Mon Sep 17 00:00:00 2001 From: Eric Buruschkin Date: Fri, 21 Aug 2026 07:48:40 -0400 Subject: [PATCH] Add a reference dashboard and document it in the README docs/dashboard.yaml is a hand-built starting point for a two-body site: per-body views with heat, pumps, features and lights, chemistry gauges, and an equipment view for pool-device telemetry. Built-in cards only, so it needs no HACS front-end dependencies. The file documents which entity IDs are fixed across installs and which are derived from the controller's own control names, since the latter have to be swapped per site. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 14 ++ docs/dashboard.yaml | 496 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 510 insertions(+) create mode 100644 docs/dashboard.yaml diff --git a/README.md b/README.md index 1f7a2fc..12423f7 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,20 @@ Options (Settings → Devices & Services → Poolside → Configure): - **Expose pool devices** — create read-only telemetry sensors for the physical equipment (pumps, heaters, actuators, ...) the controller operates. +## Dashboard + +Home Assistant builds a dashboard automatically from the devices the +integration creates, which is enough to control everything. For a hand-built +starting point, [`docs/dashboard.yaml`](docs/dashboard.yaml) is a reference +dashboard covering a two-body site: per-body views with heat, pumps, features +and lights, chemistry gauges, and an equipment view for pool-device telemetry. + +Paste it into **Settings → Dashboards → Add dashboard → New dashboard from +scratch**, then **⋮ → Raw configuration editor**. It uses built-in cards only, +so no HACS front-end dependencies are needed. The entity IDs in it are +examples — the file documents which ones are fixed and which are derived from +your controller's own control names. + ## Relationship to Home Assistant Core This integration has been submitted for inclusion in Home Assistant Core. diff --git a/docs/dashboard.yaml b/docs/dashboard.yaml new file mode 100644 index 0000000..77b464c --- /dev/null +++ b/docs/dashboard.yaml @@ -0,0 +1,496 @@ +# Poolside for Home Assistant — reference dashboard +# +# Settings → Dashboards → Add dashboard → New dashboard from scratch, +# then ⋮ → Raw configuration editor → paste this in place of the default. +# +# Built-in cards and features only — no HACS front-end dependencies. +# Verified against Home Assistant 2026.8 and Attendant 2.7. +# +# =========================================================================== +# ENTITY IDS TO SWAP +# +# Poolside entities are named ` `, and the entity_id is that +# pair slugified. The device is the body of water ("Pool", "Spa", "Sauna", +# "Cold Plunge", ...), so IDs come out like `sensor.pool_temperature`. +# +# Fixed — same on every install, only the body-of-water prefix changes: +# sensor.pool_temperature water temperature +# sensor.pool_water_state Filtering / Heating / Cooling / Off ... +# sensor.pool_ph ┐ +# sensor.pool_orp │ chemistry: each of these exists +# sensor.pool_free_chlorine │ ONLY if that probe is installed +# sensor.pool_total_chlorine │ and reporting. Delete the rest. +# sensor.pool_salt_level ┘ +# +# Derived from your controller's control names, so these WILL differ: +# climate.pool_temp TEMPERATURE control (commonly "Temp") +# select.pool_temp_heating_mode Fuel / Heat pump / Solar / Smart +# select.pool_temp_cooling_mode Chiller / Heat pump / Smart +# fan.pool_filter variable-speed pump or feature +# switch.spa_blower single-speed control +# light.pool_pool_light light; colors + shows = effect list +# +# Site-level, named after the site, not a body of water: +# sensor.my_site_controller_mode normal / installer / fault / factory +# +# To dump your own list: Developer tools → Template, and render +# {{ integration_entities('poolside') | join('\n') }} +# +# =========================================================================== + +views: + # ========================================================================= + - title: Pool + path: pool + icon: mdi:pool + type: sections + max_columns: 3 + sections: + # ---------------------------------------------------------------- status + - type: grid + cards: + - type: heading + heading: Pool + heading_style: title + icon: mdi:pool + badges: + - type: entity + entity: sensor.pool_water_state + - type: entity + entity: sensor.pool_temperature + + # Every control goes unavailable while the controller is out of + # NORMAL mode, and the mode can only be changed on the controller + # itself. Saying so beats a dashboard of greyed-out tiles. + - type: conditional + conditions: + - condition: state + entity: sensor.my_site_controller_mode + state_not: normal + card: + type: markdown + content: >- + ### ⚠️ Controller is in + {{ states('sensor.my_site_controller_mode') }} mode + + Poolside controls stay unavailable until it is returned to + Normal mode on the controller itself. + + - type: tile + entity: sensor.pool_temperature + name: Water + icon: mdi:pool-thermometer + features_position: bottom + features: + - type: trend-graph + hours_to_show: 24 + + - type: tile + entity: sensor.pool_water_state + name: State + + # ------------------------------------------------------------------ heat + - type: grid + cards: + - type: heading + heading: Heat + icon: mdi:fire + + # `hvac_modes` is deliberately left unset: a body of water offers + # only what its installed equipment supports (a chiller-only site + # reports ['off', 'cool']), and the feature shows exactly those. + - type: thermostat + entity: climate.pool_temp + features: + - type: climate-hvac-modes + + # Which heat/cool source satisfies the setpoint. Each select only + # exists if the body of water has that equipment — delete the one + # your site doesn't report. + - type: tile + entity: select.pool_temp_heating_mode + name: Heat source + features_position: bottom + features: + - type: select-options + + - type: tile + entity: select.pool_temp_cooling_mode + name: Cool source + features_position: bottom + features: + - type: select-options + + # --------------------------------------------------- pumps and features + - type: grid + cards: + - type: heading + heading: Pumps & features + icon: mdi:pump + + # Variable-speed controls are fans. The slider snaps to the exact + # percentages the hardware accepts (percentage_step), so it may + # move in coarser jumps than a normal fan. + - type: tile + entity: fan.pool_filter + name: Filter + features_position: bottom + features: + - type: fan-speed + + - type: tile + entity: fan.pool_spa_cleaner + name: Cleaner + features_position: bottom + features: + - type: fan-speed + + # Single-speed controls, and blowers, are plain switches. + - type: tile + entity: switch.pool_spa_landscape_mister + name: Landscape mister + + # ---------------------------------------------------------------- lights + - type: grid + cards: + - type: heading + heading: Lights + icon: mdi:lightbulb-on-outline + + # There is no RGB here: colors and multi-color shows are both + # opaque named values, exposed together as the light's effect list. + # + # Home Assistant has no tile feature for effects, so the buttons + # below set them directly. Pick names from YOUR light's + # effect_list (Developer tools → States) — the catalog comes from + # the hardware and differs per fixture. Full list is always + # available by tapping the tile for the more-info dialog. + # + # Poolside lights report SupportsBrightness; the ones on this + # site are on/off only (supported_color_modes: ['onoff']), so no + # brightness slider is shown. If yours is dimmable, add: + # - type: light-brightness + - type: tile + entity: light.pool_pool_light + name: Pool light + icon: mdi:track-light + + - type: grid + columns: 3 + square: false + cards: + - type: button + name: Royal Blue + icon: mdi:palette + show_state: false + tap_action: + action: perform-action + perform_action: light.turn_on + target: + entity_id: light.pool_pool_light + data: + effect: Royal Blue + - type: button + name: Emerald + icon: mdi:palette + show_state: false + tap_action: + action: perform-action + perform_action: light.turn_on + target: + entity_id: light.pool_pool_light + data: + effect: Emerald + - type: button + name: Mardi Gras + icon: mdi:party-popper + show_state: false + tap_action: + action: perform-action + perform_action: light.turn_on + target: + entity_id: light.pool_pool_light + data: + effect: Mardi Gras + + # ------------------------------------------------------------- chemistry + # Chemistry probes are optional equipment: each sensor is created only + # once the controller actually reports that field. Delete any your + # site doesn't have — most sites have some subset of these. + - type: grid + column_span: 2 + cards: + - type: heading + heading: Chemistry + icon: mdi:beaker-outline + + # Probes report full precision, so pH renders as e.g. 7.572999. The + # gauge card has no rounding option — set it on the entity instead: + # Settings → Devices & services → Entities → the sensor → cog → + # Display precision. 2 decimals suits pH, 0 suits ORP and salt. + + - type: gauge + entity: sensor.pool_ph + name: pH + min: 6.8 + max: 8.2 + needle: true + segments: + - from: 6.8 + color: "#db4437" + - from: 7.2 + color: "#43a047" + - from: 7.8 + color: "#db4437" + + - type: gauge + entity: sensor.pool_orp + name: ORP + min: 400 + max: 900 + needle: true + segments: + - from: 400 + color: "#db4437" + - from: 650 + color: "#43a047" + - from: 800 + color: "#f4b400" + + - type: gauge + entity: sensor.pool_total_chlorine + name: Total chlorine + min: 0 + max: 6 + needle: true + segments: + - from: 0 + color: "#db4437" + - from: 1 + color: "#43a047" + - from: 3 + color: "#f4b400" + + - type: gauge + entity: sensor.pool_salt_level + name: Salt + min: 2000 + max: 5000 + needle: true + segments: + - from: 2000 + color: "#db4437" + - from: 2700 + color: "#43a047" + - from: 4000 + color: "#f4b400" + + # ----------------------------------------------------------------- trend + - type: grid + column_span: 2 + cards: + - type: heading + heading: Last 24 hours + icon: mdi:chart-line + + - type: history-graph + hours_to_show: 24 + entities: + - entity: sensor.pool_temperature + name: Water + - entity: sensor.pool_water_state + name: State + - entity: fan.pool_filter + name: Filter + + # ========================================================================= + # One view per body of water scales better than one crowded overview — + # a site can expose Pool, Spa, Sauna, Cold Plunge and more. + - title: Spa + path: spa + icon: mdi:hot-tub + type: sections + max_columns: 3 + sections: + - type: grid + cards: + - type: heading + heading: Spa + heading_style: title + icon: mdi:hot-tub + badges: + - type: entity + entity: sensor.spa_water_state + - type: entity + entity: sensor.spa_temperature + + # Reads `unknown` rather than a stale number while the body of + # water isn't circulating — there is no probe value to report. + - type: tile + entity: sensor.spa_temperature + name: Water + icon: mdi:pool-thermometer + + - type: tile + entity: sensor.spa_water_state + name: State + + - type: grid + cards: + - type: heading + heading: Heat + icon: mdi:fire + + - type: thermostat + entity: climate.spa_temp + features: + - type: climate-hvac-modes + + - type: tile + entity: select.spa_temp_heating_mode + name: Heat source + features_position: bottom + features: + - type: select-options + + - type: grid + cards: + - type: heading + heading: Features + icon: mdi:fountain + + - type: tile + entity: fan.spa_spa_jet + name: Jets + features_position: bottom + features: + - type: fan-speed + + - type: tile + entity: switch.spa_blower + name: Blower + + - type: tile + entity: light.spa_spa_light + name: Spa light + icon: mdi:track-light + + # ========================================================================= + # Physical equipment telemetry. These entities exist only while + # "Expose pool devices" is enabled (Settings → Devices & services → + # Poolside → Configure). + # + # Which fields appear is entirely up to what each piece of equipment + # reports — a variable-speed pump publishes power/RPM/status, a relay-driven + # device may publish nothing but its power state. Treat this view as a + # pattern to copy, not a list to expect. + - title: Equipment + path: equipment + icon: mdi:cog-outline + type: sections + max_columns: 3 + sections: + - type: grid + cards: + - type: heading + heading: Controller + heading_style: title + icon: mdi:cog-outline + + - type: tile + entity: sensor.my_site_controller_mode + name: Mode + + - type: grid + cards: + - type: heading + heading: Pump + icon: mdi:pump + + - type: tile + entity: sensor.pump_power_state + name: Power state + - type: tile + entity: sensor.pump_power + name: Power draw + features_position: bottom + features: + - type: trend-graph + hours_to_show: 24 + - type: tile + entity: sensor.pump_rpm + name: Speed + - type: tile + entity: sensor.pump_status + name: Status + + - type: grid + cards: + - type: heading + heading: Heat equipment + icon: mdi:fire + + - type: tile + entity: sensor.heater_power_state + name: Heater + - type: tile + entity: sensor.chiller_power_state + name: Chiller + # A heater that has just shut down circulates water to dissipate + # residual heat; this is when it will be free to fire again. The + # sensor is null while no cooldown is running, so the tile is + # conditional rather than permanently reading "Unknown". + - type: conditional + conditions: + - condition: state + entity: sensor.pump_heater_cooldown_until + state_not: unknown + - condition: state + entity: sensor.pump_heater_cooldown_until + state_not: unavailable + card: + type: tile + entity: sensor.pump_heater_cooldown_until + name: Heater cooldown until + + - type: grid + cards: + - type: heading + heading: Valves + icon: mdi:valve + + # Idle / Moving / Waiting / Calibrating / Error / Failed / + # Offline / Overload — the icon tracks the state. + - type: tile + entity: sensor.pool_spa_suction_actuator_state + name: Pool/spa suction + - type: tile + entity: sensor.pool_spa_suction_actuator_position + name: Position + - type: tile + entity: sensor.chiller_return_valve_state + name: Chiller return + + # Diagnostic entities are hidden from auto-generated dashboards but can + # be placed explicitly. `disabled reason` is the one to reach for when a + # control is unavailable and you want to know why: Winterized, + # Freeze protection, or Pool cover closed. + - type: grid + column_span: 2 + cards: + - type: heading + heading: Why is a control unavailable? + icon: mdi:help-circle-outline + + - type: entities + entities: + - entity: sensor.pool_temp_disabled_reason + name: Pool heat + - entity: sensor.pool_filter_disabled_reason + name: Pool filter + - entity: sensor.pool_pool_light_disabled_reason + name: Pool light + - entity: sensor.spa_temp_disabled_reason + name: Spa heat + - entity: sensor.spa_blower_disabled_reason + name: Spa blower