From 4b4d9921e9de6b830c1e62746946ef49d5055c94 Mon Sep 17 00:00:00 2001 From: astyrrian1 Date: Sat, 2 May 2026 23:53:53 -0500 Subject: [PATCH] fix: make mission control dashboard generic --- CHANGELOG.md | 9 + README.md | 11 +- dashboards/mission-control.yaml | 970 ++++++++++++++++---------------- 3 files changed, 506 insertions(+), 484 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4dc8b7..a7bb5d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to the HAPSIC Controller are documented here. Versions follow [Semantic Versioning](https://semver.org/). +## [Unreleased] + +### Fixed +- **Mission Control dashboard load failure**: Wrapped `dashboards/mission-control.yaml` as a full Lovelace dashboard config with `views:` so it can be pasted directly into Home Assistant's raw configuration editor as documented. +- **Panel view card count**: Moved the History graph into the main vertical stack so the panel view has exactly one card, matching current Home Assistant panel view requirements. +- **Boiler curve rendering**: Added a safe JSON fallback for `input_text.hapsic_boiler_curve` so an empty or invalid helper value cannot break the markdown card. +- **Structure Velocity chart**: Kept the dashboard on the intended stable `sensor.hapsic_structure_velocity` MQTT contract; the missing entity must be provided by the Home Assistant `hapsic_sensors.yaml` package. +- **Open-source dashboard privacy**: Removed site-specific text and external deployment entities from `dashboards/mission-control.yaml`; the public dashboard now uses only the generic HAPSIC entity contract. + ## [v2.6.1] — 2026-05-02 ### Fixed diff --git a/README.md b/README.md index 0e46022..235339c 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ HAPSIC solves this with math. ## Dashboard -HAPSIC ships with a **Mission Control** dashboard for monitoring the physics engine, duct safety, and moisture balance in real time. +HAPSIC ships with a generic **Mission Control** dashboard for monitoring the physics engine, duct safety, and moisture balance in real time. It uses only HAPSIC contract entities and intentionally excludes site-specific sensors, locations, rooms, vendors, and personal Home Assistant helpers. **Prerequisites** (install via HACS → Frontend): - [Mushroom Cards](https://github.com/piitaya/lovelace-mushroom) @@ -39,6 +39,15 @@ HAPSIC ships with a **Mission Control** dashboard for monitoring the physics eng 3. Paste the contents of [`dashboards/mission-control.yaml`](dashboards/mission-control.yaml) 4. Save +Personal production dashboards should live in your own Home Assistant config repository. Keep local-only entities, room names, vendor hardware, and location-specific context out of this open-source dashboard. + +**Dashboard entity contract:** +- State and faults: `sensor.hapsic_fsm_state`, `sensor.hapsic_fault_reason`, `sensor.hapsic_boil_status` +- User inputs/storage: `input_number.target_dew_point`, `input_number.humidifier_max_capacity`, `input_number.hapsic_chi_ema`, `input_text.hapsic_boiler_curve` +- Physics and control: `sensor.hapsic_steam_voltage`, `sensor.hapsic_steam_mass`, `sensor.hapsic_ventilation_loss`, `sensor.hapsic_net_flux`, `sensor.hapsic_structure_velocity`, `sensor.hapsic_room_deficit`, `sensor.hapsic_target_duct_dp`, `sensor.hapsic_max_achievable_dp`, `sensor.hapsic_is_target_infeasible` +- Psychrometrics and duct safety: `sensor.hapsic_room_dew_point`, `sensor.hapsic_room_average_temp`, `sensor.hapsic_room_average_rh`, `sensor.hapsic_pre_steam_dp`, `sensor.hapsic_duct_dp`, `sensor.hapsic_cleansed_supply_temp`, `sensor.hapsic_cleansed_supply_rh`, `sensor.hapsic_cleansed_post_steam_temp`, `sensor.hapsic_cleansed_post_steam_rh`, `sensor.hapsic_supply_flow`, `sensor.hapsic_cleansed_airflow` +- Health: `sensor.hapsic_chi_instant`, `sensor.hapsic_health_measured_steam`, `sensor.hapsic_health_production_efficiency` + ## Notification Blueprints HAPSIC includes three Blueprint automations for proactive system monitoring. Each can be imported with one click: diff --git a/dashboards/mission-control.yaml b/dashboards/mission-control.yaml index 2dd524c..0c4e9a7 100644 --- a/dashboards/mission-control.yaml +++ b/dashboards/mission-control.yaml @@ -1,504 +1,508 @@ -type: panel -path: humidifier2 -title: Humidifier2 -cards: - - type: vertical-stack +title: HAPSIC Mission Control +views: + - type: panel + path: humidifier2 + title: Humidifier2 cards: - - type: custom:mushroom-title-card - title: HAPSIC Mission Control - subtitle: >- - Amarillo, TX • {{ states('sensor.hapsic_fsm_state') | upper }} • {{ - states('sensor.gw1200b_absolute_pressure') }} kPa - - type: conditional - conditions: - - condition: state - entity: sensor.hapsic_fsm_state - state: FAULT - card: - type: vertical-stack - cards: - - type: tile - entity: sensor.hapsic_fault_reason - name: FAULT ACTIVE - icon: mdi:alert-octagon - color: red - - type: markdown - content: | - ### 🛑 Logic Lockout Active - The controller has entered safety shutdown. - **Reason:** {{ states('sensor.hapsic_fault_reason') }} - - type: conditional - conditions: - - condition: state - entity: sensor.hapsic_fsm_state - state: FAULT - - condition: state - entity: sensor.hapsic_fault_reason - state: Economizer Bypass Active - card: - type: tile - entity: sensor.zehnder_comfoair_q_a4cb9c_bypass_state - name: FREE COOLING ACTIVE (YIELDING) - icon: mdi:snowflake-thermometer - color: cyan - - type: horizontal-stack + - type: vertical-stack cards: - - type: tile - entity: input_number.target_dew_point - name: Target Dew Point - icon: mdi:thermometer-water - color: deep-purple - - type: tile - entity: sensor.hapsic_steam_voltage - name: Output V - icon: mdi:flash-auto - color: >- - {% if states('sensor.hapsic_steam_voltage')|float > 0 %} orange {% - else %} grey {% endif %} - - type: tile - entity: input_number.humidifier_max_capacity - name: Capacity - icon: mdi:kettle-steam - color: cyan - - type: grid - columns: 2 - square: false - cards: - - type: gauge - entity: sensor.hapsic_steam_mass - name: Injection Rate - unit: lbs/hr - min: 0 - max: 6 - needle: true - severity: - green: 0 - yellow: 4 - red: 5.5 - - type: vertical-stack + - type: custom:mushroom-title-card + title: HAPSIC Mission Control + subtitle: >- + {{ states('sensor.hapsic_fsm_state') | upper }} • Target {{ + states('input_number.target_dew_point') }} °F DP • {{ + states('sensor.hapsic_fault_reason') }} + - type: conditional + conditions: + - condition: state + entity: sensor.hapsic_fsm_state + state: FAULT + card: + type: vertical-stack + cards: + - type: tile + entity: sensor.hapsic_fault_reason + name: FAULT ACTIVE + icon: mdi:alert-octagon + color: red + - type: markdown + content: | + ### 🛑 Logic Lockout Active + The controller has entered safety shutdown. + **Reason:** {{ states('sensor.hapsic_fault_reason') }} + - type: conditional + conditions: + - condition: state + entity: sensor.hapsic_fsm_state + state: FAULT + - condition: state + entity: sensor.hapsic_fault_reason + state: Economizer Bypass Active + card: + type: markdown + content: > + ### Economizer Bypass Active + + HAPSIC is yielding because the controller reported an economizer + bypass fault state. + - type: horizontal-stack + cards: + - type: tile + entity: input_number.target_dew_point + name: Target Dew Point + icon: mdi:thermometer-water + color: deep-purple + - type: tile + entity: sensor.hapsic_steam_voltage + name: Output V + icon: mdi:flash-auto + color: >- + {% if states('sensor.hapsic_steam_voltage')|float(0) > 0 %} orange {% + else %} grey {% endif %} + - type: tile + entity: input_number.humidifier_max_capacity + name: Capacity + icon: mdi:kettle-steam + color: cyan + - type: grid + columns: 2 + square: false cards: - type: gauge - entity: sensor.hapsic_chi_instant - name: Canister Health - unit: "%" + entity: sensor.hapsic_steam_mass + name: Injection Rate + unit: lbs/hr min: 0 - max: 120 + max: 6 needle: true severity: - red: 50 - yellow: 70 - green: 90 - - type: markdown - content: > -
Boiler State: {{ - states('sensor.hapsic_boil_status') }}
- - type: heading - heading: Boiler Health & Characterization - heading_style: title - - type: grid - columns: 4 - square: false - cards: - - type: tile - entity: sensor.hapsic_steam_mass - name: Commanded Steam - icon: mdi:gauge-empty - color: >- - {% set val = states('sensor.hapsic_steam_mass')|float(0) %} - {% if val > 0 %} blue {% else %} grey {% endif %} - state_content: state - - type: tile - entity: sensor.hapsic_health_measured_steam - name: Actual Steam - icon: mdi:gauge-full - color: >- - {% set val = states('sensor.hapsic_health_measured_steam')|float(0) %} - {% if val > 0 %} green {% else %} grey {% endif %} - state_content: state - - type: tile - entity: sensor.hapsic_health_production_efficiency - name: Efficiency - icon: mdi:percent-circle - color: >- - {% set val = states('sensor.hapsic_health_production_efficiency')|float(0) %} - {% if val > 90 %} green {% elif val > 60 %} orange - {% elif val > 0 %} red {% else %} grey {% endif %} - state_content: state - - type: tile - entity: sensor.hapsic_boil_status - name: Boiler State - icon: >- - {% if states('sensor.hapsic_boil_status') == 'BOILING' %} - mdi:fire {% else %} mdi:snowflake {% endif %} - color: >- - {% if states('sensor.hapsic_boil_status') == 'BOILING' %} - red {% else %} grey {% endif %} - - type: custom:apexcharts-card - header: - show: true - title: "Steam Output \u2014 Commanded vs Actual (lbs/hr)" - show_states: true - colorize_states: true - graph_span: 12h - series: - - entity: sensor.hapsic_steam_mass - name: Commanded - stroke_width: 2 - color: "#42a5f5" - curve: stepline - show: - in_header: true - - entity: sensor.hapsic_health_measured_steam - name: Actual - stroke_width: 2 - color: "#66bb6a" - curve: smooth - show: - in_header: true - - entity: input_number.humidifier_max_capacity - name: Effective Max - stroke_width: 1 - color: "#ef5350" - opacity: 0.4 - curve: stepline - show: - in_header: false - yaxis: - - min: 0 - decimals: 2 - - type: custom:apexcharts-card - header: - show: true - title: Production Efficiency (%) - show_states: true - colorize_states: true - graph_span: 12h - experimental: - color_threshold: true - series: - - entity: sensor.hapsic_health_production_efficiency - name: Efficiency - stroke_width: 2 - curve: smooth - show: - in_header: true - color_threshold: - - value: 0 - color: "#f44336" - - value: 60 - color: "#ff9800" - - value: 90 - color: "#4caf50" - yaxis: - - min: 0 - max: 120 - decimals: 0 - - type: markdown - title: Boiler Curve (Learned) - content: > - {% set curve = states('input_text.hapsic_boiler_curve') %} + green: 0 + yellow: 4 + red: 5.5 + - type: vertical-stack + cards: + - type: gauge + entity: sensor.hapsic_chi_instant + name: Canister Health + unit: "%" + min: 0 + max: 120 + needle: true + severity: + red: 50 + yellow: 70 + green: 90 + - type: markdown + content: > +
Boiler State: {{ + states('sensor.hapsic_boil_status') }}
+ - type: heading + heading: Boiler Health & Characterization + heading_style: title + - type: grid + columns: 4 + square: false + cards: + - type: tile + entity: sensor.hapsic_steam_mass + name: Commanded Steam + icon: mdi:gauge-empty + color: >- + {% set val = states('sensor.hapsic_steam_mass')|float(0) %} + {% if val > 0 %} blue {% else %} grey {% endif %} + state_content: state + - type: tile + entity: sensor.hapsic_health_measured_steam + name: Actual Steam + icon: mdi:gauge-full + color: >- + {% set val = states('sensor.hapsic_health_measured_steam')|float(0) %} + {% if val > 0 %} green {% else %} grey {% endif %} + state_content: state + - type: tile + entity: sensor.hapsic_health_production_efficiency + name: Efficiency + icon: mdi:percent-circle + color: >- + {% set val = states('sensor.hapsic_health_production_efficiency')|float(0) %} + {% if val > 90 %} green {% elif val > 60 %} orange + {% elif val > 0 %} red {% else %} grey {% endif %} + state_content: state + - type: tile + entity: sensor.hapsic_boil_status + name: Boiler State + icon: >- + {% if states('sensor.hapsic_boil_status') == 'BOILING' %} + mdi:fire {% else %} mdi:snowflake {% endif %} + color: >- + {% if states('sensor.hapsic_boil_status') == 'BOILING' %} + red {% else %} grey {% endif %} + - type: custom:apexcharts-card + header: + show: true + title: "Steam Output \u2014 Commanded vs Actual (lbs/hr)" + show_states: true + colorize_states: true + graph_span: 12h + series: + - entity: sensor.hapsic_steam_mass + name: Commanded + stroke_width: 2 + color: "#42a5f5" + curve: stepline + show: + in_header: true + - entity: sensor.hapsic_health_measured_steam + name: Actual + stroke_width: 2 + color: "#66bb6a" + curve: smooth + show: + in_header: true + - entity: input_number.humidifier_max_capacity + name: Effective Max + stroke_width: 1 + color: "#ef5350" + opacity: 0.4 + curve: stepline + show: + in_header: false + yaxis: + - min: 0 + decimals: 2 + - type: custom:apexcharts-card + header: + show: true + title: Production Efficiency (%) + show_states: true + colorize_states: true + graph_span: 12h + experimental: + color_threshold: true + series: + - entity: sensor.hapsic_health_production_efficiency + name: Efficiency + stroke_width: 2 + curve: smooth + show: + in_header: true + color_threshold: + - value: 0 + color: "#f44336" + - value: 60 + color: "#ff9800" + - value: 90 + color: "#4caf50" + yaxis: + - min: 0 + max: 120 + decimals: 0 + - type: markdown + title: Boiler Curve (Learned) + content: > + {% set curve = states('input_text.hapsic_boiler_curve') %} - {% set bins = curve | from_json if curve not in ['unknown','unavailable'] else [0,0,0,0] %} + {% set bins = curve | from_json([0,0,0,0]) %} - | Voltage Band | 0-2.5V | 2.5-5V | 5-7.5V | 7.5-10V | + | Voltage Band | 0-2.5V | 2.5-5V | 5-7.5V | 7.5-10V | - | :---: | :---: | :---: | :---: | :---: | + | :---: | :---: | :---: | :---: | :---: | - | **Capacity** | {{ '%.2f'|format(bins[0]) }} | {{ '%.2f'|format(bins[1]) }} | {{ '%.2f'|format(bins[2]) }} | {{ '%.2f'|format(bins[3]) }} | + | **Capacity** | {{ '%.2f'|format(bins[0]) }} | {{ '%.2f'|format(bins[1]) }} | {{ '%.2f'|format(bins[2]) }} | {{ '%.2f'|format(bins[3]) }} | - | **Bar** | {{ '█' * ((bins[0]*10)|int) }} | {{ '█' * ((bins[1]*10)|int) }} | {{ '█' * ((bins[2]*10)|int) }} | {{ '█' * ((bins[3]*10)|int) }} | - - type: custom:apexcharts-card - header: - show: true - title: "Canister Health (\u03C7 Ratio)" - show_states: true - colorize_states: true - graph_span: 12h - experimental: - color_threshold: true - series: - - entity: sensor.hapsic_chi_instant - name: "\u03C7 Instant" - stroke_width: 1 - opacity: 0.6 - show: - in_header: true - color_threshold: - - value: 0 - color: "#f44336" - - value: 70 - color: "#ff9800" - - value: 90 - color: "#4caf50" - - entity: input_number.hapsic_chi_ema - name: "\u03C7 EMA (48h)" - stroke_width: 2 - color: "#9b59b6" - curve: smooth - show: - in_header: true - yaxis: - - min: 0 - max: 120 - decimals: 0 - - type: heading - heading: Physics Engine (Decoupled) - heading_style: title - - type: entities - title: State Vector - show_header_toggle: false - entities: - - entity: sensor.hapsic_room_dew_point - name: Actual Dew Point (Goal Metric) - icon: mdi:water-thermometer - - entity: sensor.hapsic_room_average_temp - name: Actual Temp - - entity: sensor.hapsic_room_average_rh - name: Actual RH - - entity: sensor.hapsic_cleansed_supply_temp - name: Supply Temp (T_sup) - - entity: sensor.hapsic_cleansed_supply_rh - name: Supply RH (Baseline) - - entity: sensor.hapsic_supply_flow - name: Airflow Mass (m3/h) - icon: mdi:fan - - type: heading - heading: Duct Safety Monitor - heading_style: title - - type: grid - columns: 2 - square: false - cards: + | **Bar** | {{ '█' * ((bins[0]*10)|int) }} | {{ '█' * ((bins[1]*10)|int) }} | {{ '█' * ((bins[2]*10)|int) }} | {{ '█' * ((bins[3]*10)|int) }} | + - type: custom:apexcharts-card + header: + show: true + title: "Canister Health (\u03C7 Ratio)" + show_states: true + colorize_states: true + graph_span: 12h + experimental: + color_threshold: true + series: + - entity: sensor.hapsic_chi_instant + name: "\u03C7 Instant" + stroke_width: 1 + opacity: 0.6 + show: + in_header: true + color_threshold: + - value: 0 + color: "#f44336" + - value: 70 + color: "#ff9800" + - value: 90 + color: "#4caf50" + - entity: input_number.hapsic_chi_ema + name: "\u03C7 EMA (48h)" + stroke_width: 2 + color: "#9b59b6" + curve: smooth + show: + in_header: true + yaxis: + - min: 0 + max: 120 + decimals: 0 + - type: heading + heading: Physics Engine (Decoupled) + heading_style: title - type: entities - title: Pre-Steam (Supply) + title: State Vector show_header_toggle: false entities: + - entity: sensor.hapsic_room_dew_point + name: Actual Dew Point (Goal Metric) + icon: mdi:water-thermometer + - entity: sensor.hapsic_room_average_temp + name: Actual Temp + - entity: sensor.hapsic_room_average_rh + name: Actual RH - entity: sensor.hapsic_cleansed_supply_temp - name: Temp - icon: mdi:thermometer-chevron-down + name: Supply Temp (T_sup) - entity: sensor.hapsic_cleansed_supply_rh - name: Humidity - icon: mdi:water-minus - - type: entities - title: Post-Steam (Duct) - show_header_toggle: false - entities: - - entity: sensor.hapsic_duct_temp - name: Temp - icon: mdi:thermometer-chevron-up - - entity: sensor.hapsic_duct_rh - name: Humidity - icon: mdi:water-plus - card_mod: - style: | - :host { - --paper-item-icon-color: - {% if states(config.entity)|float(0) > 85 %} red - {% elif states(config.entity)|float(0) > 80 %} orange - {% else %} green {% endif %}; - } - - type: gauge - entity: sensor.hapsic_duct_rh - name: Duct Saturation Safety - unit: "%" - min: 0 - max: 100 - needle: true - severity: - green: 0 - yellow: 80 - red: 90 - - type: heading - heading: Moisture Balance Engine - heading_style: title - - type: custom:apexcharts-card - header: - show: true - title: 1. ENGINE EFFORT - show_states: true - colorize_states: true - experimental: - color_threshold: true - series: - - entity: sensor.hapsic_steam_voltage - name: Steam Output - stroke_width: 2 - show: - in_header: true - color_threshold: - - value: 0 - color: "#4caf50" - - value: 9.5 - color: "#f44336" - yaxis: - - min: 0 - max: 10 - decimals: 1 - graph_span: 2h - - type: custom:apexcharts-card - header: - show: true - title: 2. WORK DONE (Lift) - show_states: true - colorize_states: true - graph_span: 2h - series: - - entity: sensor.hapsic_target_duct_dp - name: PID Request - color: "#9b59b6" - stroke_width: 2 - curve: stepline - - entity: sensor.hapsic_duct_dp - name: Actual Discharge - color: "#ff9800" - type: area - opacity: 0.5 - stroke_width: 2 - - entity: sensor.hapsic_pre_steam_dp - name: Baseline Intake - color: "#2196f3" - stroke_width: 2 - now: - show: true - label: Current - - type: custom:apexcharts-card - header: - show: true - title: 3. STRUCTURE VELOCITY - show_states: true - colorize_states: true - graph_span: 2h - experimental: - color_threshold: true - series: - - entity: sensor.hapsic_structure_velocity - name: Climb Rate - type: area - opacity: 0.3 - stroke_width: 2 - show: - in_header: true - color_threshold: - - value: -10 - color: "#9e9e9e" - - value: 0 - color: "#9c27b0" - yaxis: - - min: -1 - max: 1 - decimals: 2 - - type: markdown - title: Mass Balance Tracker - content: > - | Metric | Value | Impact | + name: Supply RH (Baseline) + - entity: sensor.hapsic_supply_flow + name: Airflow Mass (m3/h) + icon: mdi:fan + - type: heading + heading: Duct Safety Monitor + heading_style: title + - type: grid + columns: 2 + square: false + cards: + - type: entities + title: Pre-Steam (Supply) + show_header_toggle: false + entities: + - entity: sensor.hapsic_cleansed_supply_temp + name: Temp + icon: mdi:thermometer-chevron-down + - entity: sensor.hapsic_cleansed_supply_rh + name: Humidity + icon: mdi:water-minus + - type: entities + title: Post-Steam (Duct) + show_header_toggle: false + entities: + - entity: sensor.hapsic_cleansed_post_steam_temp + name: Temp + icon: mdi:thermometer-chevron-up + - entity: sensor.hapsic_cleansed_post_steam_rh + name: Humidity + icon: mdi:water-plus + card_mod: + style: | + :host { + --paper-item-icon-color: + {% if states(config.entity)|float(0) > 85 %} red + {% elif states(config.entity)|float(0) > 80 %} orange + {% else %} green {% endif %}; + } + - type: gauge + entity: sensor.hapsic_cleansed_post_steam_rh + name: Duct Saturation Safety + unit: "%" + min: 0 + max: 100 + needle: true + severity: + green: 0 + yellow: 80 + red: 90 + - type: heading + heading: Moisture Balance Engine + heading_style: title + - type: custom:apexcharts-card + header: + show: true + title: 1. ENGINE EFFORT + show_states: true + colorize_states: true + experimental: + color_threshold: true + series: + - entity: sensor.hapsic_steam_voltage + name: Steam Output + stroke_width: 2 + show: + in_header: true + color_threshold: + - value: 0 + color: "#4caf50" + - value: 9.5 + color: "#f44336" + yaxis: + - min: 0 + max: 10 + decimals: 1 + graph_span: 2h + - type: custom:apexcharts-card + header: + show: true + title: 2. WORK DONE (Lift) + show_states: true + colorize_states: true + graph_span: 2h + series: + - entity: sensor.hapsic_target_duct_dp + name: PID Request + color: "#9b59b6" + stroke_width: 2 + curve: stepline + - entity: sensor.hapsic_duct_dp + name: Actual Discharge + color: "#ff9800" + type: area + opacity: 0.5 + stroke_width: 2 + - entity: sensor.hapsic_pre_steam_dp + name: Baseline Intake + color: "#2196f3" + stroke_width: 2 + now: + show: true + label: Current + - type: custom:apexcharts-card + header: + show: true + title: 3. STRUCTURE VELOCITY + show_states: true + colorize_states: true + graph_span: 2h + experimental: + color_threshold: true + series: + - entity: sensor.hapsic_structure_velocity + name: Climb Rate + type: area + opacity: 0.3 + stroke_width: 2 + show: + in_header: true + color_threshold: + - value: -10 + color: "#9e9e9e" + - value: 0 + color: "#9c27b0" + yaxis: + - min: -1 + max: 1 + decimals: 2 + - type: markdown + title: Mass Balance Tracker + content: > + | Metric | Value | Impact | - | :--- | :--- | :--- | + | :--- | :--- | :--- | - | **Injection** | `{{ states('sensor.hapsic_steam_mass') }} lbs/hr` | - Wetting ⬆️ | + | **Injection** | `{{ states('sensor.hapsic_steam_mass') }} lbs/hr` | + Wetting ⬆️ | - | **Ventilation** | `{{ states('sensor.hapsic_ventilation_loss') }} - lbs/hr` | Drying ⬇️ | + | **Ventilation** | `{{ states('sensor.hapsic_ventilation_loss') }} + lbs/hr` | Drying ⬇️ | - | **NET FLUX** | **{{ states('sensor.hapsic_net_flux') }} lbs/hr** | - **{{ 'CHARGING' if states('sensor.hapsic_net_flux')|float(0) > 0 else - 'DRAINING' }}** | - - type: custom:power-flow-card-plus - title: HAPSIC Physics Engine - entities: - solar: - entity: sensor.hapsic_steam_mass - name: Steam Input - color: "#3498db" - unit_of_measurement: lbs/hr - battery: - name: Net Flux - entity: - consumption: sensor.hapsic_net_flux - production: sensor.hapsic_net_flux - color_icon: true - color_circle: true - unit_of_measurement: lbs/hr - label_consumption: Draining - label_production: Charging - home: - name: Vent Loss - entity: sensor.hapsic_ventilation_loss - color_icon: true - unit_of_measurement: lbs/hr - dashboard_link: /energy - display_zero_lines: true - use_new_flow_rate_model: true - min_flow_rate: 0.1 - decimals: 2 - watt_threshold: 10000 - - type: heading - heading: Control Strategy (Loop A) - heading_style: title - - type: grid - columns: 3 - square: false - cards: - - type: tile - entity: sensor.hapsic_room_deficit - name: Deficit - icon: mdi:arrow-collapse-down - color: >- - {% set val = states('sensor.hapsic_room_deficit')|float(0) %} {% - if val < -0.5 %} blue {% elif val < 0.5 %} green {% elif val < - 2.0 %} orange {% else %} red {% endif %} - state_content: state - - type: tile - entity: sensor.hapsic_target_duct_dp - name: Duct Request - icon: mdi:target - color: deep-purple - state_content: state - - type: tile - entity: sensor.hapsic_max_achievable_dp - name: Feasibility Limit - icon: mdi:speedometer - color: >- - {% if states('sensor.hapsic_is_target_infeasible') == 'True' %} - red {% else %} green {% endif %} - state_content: state - - type: custom:apexcharts-card - header: - show: true - title: Target vs. Actual Dew Point - show_states: true - colorize_states: true - graph_span: 6h - series: - - entity: sensor.hapsic_room_dew_point - name: Actual Dew Point - color: "#2196f3" - stroke_width: 2 - curve: smooth - - entity: input_number.target_dew_point - name: Target Dew Point - color: "#9b59b6" - stroke_width: 2 - curve: stepline - - entity: sensor.hapsic_max_achievable_dp - name: Physical Limit - color: "#f44336" - stroke_width: 2 - type: area - opacity: 0.1 - - title: History - type: history-graph - hours_to_show: 12 - entities: - - sensor.hapsic_pre_steam_dp - - sensor.hapsic_cleansed_airflow - - input_number.hapsic_chi_ema - - sensor.hapsic_duct_dp - - sensor.hapsic_target_duct_dp - - sensor.hapsic_max_achievable_dp - - sensor.hapsic_chi_instant - - sensor.hapsic_room_dew_point - - input_number.target_dew_point - - sensor.hapsic_steam_voltage + | **NET FLUX** | **{{ states('sensor.hapsic_net_flux') }} lbs/hr** | + **{{ 'CHARGING' if states('sensor.hapsic_net_flux')|float(0) > 0 else + 'DRAINING' }}** | + - type: custom:power-flow-card-plus + title: HAPSIC Physics Engine + entities: + solar: + entity: sensor.hapsic_steam_mass + name: Steam Input + color: "#3498db" + unit_of_measurement: lbs/hr + battery: + name: Net Flux + entity: + consumption: sensor.hapsic_net_flux + production: sensor.hapsic_net_flux + color_icon: true + color_circle: true + unit_of_measurement: lbs/hr + label_consumption: Draining + label_production: Charging + home: + name: Vent Loss + entity: sensor.hapsic_ventilation_loss + color_icon: true + unit_of_measurement: lbs/hr + dashboard_link: /energy + display_zero_lines: true + use_new_flow_rate_model: true + min_flow_rate: 0.1 + decimals: 2 + watt_threshold: 10000 + - type: heading + heading: Control Strategy (Loop A) + heading_style: title + - type: grid + columns: 3 + square: false + cards: + - type: tile + entity: sensor.hapsic_room_deficit + name: Deficit + icon: mdi:arrow-collapse-down + color: >- + {% set val = states('sensor.hapsic_room_deficit')|float(0) %} {% + if val < -0.5 %} blue {% elif val < 0.5 %} green {% elif val < + 2.0 %} orange {% else %} red {% endif %} + state_content: state + - type: tile + entity: sensor.hapsic_target_duct_dp + name: Duct Request + icon: mdi:target + color: deep-purple + state_content: state + - type: tile + entity: sensor.hapsic_max_achievable_dp + name: Feasibility Limit + icon: mdi:speedometer + color: >- + {% if states('sensor.hapsic_is_target_infeasible') == 'True' %} + red {% else %} green {% endif %} + state_content: state + - type: custom:apexcharts-card + header: + show: true + title: Target vs. Actual Dew Point + show_states: true + colorize_states: true + graph_span: 6h + series: + - entity: sensor.hapsic_room_dew_point + name: Actual Dew Point + color: "#2196f3" + stroke_width: 2 + curve: smooth + - entity: input_number.target_dew_point + name: Target Dew Point + color: "#9b59b6" + stroke_width: 2 + curve: stepline + - entity: sensor.hapsic_max_achievable_dp + name: Physical Limit + color: "#f44336" + stroke_width: 2 + type: area + opacity: 0.1 + - title: History + type: history-graph + hours_to_show: 12 + entities: + - sensor.hapsic_pre_steam_dp + - sensor.hapsic_cleansed_airflow + - input_number.hapsic_chi_ema + - sensor.hapsic_duct_dp + - sensor.hapsic_target_duct_dp + - sensor.hapsic_max_achievable_dp + - sensor.hapsic_chi_instant + - sensor.hapsic_room_dew_point + - input_number.target_dew_point + - sensor.hapsic_steam_voltage