From c00d9b66c226029136d5e30822921613812ae7f2 Mon Sep 17 00:00:00 2001 From: Jannis Christiani Date: Sat, 11 Apr 2026 20:49:26 +0200 Subject: [PATCH] Add Lovelace dashboard for BMS monitoring Full-featured dashboard with mushroom overview cards, bar-card cell voltage display with colour thresholds, ApexCharts history graphs for voltage/current/SoC/power, balance quality indicator, and controls/protection panel. Co-Authored-By: Claude Sonnet 4.6 --- dashboard/bms-dashboard.yaml | 377 +++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) create mode 100644 dashboard/bms-dashboard.yaml diff --git a/dashboard/bms-dashboard.yaml b/dashboard/bms-dashboard.yaml new file mode 100644 index 0000000..6d3ef6b --- /dev/null +++ b/dashboard/bms-dashboard.yaml @@ -0,0 +1,377 @@ +# ───────────────────────────────────────────────────────────────────────────── +# Xiaoxiang Smart BMS — Lovelace Dashboard +# ───────────────────────────────────────────────────────────────────────────── +# +# REQUIRED HACS CARDS (install via HACS → Frontend): +# • Mushroom Cards https://github.com/piitaya/lovelace-mushroom +# • ApexCharts Card https://github.com/RomRider/apexcharts-card +# • Bar Card https://github.com/custom-cards/bar-card +# +# SETUP: +# 1. Go to Settings → Devices → your BMS device → any entity +# 2. Note the entity ID prefix (e.g. "lifepo4_48v" from "sensor.lifepo4_48v_voltage") +# 3. Find-and-replace YOUR_BMS with that prefix everywhere below +# 4. Adjust cell count: remove unused cell_voltage_N lines at the bottom +# 5. Adjust min/max in bar-card to match your chemistry: +# LiFePO4: min 2.8 max 3.7 +# Li-ion: min 2.5 max 4.25 +# +# HOW TO ADD: +# Dashboards → Add Dashboard → (name it) → three-dot menu → Edit → Raw config editor +# Paste this entire file (or just the `cards:` block into an existing view). +# ───────────────────────────────────────────────────────────────────────────── + +views: + - title: Battery + path: battery + icon: mdi:battery-charging + cards: + + # ── Status chips ─────────────────────────────────────────────────────── + - type: custom:mushroom-chips-card + chips: + - type: entity + entity: sensor.YOUR_BMS_state_of_charge + icon: mdi:battery + content_info: state + - type: entity + entity: binary_sensor.YOUR_BMS_mos_charge_enabled + icon: mdi:battery-arrow-up + content_info: none + - type: entity + entity: binary_sensor.YOUR_BMS_mos_discharge_enabled + icon: mdi:battery-arrow-down + content_info: none + - type: entity + entity: binary_sensor.YOUR_BMS_balance_active + icon: mdi:approximately-equal + content_info: none + # Red warning chip — only visible when any protection fires + - type: conditional + conditions: + - condition: or + conditions: + - condition: state + entity: binary_sensor.YOUR_BMS_prot_cell_overvolt + state: "on" + - condition: state + entity: binary_sensor.YOUR_BMS_prot_cell_undervolt + state: "on" + - condition: state + entity: binary_sensor.YOUR_BMS_prot_charge_overcurrent + state: "on" + - condition: state + entity: binary_sensor.YOUR_BMS_prot_discharge_overcurrent + state: "on" + - condition: state + entity: binary_sensor.YOUR_BMS_prot_short_circuit + state: "on" + - condition: state + entity: binary_sensor.YOUR_BMS_prot_software_lock + state: "on" + chip: + type: template + content: Protection triggered + icon: mdi:shield-alert + icon_color: red + + # ── Primary metrics ──────────────────────────────────────────────────── + - type: grid + columns: 3 + square: false + cards: + + # State of Charge — dynamic icon + colour + - type: custom:mushroom-template-card + primary: "{{ states('sensor.YOUR_BMS_state_of_charge') }} %" + secondary: State of Charge + entity: sensor.YOUR_BMS_state_of_charge + icon: > + {% set s = states('sensor.YOUR_BMS_state_of_charge') | int(0) %} + {% if s >= 90 %} mdi:battery + {% elif s >= 80 %} mdi:battery-90 + {% elif s >= 70 %} mdi:battery-80 + {% elif s >= 60 %} mdi:battery-70 + {% elif s >= 50 %} mdi:battery-60 + {% elif s >= 40 %} mdi:battery-50 + {% elif s >= 30 %} mdi:battery-40 + {% elif s >= 20 %} mdi:battery-30 + {% elif s >= 10 %} mdi:battery-20 + {% else %} mdi:battery-10 {% endif %} + icon_color: > + {% set s = states('sensor.YOUR_BMS_state_of_charge') | int(0) %} + {% if s >= 50 %} green + {% elif s >= 20 %} orange + {% else %} red {% endif %} + fill_container: true + tap_action: + action: more-info + + # Pack voltage + - type: custom:mushroom-template-card + primary: "{{ states('sensor.YOUR_BMS_voltage') }} V" + secondary: Pack Voltage + entity: sensor.YOUR_BMS_voltage + icon: mdi:lightning-bolt-circle + icon_color: blue + fill_container: true + tap_action: + action: more-info + + # Current — shows charge/discharge direction + - type: custom:mushroom-template-card + primary: > + {% set a = states('sensor.YOUR_BMS_current') | float(0) %} + {% if a > 0 %}+{% endif %}{{ a }} A + secondary: > + {% set a = states('sensor.YOUR_BMS_current') | float(0) %} + {% if a > 0.05 %} Charging + {% elif a < -0.05 %} Discharging + {% else %} Idle {% endif %} + entity: sensor.YOUR_BMS_current + icon: > + {% set a = states('sensor.YOUR_BMS_current') | float(0) %} + {% if a > 0.05 %} mdi:battery-charging-outline + {% elif a < -0.05 %} mdi:battery-minus-outline + {% else %} mdi:battery-check-outline {% endif %} + icon_color: > + {% set a = states('sensor.YOUR_BMS_current') | float(0) %} + {% if a > 0.05 %} green + {% elif a < -0.05 %} orange + {% else %} grey {% endif %} + fill_container: true + tap_action: + action: more-info + + # ── Secondary metrics ────────────────────────────────────────────────── + - type: grid + columns: 4 + square: false + cards: + - type: custom:mushroom-entity-card + entity: sensor.YOUR_BMS_power + icon: mdi:flash + name: Power + fill_container: true + - type: custom:mushroom-entity-card + entity: sensor.YOUR_BMS_energy_stored + icon: mdi:battery-charging-outline + name: Stored + fill_container: true + - type: custom:mushroom-entity-card + entity: sensor.YOUR_BMS_temperature_1 + icon: mdi:thermometer + name: Temp + fill_container: true + - type: custom:mushroom-entity-card + entity: sensor.YOUR_BMS_cycle_count + icon: mdi:counter + name: Cycles + fill_container: true + + # ── Cell voltages (bar chart) ────────────────────────────────────────── + # Colour zones for LiFePO4 — adjust min/max for your chemistry + - type: custom:bar-card + title: Cell Voltages + columns: 2 + height: 30px + positions: + icon: outside + indicator: outside + name: outside + value: outside + min: 2.8 + max: 3.7 + severity: + - from: 0 + to: 2.9 + color: "#e74c3c" # critical low + - from: 2.9 + to: 3.1 + color: "#e67e22" # low + - from: 3.1 + to: 3.5 + color: "#2ecc71" # healthy + - from: 3.5 + to: 3.65 + color: "#f39c12" # near full + - from: 3.65 + to: 10 + color: "#e74c3c" # over-voltage + entities: + - entity: sensor.YOUR_BMS_cell_voltage_1 + name: "① " + - entity: sensor.YOUR_BMS_cell_voltage_2 + name: "② " + - entity: sensor.YOUR_BMS_cell_voltage_3 + name: "③ " + - entity: sensor.YOUR_BMS_cell_voltage_4 + name: "④ " + - entity: sensor.YOUR_BMS_cell_voltage_5 + name: "⑤ " + - entity: sensor.YOUR_BMS_cell_voltage_6 + name: "⑥ " + - entity: sensor.YOUR_BMS_cell_voltage_7 + name: "⑦ " + - entity: sensor.YOUR_BMS_cell_voltage_8 + name: "⑧ " + - entity: sensor.YOUR_BMS_cell_voltage_9 + name: "⑨ " + - entity: sensor.YOUR_BMS_cell_voltage_10 + name: "⑩ " + - entity: sensor.YOUR_BMS_cell_voltage_11 + name: "⑪ " + - entity: sensor.YOUR_BMS_cell_voltage_12 + name: "⑫ " + - entity: sensor.YOUR_BMS_cell_voltage_13 + name: "⑬ " + - entity: sensor.YOUR_BMS_cell_voltage_14 + name: "⑭ " + - entity: sensor.YOUR_BMS_cell_voltage_15 + name: "⑮ " + - entity: sensor.YOUR_BMS_cell_voltage_16 + name: "⑯ " + + # ── Cell balance quality ─────────────────────────────────────────────── + - type: custom:mushroom-template-card + primary: "{{ states('sensor.YOUR_BMS_cell_delta') }} mV spread" + secondary: > + {% set d = states('sensor.YOUR_BMS_cell_delta') | float(0) %} + {% if d < 10 %} Excellent balance + {% elif d < 30 %} Good balance + {% elif d < 60 %} Acceptable — balancer may activate + {% else %} Poor balance — inspect cells {% endif %} + entity: sensor.YOUR_BMS_cell_delta + icon: mdi:approximately-equal-box + icon_color: > + {% set d = states('sensor.YOUR_BMS_cell_delta') | float(0) %} + {% if d < 10 %} green + {% elif d < 30 %} light-green + {% elif d < 60 %} orange + {% else %} red {% endif %} + tap_action: + action: more-info + + # ── Voltage + Current history ────────────────────────────────────────── + - type: custom:apexcharts-card + header: + show: true + title: Voltage & Current — last 6 h + show_states: true + colorize_states: true + graph_span: 6h + all_series_config: + stroke_width: 2 + curve: smooth + extend_to: now + series: + - entity: sensor.YOUR_BMS_voltage + name: Voltage + color: "#3498db" + float_precision: 2 + yaxis_id: volts + - entity: sensor.YOUR_BMS_current + name: Current + color: "#2ecc71" + float_precision: 2 + yaxis_id: amps + yaxis: + - id: volts + decimals: 1 + apex_config: + title: + text: V + - id: amps + opposite: true + decimals: 1 + apex_config: + title: + text: A + + # ── State of Charge history ──────────────────────────────────────────── + - type: custom:apexcharts-card + header: + show: true + title: State of Charge — last 24 h + show_states: true + colorize_states: true + graph_span: 24h + series: + - entity: sensor.YOUR_BMS_state_of_charge + name: SoC + color: "#2ecc71" + type: area + opacity: 0.25 + stroke_width: 2 + curve: smooth + extend_to: now + fill_raw: last + yaxis: + - min: 0 + max: 100 + decimals: 0 + apex_config: + title: + text: "%" + + # ── Power history ────────────────────────────────────────────────────── + - type: custom:apexcharts-card + header: + show: true + title: Power — last 6 h + show_states: true + colorize_states: true + graph_span: 6h + series: + - entity: sensor.YOUR_BMS_power + name: Power + color: "#9b59b6" + type: area + opacity: 0.2 + stroke_width: 2 + curve: smooth + extend_to: now + fill_raw: last + yaxis: + - decimals: 0 + apex_config: + title: + text: W + + # ── Controls + Protection ────────────────────────────────────────────── + - type: grid + columns: 2 + square: false + cards: + + - type: entities + title: Controls + entities: + - entity: select.YOUR_BMS_mos_control + name: MOS Gate + - entity: number.YOUR_BMS_nominal_capacity + name: Capacity Override + + - type: entities + title: Protection Status + entities: + - entity: binary_sensor.YOUR_BMS_prot_cell_overvolt + name: Cell Over-Voltage + - entity: binary_sensor.YOUR_BMS_prot_cell_undervolt + name: Cell Under-Voltage + - entity: binary_sensor.YOUR_BMS_prot_pack_overvolt + name: Pack Over-Voltage + - entity: binary_sensor.YOUR_BMS_prot_pack_undervolt + name: Pack Under-Voltage + - entity: binary_sensor.YOUR_BMS_prot_charge_overtemp + name: Charge Over-Temp + - entity: binary_sensor.YOUR_BMS_prot_discharge_overtemp + name: Discharge Over-Temp + - entity: binary_sensor.YOUR_BMS_prot_charge_overcurrent + name: Charge Over-Current + - entity: binary_sensor.YOUR_BMS_prot_discharge_overcurrent + name: Discharge Over-Current + - entity: binary_sensor.YOUR_BMS_prot_short_circuit + name: Short Circuit + - entity: binary_sensor.YOUR_BMS_prot_software_lock + name: Software Lock