From bf8c5d80a7020934540b77a893ed4f47e28f7a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luca=20F=C3=A9lix?= Date: Sun, 26 Mar 2023 23:10:39 +0200 Subject: [PATCH 1/2] feat: added display state functionality for battery and grid --- src/power-flow-card-plus-config.ts | 2 + src/power-flow-card-plus.ts | 191 +++++++++++++++++------------ 2 files changed, 117 insertions(+), 76 deletions(-) diff --git a/src/power-flow-card-plus-config.ts b/src/power-flow-card-plus-config.ts index 28e9d20..c83d342 100644 --- a/src/power-flow-card-plus-config.ts +++ b/src/power-flow-card-plus-config.ts @@ -10,6 +10,7 @@ export interface PowerFlowCardConfig extends LovelaceCardConfig { icon?: string; color?: ComboEntity; color_icon?: boolean | "production" | "consumption"; + display_state?: "two_way" | "one_way" | "one_way_no_zero"; } grid?: { entity: string | ComboEntity; @@ -17,6 +18,7 @@ export interface PowerFlowCardConfig extends LovelaceCardConfig { icon?: string; color?: ComboEntity; color_icon?: boolean | "production" | "consumption"; + display_state?: "two_way" | "one_way" | "one_way_no_zero"; }; solar?: { entity: string; diff --git a/src/power-flow-card-plus.ts b/src/power-flow-card-plus.ts index 672986f..98e72da 100644 --- a/src/power-flow-card-plus.ts +++ b/src/power-flow-card-plus.ts @@ -401,15 +401,15 @@ export class PowerFlowCard extends LitElement { } if (this._config.entities.battery?.color?.consumption !== undefined) - this.style.setProperty( - "--energy-battery-out-color", - this._config.entities.battery?.color?.consumption || "#4db6ac" - ); + this.style.setProperty( + "--energy-battery-out-color", + this._config.entities.battery?.color?.consumption || "#4db6ac" + ); if (this._config.entities.battery?.color?.production !== undefined) - this.style.setProperty( - "--energy-battery-in-color", - this._config.entities.battery?.color?.production || "#a280db" - ); + this.style.setProperty( + "--energy-battery-in-color", + this._config.entities.battery?.color?.production || "#a280db" + ); const batteryIconColorType = this._config.entities.battery?.color_icon; this.style.setProperty( "--icon-battery-color", @@ -794,7 +794,14 @@ export class PowerFlowCard extends LitElement { - ${totalToGrid !== null + ${(entities.grid?.display_state === "two_way" || + entities.grid?.display_state === undefined || + (entities.grid?.display_state === "one_way" && + totalToGrid > 0) || + (entities.grid?.display_state === "one_way_no_zero" && + (totalFromGrid === null || totalFromGrid === 0) && + totalToGrid !== 0)) && + totalToGrid !== null ? html` void }) => { @@ -826,13 +833,21 @@ export class PowerFlowCard extends LitElement { ${this.displayValue(totalToGrid)} ` : null} - - ${this.displayValue(totalFromGrid)} - + ${(entities.grid?.display_state === "two_way" || + entities.grid?.display_state === undefined || + (entities.grid?.display_state === "one_way" && + totalFromGrid > 0) || + (entities.grid?.display_state === "one_way_no_zero" && + (totalToGrid === null || totalToGrid === 0))) && + totalFromGrid !== null + ? html` + ${this.displayValue(totalFromGrid)} + ` + : ""} ${entities.grid!.name || @@ -986,6 +1001,10 @@ export class PowerFlowCard extends LitElement { : null} 0 + ? "padding-top: 0px; padding-bottom: 2px;" + : "padding-top: 2px; padding-bottom: 0px;"} @click=${(e: { stopPropagation: () => void }) => { e.stopPropagation(); this.openDetails( @@ -1004,66 +1023,86 @@ export class PowerFlowCard extends LitElement { } }} > - void }) => { - const target = - typeof entities.battery!.entity === "string" - ? entities.battery!.entity! - : entities.battery!.entity!.production!; - e.stopPropagation(); - this.openDetails(target); - }} - @keyDown=${(e: { - key: string; - stopPropagation: () => void; - }) => { - if (e.key === "Enter") { - const target = - typeof entities.battery!.entity === "string" - ? entities.battery!.entity! - : entities.battery!.entity!.production!; - e.stopPropagation(); - this.openDetails(target); - } - }} - > - - ${this.displayValue(totalBatteryIn)} - void }) => { - const target = - typeof entities.battery!.entity === "string" - ? entities.battery!.entity! - : entities.battery!.entity!.consumption!; - e.stopPropagation(); - this.openDetails(target); - }} - @keyDown=${(e: { - key: string; - stopPropagation: () => void; - }) => { - if (e.key === "Enter") { - const target = - typeof entities.battery!.entity === "string" - ? entities.battery!.entity! - : entities.battery!.entity!.consumption!; - e.stopPropagation(); - this.openDetails(target); - } - }} - > - - ${this.displayValue(totalBatteryOut)} + ${(entities.battery?.display_state === "two_way" || + entities.battery?.display_state === undefined || + (entities.battery?.display_state === "one_way" && + totalBatteryIn > 0) || + (entities.grid?.display_state === "one_way_no_zero" && + (totalBatteryOut === null || + totalBatteryOut === 0) && + totalBatteryIn !== 0)) && + totalToGrid !== null + ? html` void }) => { + const target = + typeof entities.battery!.entity === "string" + ? entities.battery!.entity! + : entities.battery!.entity!.production!; + e.stopPropagation(); + this.openDetails(target); + }} + @keyDown=${(e: { + key: string; + stopPropagation: () => void; + }) => { + if (e.key === "Enter") { + const target = + typeof entities.battery!.entity === "string" + ? entities.battery!.entity! + : entities.battery!.entity!.production!; + e.stopPropagation(); + this.openDetails(target); + } + }} + > + + ${this.displayValue(totalBatteryIn)}` + : ""} + ${(entities.battery?.display_state === "two_way" || + entities.battery?.display_state === undefined || + (entities.battery?.display_state === "one_way" && + totalBatteryOut > 0) || + (entities.battery?.display_state === + "one_way_no_zero" && + (totalBatteryIn === null || + totalBatteryIn === 0))) && + totalBatteryOut !== null + ? html` void }) => { + const target = + typeof entities.battery!.entity === "string" + ? entities.battery!.entity! + : entities.battery!.entity!.consumption!; + e.stopPropagation(); + this.openDetails(target); + }} + @keyDown=${(e: { + key: string; + stopPropagation: () => void; + }) => { + if (e.key === "Enter") { + const target = + typeof entities.battery!.entity === "string" + ? entities.battery!.entity! + : entities.battery!.entity!.consumption!; + e.stopPropagation(); + this.openDetails(target); + } + }} + > + + ${this.displayValue(totalBatteryOut)}` + : ""} ${entities.battery!.name || From d39c318bf719d78c6c390e269edaba01c25ffe0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luca=20F=C3=A9lix?= <61006057+flixlix@users.noreply.github.com> Date: Sun, 26 Mar 2023 23:20:56 +0200 Subject: [PATCH 2/2] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d27a0d0..6df5cbb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # Power Flow Card Plus ![GitHub release (latest by date)](https://img.shields.io/github/v/release/flixlix/power-flow-card-plus?style=flat-square) @@ -113,6 +114,9 @@ At least one of _grid_, _battery_, or _solar_ is required. All entites (except _ | icon | `string` | `mdi:transmission-tower` | Icon path for the icon inside the Grid Circle. | | color | `object` | | Check [Color Objects](#color-object) for more information. | | color_icon | `boolean` or "production" or "consumption" | `false` | If set to `true`, icon color will match the highest value. If set to `production`, icon color will match the production. If set to `consumption`, icon color will match the consumption. | +| display_state | "two_way" or "one_way" or "one_way_no_zero" | `two_way` | If set to `two_way` the production will always be shown simultaneously, no matter the state. If set to `one_way` only the direction that is active will be shown (since this card only shows instantaneous power, there will be no overlaps ✅). If set to `one_way_no_zero` the behavior will be the same as `one_way` but you will still the consumption direction when every state is `0`. | + + #### Solar Configuration @@ -128,12 +132,13 @@ At least one of _grid_, _battery_, or _solar_ is required. All entites (except _ | Name | Type | Default | Description | | ----------- | ------- | -------- | ------------------------------------------------------------------------------------------------- | -| entity | `string` or `object` | `undefined` required | Entity ID of a sensor supporting a single state with negative values for production and positive values for consumption or an object for [split entites](#split-entities). Examples of both can be found below. | +| entity | `string` or `object` | `undefined` required | Entity ID of a sensor supporting a single state with negative values for production and positive values for consumption or an object for [split entities](#split-entities). Examples of both can be found below. | | state_of_charge | `string` | `undefined` required | Entity ID providing a state with the state of charge of the battery in percent (state of `100` for a full battery). | | name | `string` | `Battery` | Label for the battery option. If you don't populate this option, the label will continue to update based on the language selected. | | icon | `string` | `mdi:battery` or dynamic based on state of the battery | Icon path for the icon inside the Battery Circle. | | color | `object` | | Check [Color Objects](#color-object) for more information. | | color_icon | `boolean` or "production" or "consumption" | `false` | If set to `true`, icon color will match the highest value. If set to `production`, icon color will match the production. If set to `consumption`, icon color will match the consumption. | +| display_state | "two_way" or "one_way" or "one_way_no_zero" | `two_way` | If set to `two_way` the production will always be shown simultaneously, no matter the state. If set to `one_way` only the direction that is active will be shown (since this card only shows instantaneous power, there will be no overlaps ✅). If set to `one_way_no_zero` the behavior will be the same as `one_way` but you will still the consumption direction when every state is `0`. | #### Individual Configuration