this._handleClick(entities.grid_combined || entities.grid)}>
- ${renderMainIcon('grid', isGridExporting ? gridExport : gridImport, iconGrid, gridIconColor)}
- ${renderSecondaryOrLabel(labelGridText, showLabelGrid, entities.secondary_grid, hasSecondaryGrid)}
-
- ${isGridExporting ? html`▲` : (isGridActive ? html`▼` : '')}
- ${this._formatPower(isGridExporting ? gridExport : gridImport)}
-
+
+ ${renderMainIcon('grid', gridImport, iconGrid, gridColor)}
+ ${renderLabel(labelGridText, showLabelGrid)}
+
${this._formatPower(gridImport)}
` : ''}
${hasBattery ? html`
-
this._handleClick(entities.battery)}>
+
${renderMainIcon('battery', battSoc, iconBattery)}
- ${renderSecondaryOrLabel(labelBatteryText, showLabelBattery, entities.secondary_battery, hasSecondaryBattery)}
-
${Math.round(battSoc)}%
+ ${renderLabel(labelBatteryText, showLabelBattery)}
+
${Math.round(battSoc)}%
` : ''}
-
this._handleClick(entities.house)}>
- ${renderMainIcon('house', 0, null, this.config.color_icon_house ? 'var(--icon-house-color)' : houseDominantColor)}
+
+ ${renderMainIcon('house', 0, null, houseDominantColor)}
${renderLabel(labelHouseText, showLabelHouse)}
-
${this._formatPower(houseDisplay)}
+
${this._formatPower(house)}
- ${renderConsumer(showC1, 'c1', 'consumer_1', labelC1, 'car', c1Val, this._getConsumerColor(1))}
- ${renderConsumer(showC2, 'c2', 'consumer_2', labelC2, 'heater', c2Val, this._getConsumerColor(2))}
- ${renderConsumer(showC3, 'c3', 'consumer_3', labelC3, 'pool', c3Val, this._getConsumerColor(3))}
+ ${renderConsumer(showC1, 'c1', 'consumer_1', labelC1, 'car', c1Val, '#a855f7')}
+ ${renderConsumer(showC2, 'c2', 'consumer_2', labelC2, 'heater', c2Val, '#f97316')}
+ ${renderConsumer(showC3, 'c3', 'consumer_3', labelC3, 'pool', c3Val, '#06b6d4')}
`;
- }
-
- render() {
- if (!this.config || !this.hass) return html``;
-
- // SWITCH VIEW BASED ON CONFIG
- if (this.config.compact_view === true) {
- return this._renderCompactView(this.config.entities || {});
- } else {
- return this._renderStandardView(this.config.entities || {});
- }
- }
}
- customElements.define("power-flux-card", PowerFluxCard);
-})(lang_en, lang_de);
+ render() {
+ if (!this.config || !this.hass) return html``;
+
+ // SWITCH VIEW BASED ON CONFIG
+ if (this.config.compact_view === true) {
+ return this._renderCompactView(this.config.entities || {});
+ } else {
+ return this._renderStandardView(this.config.entities || {});
+ }
+ }
+}
+
+customElements.define("power-flux-card", PowerFluxCard);
window.customCards = window.customCards || [];
window.customCards.push({
diff --git a/docs/README-de.md b/docs/README-de.md
index 8f75370..71ad75d 100644
--- a/docs/README-de.md
+++ b/docs/README-de.md
@@ -9,12 +9,10 @@
# Power Flux Card
-Die ⚡Power Flux Card ist eine erweiterte, animierte Energiefluss-Karte für Home Assistant. Sie visualisiert die Energieverteilung zwischen Solar, Netz, Batterie und Verbrauchern mit wunderschönen Neon-Effekten und verschiedenen Animationen.
+Die ⚡Power Flux Card ist eine erweiterte, animierte Energiefluss-Karte für Home Assistant. Sie visualisiert die Energieverteilung zwischen Solar, Netz, Batterie und Verbrauchern mit wunderschönen Neon-Effekten und flüssigen Animationen.
-Wenn euch die custom Card gefällt, würde ich mich sehr über eine Sternebewertung ⭐ freuen. 🤗
-
-

-

+

+

### ✨ Funktionen
@@ -26,21 +24,9 @@ Wenn euch die custom Card gefällt, würde ich mich sehr über eine Sternebewert
- **Donut Chart**: Optionales Donut-Diagramm um das Haus-Icon, das den Energiemix zeigt.
- **Kometenschweif / Gestrichelte Linien**: Wählen Sie Ihren bevorzugten Animationsstil.
- **Zoom**: Anpassbare Größe für Ihr Dashboard.
- - **Benutzerdefinierte Farben**: Definiere benutzerdefinierte Farben für jede Quelle und jeden Verbraucher über den Editor.
- - **Hintergrundfarbe**: Aktiviere einen leicht getönten Hintergrund für die Kreise in der Standard-Ansicht.
-- **Dynamische Animationsgeschwindigkeit**: Partikelgeschwindigkeit und -dichte passen sich dem aktuellen Energiefluss an.
-- **Weitere Informationen**: Klicke auf eine beliebige Quelle/Verbraucher, um detaillierte Informationen in einem More-Info-Dialog anzuzeigen.
-- **Netz-Import/Export**: Unterstützt sowohl separate Import/Export-Entitäten als auch eine kombinierte Entität mit positiven/negativen Werten.
-- **Netz-zu-Batterie**: Optionaler direkter Sensor für den Netz-zu-Batterie-Fluss, der die Standardberechnung umgeht.
-- **Sekundäre Sensoren**: Optional können sekundäre Sensorwerte in den Hauptkreisen (z.B. Tagesertrag für Solar, aktuelle Lade-/Entladeleistung für Batterie) angezeigt werden.
- **Lokalisierung**: Vollständig übersetzt in Deutsch und Englisch.
- **Visueller Editor**: Einfache Konfiguration über die Home Assistant UI.
-[](https://www.youtube.com/watch?v=HGFBJJRWGW0
-)
-
----
-
### 🚀 Installation
### HACS (Empfohlen)
@@ -49,28 +35,25 @@ Wenn euch die custom Card gefällt, würde ich mich sehr über eine Sternebewert
[](https://my.home-assistant.io/redirect/hacs_repository/?owner=jayjojayson&repository=power-flux-card&category=plugin)
-- Das "Power Flux Card" sollte nun in HACS verfügbar sein. Klicke auf "INSTALLIEREN" ("INSTALL").
+- Das "Detailed Charts Panel" sollte nun in HACS verfügbar sein. Klicke auf "INSTALLIEREN" ("INSTALL").
- Die Ressource wird automatisch zu deiner Lovelace-Konfiguration hinzugefügt.
-
+-
#### HACS (manuell)
-1. Stelle sicher, dass HACS installiert ist.
-2. Füge dieses Repository als benutzerdefiniertes Repository in HACS hinzu.
-3. Suche nach "Power Flux Card" und installieren Sie es.
-4. Lade die Ressourcen neu, falls Sie dazu aufgefordert werden.
+1. Stellen Sie sicher, dass HACS installiert ist.
+2. Fügen Sie dieses Repository als benutzerdefiniertes Repository in HACS hinzu.
+3. Suchen Sie nach "Power Flux Card" und installieren Sie es.
+4. Laden Sie die Ressourcen neu, falls Sie dazu aufgefordert werden.
#### Manuelle Installation
-1. Lade die Datei `power-flux-card.js` von der [Releases](../../releases)-Seite herunter.
-2. Lade sie in Ihren `www/community/power-flux-card/`-Ordner in Home Assistant hoch.
-3. Füge die Ressource in Ihrer Dashboard-Konfiguration hinzu:
- - URL: `/local/community/power-flux-card/power-flux-card.js`
+1. Laden Sie die Datei `power-flux-card.js` von der [Releases](../../releases)-Seite herunter.
+2. Laden Sie sie in Ihren `www`-Ordner in Home Assistant hoch.
+3. Fügen Sie die Ressource in Ihrer Dashboard-Konfiguration hinzu:
+ - URL: `/local/power-flux-card.js`
- Typ: JavaScript Module
-
----
-
### ⚙️ Konfiguration
-Du kannst die Karte direkt über den visuellen Editor in Home Assistant konfigurieren.
+Sie können die Karte direkt über den visuellen Editor in Home Assistant konfigurieren.
**Haupt-Entitäten:**
- **Solar**: Erzeugung (W).
@@ -78,7 +61,7 @@ Du kannst die Karte direkt über den visuellen Editor in Home Assistant konfigur
- **Batterie**: Batterieleistung (W) und Ladestand (%).
**Zusätzliche Verbraucher:**
-- Du kannst bis zu 3 individuelle Verbraucher (z.B. Auto, Heizung, Pool) mit eigenen Icons und Beschriftungen hinzufügen.
+- Sie können bis zu 3 individuelle Verbraucher (z.B. Auto, Heizung, Pool) mit eigenen Icons und Beschriftungen hinzufügen.
**Optionen:**
- **Zoom**: Passen Sie die Größe der Karte an.
@@ -86,151 +69,3 @@ Du kannst die Karte direkt über den visuellen Editor in Home Assistant konfigur
- **Donut Chart**: Zeigt den Energiemix als Ring um das Haus an.
- **Kometenschweif / Gestrichelte Linie**: Ändern Sie den Stil der Flussanimation.
- **Kompakte Ansicht**: Wechseln Sie zum Balkendiagramm-Layout.
-- **Farboptionen**: Definieren Sie benutzerdefinierte Farben für jede Quelle und Verbraucher.
-- **Netz-Import/Export**: Konfigurieren Sie separate oder kombinierte Entitäten.
-- **Netz-zu-Batterie**: Optionaler direkter Sensor für den Netz-zu-Batterie-Fluss.
-- **Batterie getrennte Sensoren**: Optional separate Sensoren für Batterie-Ladung und -Entladung.
-- **Sekundäre Sensoren**: Zeigen Sie alternative Werte in den Hauptkreisen an (z.B. Tagesertrag, aktuelle Ladeleistung).
-
-
-
- Custom Farben mit card_mod und Jinja2 Templates
-
-Mit der [card_mod](https://github.com/thomasloven/lovelace-card-mod) Integration können die CSS-Variablen der Power Flux Card dynamisch per Jinja2-Templates überschrieben werden. So lassen sich Farben abhängig von Sensorwerten ändern — z.B. Solar-Icon grün bei Produktion, grau bei Stillstand.
-
-### Verfügbare CSS-Variablen
-
-| Variable | Beschreibung |
-|---|---|
-| `--neon-yellow` | Bubble-Farbe Solar |
-| `--neon-blue` | Bubble-Farbe Grid |
-| `--neon-green` | Bubble-Farbe Batterie |
-| `--neon-pink` | Bubble-Farbe Haus |
-| `--pipe-solar-color` | Pipe-Farbe Solar |
-| `--pipe-grid-color` | Pipe-Farbe Grid |
-| `--pipe-battery-color` | Pipe-Farbe Batterie |
-| `--icon-solar-color` | Icon-Farbe Solar |
-| `--icon-grid-color` | Icon-Farbe Grid |
-| `--icon-battery-color` | Icon-Farbe Batterie |
-| `--icon-house-color` | Icon-Farbe Haus |
-| `--icon-consumer-1-color` | Icon-Farbe Consumer 1 |
-| `--text-solar-color` | Text-Farbe Solar |
-| `--text-grid-color` | Text-Farbe Grid |
-| `--text-battery-color` | Text-Farbe Batterie |
-| `--text-house-color` | Text-Farbe Haus |
-| `--text-consumer-1-color` | Text-Farbe Consumer 1 |
-| `--consumer-1-color` | Bubble-Farbe Consumer 1 |
-| `--consumer-2-color` | Bubble-Farbe Consumer 2 |
-| `--consumer-3-color` | Bubble-Farbe Consumer 3 |
-| `--export-color` | Farbe für Export |
-
-### Beispiel 1: Solar-Icon — grün bei Produktion, grau bei Stillstand
-
-```yaml
-type: custom:power-flux-card
-entities:
- solar: sensor.solar_power
- grid: sensor.grid_power
- battery: sensor.battery_power
- battery_soc: sensor.battery_soc
-card_mod:
- style: |
- :host {
- {% if states('sensor.solar_power') | float > 0 %}
- --icon-solar-color: #00ff88;
- {% else %}
- --icon-solar-color: #9e9e9e;
- {% endif %}
- }
-```
-
-### Beispiel 2: Grid-Textfarbe — rot bei Export, blau bei Import
-
-```yaml
-type: custom:power-flux-card
-entities:
- solar: sensor.solar_power
- grid_combined: sensor.grid_power_combined
- battery: sensor.battery_power
- battery_soc: sensor.battery_soc
-card_mod:
- style: |
- :host {
- {% if states('sensor.grid_power_combined') | float < 0 %}
- --text-grid-color: #ff3333;
- {% else %}
- --text-grid-color: #3b82f6;
- {% endif %}
- }
-```
-
-### Beispiel 3: Batterie-Bubble — Farbe nach Ladestand (SoC)
-
-```yaml
-type: custom:power-flux-card
-entities:
- solar: sensor.solar_power
- grid: sensor.grid_power
- battery: sensor.battery_power
- battery_soc: sensor.battery_soc
-card_mod:
- style: |
- :host {
- {% set soc = states('sensor.battery_soc') | float %}
- {% if soc > 80 %}
- --neon-green: #00ff88;
- {% elif soc > 30 %}
- --neon-green: #f59e0b;
- {% else %}
- --neon-green: #ff3333;
- {% endif %}
- }
-```
-
-### Beispiel 4: Consumer-1-Pipe — sichtbar nur bei hoher Leistung, sonst transparent
-
-```yaml
-type: custom:power-flux-card
-entities:
- solar: sensor.solar_power
- grid: sensor.grid_power
- battery: sensor.battery_power
- battery_soc: sensor.battery_soc
- consumer_1: sensor.wallbox_power
-card_mod:
- style: |
- :host {
- {% if states('sensor.wallbox_power') | float > 500 %}
- --pipe-consumer-1-color: #a855f7;
- --icon-consumer-1-color: #a855f7;
- {% else %}
- --pipe-consumer-1-color: rgba(168, 85, 247, 0.2);
- --icon-consumer-1-color: #9e9e9e;
- {% endif %}
- }
-```
-
-### Beispiel 5: Mehrere Farben gleichzeitig — Nachtmodus (alles gedimmt wenn Solar = 0)
-
-```yaml
-type: custom:power-flux-card
-entities:
- solar: sensor.solar_power
- grid: sensor.grid_power
- battery: sensor.battery_power
- battery_soc: sensor.battery_soc
- consumer_1: sensor.wallbox_power
-card_mod:
- style: |
- :host {
- {% if states('sensor.solar_power') | float == 0 %}
- --icon-solar-color: #555555;
- --text-solar-color: #777777;
- --neon-yellow: #666633;
- --pipe-solar-color: #444422;
- {% endif %}
- }
-```
-
-> **Hinweis:** card_mod muss separat über HACS installiert werden. Die Templates werden bei jedem State-Update ausgewertet, die Farben ändern sich also in Echtzeit.
-
\ No newline at end of file
diff --git a/docs/images/power-flux-card-ani.gif b/docs/images/power-flux-card-ani.gif
deleted file mode 100644
index cb3a364..0000000
Binary files a/docs/images/power-flux-card-ani.gif and /dev/null differ
diff --git a/docs/images/power-flux-card-compact.jpg b/docs/images/power-flux-card-compact.jpg
index 19fafd0..1c9f043 100644
Binary files a/docs/images/power-flux-card-compact.jpg and b/docs/images/power-flux-card-compact.jpg differ
diff --git a/docs/images/power-flux-card-compact2.jpg b/docs/images/power-flux-card-compact2.jpg
deleted file mode 100644
index 04dc763..0000000
Binary files a/docs/images/power-flux-card-compact2.jpg and /dev/null differ
diff --git a/src/lang-de.js b/src/lang-de.js
index 8e7845b..332556d 100644
--- a/src/lang-de.js
+++ b/src/lang-de.js
@@ -9,47 +9,12 @@ export default {
"editor.consumers_section": "Zusätzliche Verbraucher",
"editor.options_section": "Darstellung & Optionen",
"editor.flow_rate_title": "Flussraten (W) an Röhren anzeigen",
- "editor.invert_battery": "Wert umkehren (+/-)",
"editor.label_toggle": "Label im Kreis anzeigen",
"editor.compact_view": "Kompakte Ansicht (evcc)",
"editor.hide_inactive": "Inaktive Röhren ausblenden",
- "editor.entity": "Kombinierter Batterie Sensor (W)",
+ "editor.entity": "Entität (Watt)",
"editor.label": "Beschriftung",
"editor.icon": "Icon",
- "editor.back": "Zurück",
- "editor.battery_soc_label": "Ladestand (%)",
- "editor.house_total_title": "🏠 Gesamtverbrauch (optional)",
- "editor.house_sensor_label": "Sensor für Hausverbrauch (optional)",
- "editor.house_sensor_hint": "Wird benötigt, damit das Haus-Icon anklickbar ist (more-details). Ansonsten wird der Hausverbrauch berechnet.",
- "editor.consumer_1_title": "🚗 Links (Lila)",
- "editor.consumer_2_title": "♨️ Mitte (Orange)",
- "editor.consumer_3_title": "🏊 Rechts (Türkis)",
- "editor.zoom_label": "🔍 Zoom (Standard View)",
- "editor.neon_glow": "Neon Glow",
- "editor.donut_chart": "Donut Chart (Grid/Haus)",
- "editor.comet_tail": "Comet Tail Effect",
- "editor.dashed_line": "Dashed Line Effect",
- "editor.tinted_background": "Farbiger Hintergrund in Kreisen",
- "editor.colored_values": "Farbige Textwerte",
- "editor.hide_consumer_icons": "Icons unten ausblenden",
- "editor.invert_consumer_1": "Sensorwert invertieren (+/-)",
- "editor.secondary_sensor": "Zweiter Sensor (nur Anzeige)",
- "editor.grid_to_battery_sensor": "Netz-zu-Batterie Sensor (W, Optional)",
- "editor.grid_to_battery_hint": "Optional: separater Sensor für den Netz-zu-Batterie Fluss. Wenn leer, wird der Wert automatisch berechnet.",
- "editor.grid_combined_sensor": "Kombinierter Netz-Sensor (W, Optional)",
- "editor.grid_combined_hint": "Ein Sensor für Import UND Export: positiv = Import, negativ = Export. Überschreibt den kombinierten Import/Export Sensor.",
- "editor.color_picker": "Bubble",
- "editor.pipe_color": "Pipe",
- "editor.export_color": "Export",
- "editor.consumer_unit_kw": "Sensor meldet in kW",
- "editor.show_consumer_always": "Verbraucher bei null Watt anzeigen",
- "editor.battery_charge_sensor": "Batterie-Ladung Sensor (W, Optional)",
- "editor.battery_discharge_sensor": "Batterie-Entladung Sensor (W, Optional)",
- "editor.battery_separate_hint": "Optional: Separate Sensoren für Laden/Entladen. Überschreiben den Hauptsensor für die Berechnung.",
- "editor.consumer_1_hide_pipe": "Pipe bei geringer Leistung ausblenden",
- "editor.consumer_pipe_threshold": "Pipe-Schwellenwert (Watt)",
- "editor.text_color": "Text",
- "editor.icon_color": "Icon",
},
card: {
"card.label_solar": "Solar",
@@ -57,7 +22,7 @@ export default {
"card.label_battery": "Batterie",
"card.label_house": "Verbrauch",
"card.label_car": "E-Auto",
- "card.label_heater": "Heizung",
- "card.label_pool": "Pool",
+ "card.label_import": "Import",
+ "card.label_export": "Export",
}
};
diff --git a/src/lang-en.js b/src/lang-en.js
index 46ae1ca..bde372d 100644
--- a/src/lang-en.js
+++ b/src/lang-en.js
@@ -9,47 +9,12 @@ export default {
"editor.consumers_section": "Additional Consumers",
"editor.options_section": "Appearance & Options",
"editor.flow_rate_title": "Show Flow Rates (W) on pipes",
- "editor.invert_battery": "Invert Power Value (+/-)",
"editor.label_toggle": "Show Label in Bubble",
"editor.compact_view": "Compact View (evcc)",
"editor.hide_inactive": "Hide Inactive Pipes",
- "editor.entity": "Combined Battery Sensor (W)",
+ "editor.entity": "Entity (Watt)",
"editor.label": "Label",
"editor.icon": "Icon",
- "editor.back": "Back",
- "editor.battery_soc_label": "State of Charge (%)",
- "editor.house_total_title": "🏠 Total Consumption (optional)",
- "editor.house_sensor_label": "Sensor for House Consumption (optional)",
- "editor.house_sensor_hint": "Required to make the house icon clickable (more-details). Otherwise, the house consumption is calculated.",
- "editor.consumer_1_title": "🚗 Left (Purple)",
- "editor.consumer_2_title": "♨️ Center (Orange)",
- "editor.consumer_3_title": "🏊 Right (Cyan)",
- "editor.zoom_label": "🔍 Zoom (Standard View)",
- "editor.neon_glow": "Neon Glow",
- "editor.donut_chart": "Donut Chart (Grid/House)",
- "editor.comet_tail": "Comet Tail Effect",
- "editor.dashed_line": "Dashed Line Effect",
- "editor.tinted_background": "Tinted Background in Bubbles",
- "editor.colored_values": "Colored Text Values",
- "editor.hide_consumer_icons": "Hide Consumer Icons",
- "editor.invert_consumer_1": "Invert Sensor Value (+/-)",
- "editor.secondary_sensor": "Secondary Sensor (display only)",
- "editor.grid_to_battery_sensor": "Grid to Battery Sensor (W, optional)",
- "editor.grid_to_battery_hint": "Optional: separate sensor for grid-to-battery flow. If empty, the value is calculated automatically.",
- "editor.grid_combined_sensor": "Combined Grid Sensor (W, Optional)",
- "editor.grid_combined_hint": "Single sensor for import AND export: positive = import, negative = export. Overrides combined import/export sensor.",
- "editor.color_picker": "Bubble Color",
- "editor.pipe_color": "Pipe Color",
- "editor.export_color": "Export Color",
- "editor.consumer_unit_kw": "Sensor reports in kW",
- "editor.show_consumer_always": "Show Consumers at zero watts",
- "editor.battery_charge_sensor": "Battery Charge Sensor (W, Optional)",
- "editor.battery_discharge_sensor": "Battery Discharge Sensor (W, Optional)",
- "editor.battery_separate_hint": "Optional: Separate sensors for charge/discharge. Override the main sensor for calculations.",
- "editor.consumer_1_hide_pipe": "Hide pipe at low power",
- "editor.consumer_pipe_threshold": "Pipe Threshold (Watts)",
- "editor.text_color": "Text Color",
- "editor.icon_color": "Icon Color",
},
card: {
"card.label_solar": "Solar",
@@ -57,7 +22,7 @@ export default {
"card.label_battery": "Battery",
"card.label_house": "Consumption",
"card.label_car": "Car",
- "card.label_heater": "Heater",
- "card.label_pool": "Pool",
+ "card.label_import": "Import",
+ "card.label_export": "Export",
}
};
diff --git a/src/power-flux-card-editor.js b/src/power-flux-card-editor.js
index 7702902..84ed4d9 100644
--- a/src/power-flux-card-editor.js
+++ b/src/power-flux-card-editor.js
@@ -1,23 +1,14 @@
-import lang_en from "./lang-en.js";
-import lang_de from "./lang-de.js";
-
-const editorTranslations = {
- "en": lang_en.editor,
- "de": lang_de.editor
-};
-
-
const fireEvent = (node, type, detail, options) => {
- options = options || {};
- detail = detail === null || detail === undefined ? {} : detail;
- const event = new Event(type, {
- bubbles: options.bubbles === undefined ? true : options.bubbles,
- cancelable: Boolean(options.cancelable),
- composed: options.composed === undefined ? true : options.composed,
- });
- event.detail = detail;
- node.dispatchEvent(event);
- return event;
+ options = options || {};
+ detail = detail === null || detail === undefined ? {} : detail;
+ const event = new Event(type, {
+ bubbles: options.bubbles === undefined ? true : options.bubbles,
+ cancelable: Boolean(options.cancelable),
+ composed: options.composed === undefined ? true : options.composed,
+ });
+ event.detail = detail;
+ node.dispatchEvent(event);
+ return event;
};
const LitElement = customElements.get("ha-lit-element") || Object.getPrototypeOf(customElements.get("home-assistant-main"));
@@ -25,174 +16,83 @@ const html = LitElement.prototype.html;
const css = LitElement.prototype.css;
class PowerFluxCardEditor extends LitElement {
+
+ static get properties() {
+ return {
+ hass: {},
+ _config: { state: true },
+ _subView: { state: true } // Controls which sub-page is open (null = main)
+ };
+ }
- static get properties() {
- return {
- hass: {},
- _config: { state: true },
- _subView: { state: true } // Controls which sub-page is open (null = main)
- };
+ setConfig(config) {
+ this._config = config;
+ }
+
+ _localize(key) {
+ const lang = this.hass && this.hass.language ? this.hass.language : 'en';
+ const dict = editorTranslations[lang] || editorTranslations['en'];
+ return dict[key] || editorTranslations['en'][key] || key;
+ }
+
+ _valueChanged(ev) {
+ if (!this._config || !this.hass) return;
+
+ const target = ev.target;
+ const key = target.configValue || this._currentConfigValue;
+
+ let value;
+ if (target.tagName === 'HA-SWITCH') {
+ value = target.checked;
+ } else if (ev.detail && 'value' in ev.detail) {
+ value = ev.detail.value;
+ } else {
+ value = target.value;
+ }
+
+ if (value === null || value === undefined) {
+ value = "";
}
- setConfig(config) {
- this._config = config;
- }
-
- _localize(key) {
- const lang = this.hass && this.hass.language ? this.hass.language : 'en';
- const dict = editorTranslations[lang] || editorTranslations['en'];
- return dict[key] || editorTranslations['en'][key] || key;
- }
-
- _valueChanged(ev) {
- if (!this._config || !this.hass) return;
-
- const target = ev.target;
- const key = target.configValue;
-
- let value;
- if (target.tagName === 'HA-SWITCH') {
- value = target.checked;
- } else if (ev.detail && 'value' in ev.detail) {
- value = ev.detail.value;
- } else {
- value = target.value;
- }
-
- if (value === null || value === undefined) {
- value = "";
- }
-
- if (key) {
- const entityKeys = [
- 'solar', 'grid', 'grid_export', 'grid_combined',
- 'battery', 'battery_soc', 'grid_to_battery',
- 'battery_charge', 'battery_discharge',
- 'house',
- 'consumer_1', 'consumer_2', 'consumer_3',
- 'secondary_solar', 'secondary_grid', 'secondary_battery',
- 'secondary_consumer_1', 'secondary_consumer_2', 'secondary_consumer_3'
- ];
-
- let newConfig = { ...this._config };
-
- if (entityKeys.includes(key)) {
- const currentEntities = newConfig.entities || {};
- const newEntities = { ...currentEntities, [key]: value };
- newConfig.entities = newEntities;
- } else {
- newConfig[key] = value;
-
- if (key === 'show_comet_tail' && value === true) {
- newConfig.show_dashed_line = false;
- }
- if (key === 'show_dashed_line' && value === true) {
- newConfig.show_comet_tail = false;
- }
- }
-
- this._config = newConfig;
- fireEvent(this, "config-changed", { config: this._config });
- }
- }
-
- _goSubView(view) {
- this._subView = view;
- }
-
- _goBack() {
- this._subView = null;
- }
-
- _clearEntity(key) {
- const newConfig = { ...this._config };
- const currentEntities = newConfig.entities || {};
- const newEntities = { ...currentEntities, [key]: "" };
- newConfig.entities = newEntities;
- this._config = newConfig;
- fireEvent(this, "config-changed", { config: this._config });
- }
-
- _colorChanged(key, ev) {
- const newConfig = { ...this._config, [key]: ev.target.value };
- this._config = newConfig;
- fireEvent(this, "config-changed", { config: this._config });
- }
-
- _resetColor(key) {
- const newConfig = { ...this._config };
- delete newConfig[key];
- this._config = newConfig;
- fireEvent(this, "config-changed", { config: this._config });
- }
-
- _renderEntitySelector(entitySelectorSchema, value, configValue, label) {
- const val = value || "";
- return html`
-
-
- ${val ? html` this._clearEntity(configValue)}
- >` : ''}
-
- `;
- }
-
- _renderColorPicker(key, label, defaultColor) {
- const currentColor = this._config[key] || defaultColor;
- const hasCustom = !!this._config[key];
- return html`
-
- this._colorChanged(key, e)}>
- ${label}
- ${hasCustom ? html` this._resetColor(key)}>` : ''}
-
- `;
- }
-
- _renderColorPickerQuad(bubbleKey, pipeKey, textKey, iconKey, defaultColor) {
- const items = [
- { key: bubbleKey, label: this._localize('editor.color_picker'), default: defaultColor },
+ if (key) {
+ const entityKeys = [
+ 'solar', 'grid', 'grid_export',
+ 'battery', 'battery_soc',
+ 'consumer_1', 'consumer_2', 'consumer_3'
];
- if (pipeKey) items.push({ key: pipeKey, label: this._localize('editor.pipe_color'), default: defaultColor });
- items.push({ key: textKey, label: this._localize('editor.text_color'), default: defaultColor });
- items.push({ key: iconKey, label: this._localize('editor.icon_color'), default: defaultColor });
- return html`
-
- ${items.map(item => {
- const color = this._config[item.key] || item.default;
- const hasCustom = !!this._config[item.key];
- return html`
-
- this._colorChanged(item.key, e)}>
- ${item.label}
- ${hasCustom ? html` this._resetColor(item.key)}>` : ''}
-
- `;
- })}
-
- `;
- }
- static get styles() {
- return css`
+ let newConfig = { ...this._config };
+
+ if (entityKeys.includes(key)) {
+ const currentEntities = newConfig.entities || {};
+ const newEntities = { ...currentEntities, [key]: value };
+ newConfig.entities = newEntities;
+ } else {
+ newConfig[key] = value;
+
+ if (key === 'show_comet_tail' && value === true) {
+ newConfig.show_dashed_line = false;
+ }
+ if (key === 'show_dashed_line' && value === true) {
+ newConfig.show_comet_tail = false;
+ }
+ }
+
+ this._config = newConfig;
+ fireEvent(this, "config-changed", { config: this._config });
+ }
+ }
+
+ _goSubView(view) {
+ this._subView = view;
+ }
+
+ _goBack() {
+ this._subView = null;
+ }
+
+ static get styles() {
+ return css`
.card-config {
display: flex;
flex-direction: column;
@@ -269,82 +169,28 @@ class PowerFluxCardEditor extends LitElement {
border-bottom: 1px solid var(--divider-color);
margin: 10px 0;
}
- .entity-picker-wrapper {
- position: relative;
- display: flex;
- align-items: center;
- gap: 4px;
- }
- .entity-picker-wrapper ha-selector {
- flex: 1;
- }
- .clear-entity-btn {
- --mdc-icon-size: 20px;
- color: var(--secondary-text-color);
- cursor: pointer;
- flex-shrink: 0;
- margin-top: -12px;
- }
- .clear-entity-btn:hover {
- color: var(--error-color, #db4437);
- }
- .color-picker-row {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 8px 0;
- }
- .color-picker-row input[type="color"] {
- -webkit-appearance: none;
- border: 2px solid var(--divider-color);
- border-radius: 50%;
- width: 30px;
- height: 30px;
- padding: 2px;
- cursor: pointer;
- background: transparent;
- }
- .color-picker-row input[type="color"]::-webkit-color-swatch-wrapper {
- padding: 0;
- }
- .color-picker-row input[type="color"]::-webkit-color-swatch {
- border: none;
- border-radius: 50%;
- }
- .color-label {
- flex: 1;
- font-size: 14px;
- }
- .color-reset-btn {
- --mdc-icon-size: 20px;
- color: var(--secondary-text-color);
- cursor: pointer;
- }
- .color-reset-btn:hover {
- color: var(--primary-color);
- }
- .color-picker-quad {
- display: flex;
- gap: 8px;
- }
- .color-picker-quad .color-picker-row {
- flex: 1;
- }
`;
- }
+ }
- // --- SUBVIEW RENDERING ---
+ // --- SUBVIEW RENDERING ---
- _renderSolarView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema) {
- return html`
+ _renderSolarView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema) {
+ return html`
- ${this._renderEntitySelector(entitySelectorSchema, entities.solar, 'solar', this._localize('editor.entity'))}
+
@@ -366,15 +212,11 @@ class PowerFluxCardEditor extends LitElement {
@value-changed=${this._valueChanged}
>
- ${this._renderEntitySelector(entitySelectorSchema, entities.secondary_solar || "", 'secondary_solar', this._localize('editor.secondary_sensor'))}
-
- ${this._renderColorPickerQuad('color_solar', 'color_pipe_solar', 'color_text_solar', 'color_icon_solar', '#ffdd00')}
-
@@ -390,29 +232,34 @@ class PowerFluxCardEditor extends LitElement {
${this._localize('editor.flow_rate_title')}
`;
- }
+ }
- _renderGridView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema) {
- return html`
+ _renderGridView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema) {
+ return html`
- ${this._renderEntitySelector(entitySelectorSchema, entities.grid_combined || "", 'grid_combined', this._localize('editor.grid_combined_sensor'))}
-
-
+
-
- ${this._localize('editor.grid_combined_hint')}
-
-
-
- ${this._renderEntitySelector(entitySelectorSchema, entities.grid, 'grid', this._localize('card.label_import') + " (W)")}
-
- ${this._renderEntitySelector(entitySelectorSchema, entities.grid_export, 'grid_export', this._localize('card.label_export') + " (W, Optional)")}
+
@@ -434,17 +281,11 @@ class PowerFluxCardEditor extends LitElement {
@value-changed=${this._valueChanged}
>
- ${this._renderEntitySelector(entitySelectorSchema, entities.secondary_grid || "", 'secondary_grid', this._localize('editor.secondary_sensor'))}
-
- ${this._renderColorPickerQuad('color_grid', 'color_pipe_grid', 'color_text_grid', 'color_icon_grid', '#3b82f6')}
-
- ${this._renderColorPicker('color_export', this._localize('editor.export_color'), '#ff3333')}
-
@@ -460,27 +301,35 @@ class PowerFluxCardEditor extends LitElement {
${this._localize('editor.flow_rate_title')}
`;
- }
+ }
- _renderBatteryView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema) {
- return html`
+ _renderBatteryView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema) {
+ return html`
- ${this._renderEntitySelector(entitySelectorSchema, entities.battery, 'battery', this._localize('editor.entity'))}
-
-
-
-
- ${this._localize('editor.battery_separate_hint')}
-
- ${this._renderEntitySelector(entitySelectorSchema, entities.battery_charge || "", 'battery_charge', this._localize('editor.battery_charge_sensor'))}
- ${this._renderEntitySelector(entitySelectorSchema, entities.battery_discharge || "", 'battery_discharge', this._localize('editor.battery_discharge_sensor'))}
+
+
+
-
-
-
- ${this._renderEntitySelector(entitySelectorSchema, entities.battery_soc, 'battery_soc', this._localize('editor.battery_soc_label'))}
-
-
-
-
- ${this._localize('editor.grid_to_battery_hint')}
-
- ${this._renderEntitySelector(entitySelectorSchema, entities.grid_to_battery || "", 'grid_to_battery', this._localize('editor.grid_to_battery_sensor'))}
-
- ${this._renderEntitySelector(entitySelectorSchema, entities.secondary_battery || "", 'secondary_battery', this._localize('editor.secondary_sensor'))}
-
- ${this._renderColorPickerQuad('color_battery', 'color_pipe_battery', 'color_text_battery', 'color_icon_battery', '#00ff88')}
@@ -535,40 +369,28 @@ class PowerFluxCardEditor extends LitElement {
>
${this._localize('editor.flow_rate_title')}
-
-
-
-
${this._localize('editor.invert_battery')}
-
`;
- }
+ }
- _renderConsumersView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema) {
- return html`
+ _renderConsumersView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema) {
+ return html`
-
${this._localize('editor.house_total_title')}
- ${this._renderEntitySelector(entitySelectorSchema, entities.house || "", 'house', this._localize('editor.house_sensor_label'))}
-
- ${this._localize('editor.house_sensor_hint')}
-
-
- ${this._renderColorPickerQuad('color_house', null, 'color_text_house', 'color_icon_house', '#ff0080')}
-
-
-
-
${this._localize('editor.consumer_1_title')}
- ${this._renderEntitySelector(entitySelectorSchema, entities.consumer_1, 'consumer_1', this._localize('editor.entity'))}
+
🚗 Links (Lila)
+
-
-
- ${this._localize('editor.invert_consumer_1')}
-
-
-
-
- ${this._localize('editor.consumer_1_hide_pipe')}
-
-
-
- ${this._config.consumer_1_hide_pipe === true ? html`
-
- ` : ''}
-
-
- ${this._localize('editor.consumer_unit_kw')}
-
-
-
- ${this._renderEntitySelector(entitySelectorSchema, entities.secondary_consumer_1 || "", 'secondary_consumer_1', this._localize('editor.secondary_sensor'))}
-
- ${this._renderColorPickerQuad('color_consumer_1', 'color_pipe_consumer_1', 'color_text_consumer_1', 'color_icon_consumer_1', '#a855f7')}
-
${this._localize('editor.consumer_2_title')}
- ${this._renderEntitySelector(entitySelectorSchema, entities.consumer_2, 'consumer_2', this._localize('editor.entity'))}
+
♨️ Mitte (Orange)
+
-
-
- ${this._localize('editor.consumer_unit_kw')}
-
-
-
- ${this._renderEntitySelector(entitySelectorSchema, entities.secondary_consumer_2 || "", 'secondary_consumer_2', this._localize('editor.secondary_sensor'))}
-
- ${this._renderColorPickerQuad('color_consumer_2', 'color_pipe_consumer_2', 'color_text_consumer_2', 'color_icon_consumer_2', '#f97316')}
-
${this._localize('editor.consumer_3_title')}
- ${this._renderEntitySelector(entitySelectorSchema, entities.consumer_3, 'consumer_3', this._localize('editor.entity'))}
+
🏊 Rechts (Türkis)
+
-
-
- ${this._localize('editor.consumer_unit_kw')}
-
-
-
- ${this._renderEntitySelector(entitySelectorSchema, entities.secondary_consumer_3 || "", 'secondary_consumer_3', this._localize('editor.secondary_sensor'))}
-
- ${this._renderColorPickerQuad('color_consumer_3', 'color_pipe_consumer_3', 'color_text_consumer_3', 'color_icon_consumer_3', '#06b6d4')}
`;
+ }
+
+ render() {
+ if (!this.hass || !this._config) {
+ return html``;
}
- render() {
- if (!this.hass || !this._config) {
- return html``;
- }
+ const entities = this._config.entities || {};
- const entities = this._config.entities || {};
+ const entitySelectorSchema = { entity: { domain: ["sensor", "input_number"] } };
+ const textSelectorSchema = { text: {} };
+ const iconSelectorSchema = { icon: {} };
- const entitySelectorSchema = { entity: { domain: ["sensor", "input_number"] } };
- const textSelectorSchema = { text: {} };
- const iconSelectorSchema = { icon: {} };
-
- // SUBVIEW ROUTING
- if (this._subView === 'solar') return this._renderSolarView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema);
- if (this._subView === 'grid') return this._renderGridView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema);
- if (this._subView === 'battery') return this._renderBatteryView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema);
- if (this._subView === 'consumers') return this._renderConsumersView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema);
+ // SUBVIEW ROUTING
+ if (this._subView === 'solar') return this._renderSolarView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema);
+ if (this._subView === 'grid') return this._renderGridView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema);
+ if (this._subView === 'battery') return this._renderBatteryView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema);
+ if (this._subView === 'consumers') return this._renderConsumersView(entities, entitySelectorSchema, textSelectorSchema, iconSelectorSchema);
- // MAIN MENU VIEW
- return html`
+ // MAIN MENU VIEW
+ return html`
${this._localize('editor.main_title')}
@@ -757,7 +525,7 @@ class PowerFluxCardEditor extends LitElement {
.selector=${{ number: { min: 0.5, max: 1.5, step: 0.05, mode: "slider" } }}
.value=${this._config.zoom !== undefined ? this._config.zoom : 0.9}
.configValue=${'zoom'}
- .label=${this._localize('editor.zoom_label')}
+ .label=${"🔍 Zoom (Standard View)"}
@value-changed=${this._valueChanged}
>
@@ -768,7 +536,7 @@ class PowerFluxCardEditor extends LitElement {
.configValue=${'show_neon_glow'}
@change=${this._valueChanged}
>
-
${this._localize('editor.neon_glow')}
+
Neon Glow