Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added option to sort individual devices by power usage and have… #700

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions src/components/individualLeftBottomElement.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { html, svg } from "lit";
import { showLine } from "../utils/showLine";
import { PowerFlowCardPlus } from "../power-flow-card-plus";
import { PowerFlowCardPlusConfig } from "../power-flow-card-plus-config";
import { NewDur, TemplatesObj } from "../type";
import { IndividualObject } from "../states/raw/individual/getIndividualObject";
import { NewDur, TemplatesObj } from "../type";
import { checkShouldShowDots } from "../utils/checkShouldShowDots";
import { computeIndividualFlowRate } from "../utils/computeFlowRate";
import { showLine } from "../utils/showLine";
import { styleLine } from "../utils/styleLine";
import { individualSecondarySpan } from "./spans/individualSecondarySpan";
import { HomeAssistant } from "custom-card-helpers";
import { computeIndividualFlowRate } from "../utils/computeFlowRate";
import { checkShouldShowDots } from "../utils/checkShouldShowDots";

interface IndividualBottom {
newDur: NewDur;
Expand All @@ -19,7 +18,6 @@ interface IndividualBottom {

export const individualLeftBottomElement = (
main: PowerFlowCardPlus,
hass: HomeAssistant,
config: PowerFlowCardPlusConfig,
{ individualObj, templatesObj, displayState, newDur }: IndividualBottom
) => {
Expand Down Expand Up @@ -62,7 +60,7 @@ export const individualLeftBottomElement = (
}
}}
>
${individualSecondarySpan(hass, main, config, templatesObj, individualObj, indexOfIndividual, "left-bottom")}
${individualSecondarySpan(main.hass, main, config, templatesObj, individualObj, indexOfIndividual, "left-bottom")}
${individualObj?.icon !== " " ? html` <ha-icon id="individual-left-bottom-icon" .icon=${individualObj?.icon} />` : null}
${individualObj?.field?.display_zero_state !== false || (individualObj?.state || 0) > (individualObj.displayZeroTolerance ?? 0)
? html` <span class="individual-bottom individual-left-bottom"
Expand Down
3 changes: 2 additions & 1 deletion src/localize/languages/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Průhlednost",
"grey_color": "Šedá barva",
"tap_action": "Akce po klepnutí",
"navigation_path": "Navigační cesta"
"navigation_path": "Navigační cesta",
"sort_individual_devices": "Seřaďte individuálně"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Transparenz",
"grey_color": "Graue Farbe",
"tap_action": "Aktion beim Antippen",
"navigation_path": "Navigationspfad"
"navigation_path": "Navigationspfad",
"sort_individual_devices": "Individuelle Geräte sortieren"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/dk.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Transparens",
"grey_color": "Grå farve",
"tap_action": "Tap Handling",
"navigation_path": "Navigationssti"
"navigation_path": "Navigationssti",
"sort_individual_devices": "Sorter individuelle enheder"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Transparency",
"grey_color": "Grey Color",
"tap_action": "Tap Action",
"navigation_path": "Navigation Path"
"navigation_path": "Navigation Path",
"sort_individual_devices": "Sort individual devices"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Läpinäkyvyys",
"grey_color": "Harmaa väri",
"tap_action": "Napauta toimintoa",
"navigation_path": "Navigointipolku"
"navigation_path": "Navigointipolku",
"sort_individual_devices": "Lajittele yksittäiset laitteet"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Transparence",
"grey_color": "Couleur grise",
"tap_action": "Action de tap",
"navigation_path": "Chemin de navigation"
"navigation_path": "Chemin de navigation",
"sort_individual_devices": "Trier les appareils individuels"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Trasparenza",
"grey_color": "Colore Sfumato",
"tap_action": "Azione al tocco",
"navigation_path": "Percorso di navigazione"
"navigation_path": "Percorso di navigazione",
"sort_individual_devices": "Ordina i singoli individuale"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Transparantie",
"grey_color": "Grijstint",
"tap_action": "Tik Actie",
"navigation_path": "Navigatiepad"
"navigation_path": "Navigatiepad",
"sort_individual_devices": "Sorteer individuele apparaten"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Przezroczystość",
"grey_color": "Kolor szary",
"tap_action": "Akcja dotknięcia",
"navigation_path": "Ścieżka nawigacji"
"navigation_path": "Ścieżka nawigacji",
"sort_individual_devices": "Sortuj poszczególne urządzenia"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Transparência",
"grey_color": "Cor do Cinza",
"tap_action": "Ação de Toque",
"navigation_path": "Caminho de Navegação"
"navigation_path": "Caminho de Navegação",
"sort_individual_devices": "Classifique dispositivos individuais"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/pt-PT.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Transparência",
"grey_color": "Cor Cinzenta",
"tap_action": "Ação de Toque",
"navigation_path": "Caminho de Navegação"
"navigation_path": "Caminho de Navegação",
"sort_individual_devices": "Classifique dispositivos individuais"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Прозрачность",
"grey_color": "Серый цвет",
"tap_action": "действие касания",
"navigation_path": "путь навигации"
"navigation_path": "путь навигации",
"sort_individual_devices": "Сортировка отдельных устройств"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/sk.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Transparentnosť",
"grey_color": "Šedá farba",
"tap_action": "Akcia po klepnutí",
"navigation_path": "Navigačná cesta"
"navigation_path": "Navigačná cesta",
"sort_individual_devices": "Zoraďte jednotlivé zariadenia"
}
}
3 changes: 2 additions & 1 deletion src/localize/languages/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"transparency": "Transparens",
"grey_color": "Grå färg",
"tap_action": "Tryckåtgärd",
"navigation_path": "Navigationsväg"
"navigation_path": "Navigationsväg",
"sort_individual_devices": "Sortera enskilda enheter"
}
}
5 changes: 2 additions & 3 deletions src/power-flow-card-plus-config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LovelaceCardConfig } from "custom-card-helpers";
import { ComboEntity, GridPowerOutage, IndividualDeviceType, SecondaryInfoType, BaseConfigEntity } from "./type.js";
import { BaseConfigEntity, ComboEntity, GridPowerOutage, IndividualDeviceType, SecondaryInfoType } from "./type.js";

export type DisplayZeroLinesMode = "show" | "grey_out" | "transparency" | "hide" | "custom";

Expand Down Expand Up @@ -30,6 +30,7 @@ interface mainConfigOptions {
transparency?: number;
grey_color?: string | number[];
};
sort_individual_devices?: boolean;
}

export interface PowerFlowCardPlusConfig extends LovelaceCardConfig, mainConfigOptions {
Expand Down Expand Up @@ -103,5 +104,3 @@ export type ConfigEntities = {
};

export type ConfigEntity = Battery | Grid | Solar | Home | FossilFuelPercentage | IndividualDeviceType;

export const MAX_INDIVIDUAL_ENTITIES = 4;
91 changes: 49 additions & 42 deletions src/power-flow-card-plus.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,38 @@
/* eslint-disable wc/guard-super-call */
/* eslint-disable import/extensions */
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { ActionConfig, HomeAssistant, LovelaceCardEditor } from "custom-card-helpers";
import { html, LitElement, PropertyValues, svg, TemplateResult } from "lit";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, query, state } from "lit/decorators.js";
import { MAX_INDIVIDUAL_ENTITIES, PowerFlowCardPlusConfig } from "./power-flow-card-plus-config";
import { coerceNumber } from "./utils/utils";
import { registerCustomCard } from "./utils/register-custom-card";
import { RenderTemplateResult, subscribeRenderTemplate } from "./template/ha-websocket.js";
import { styles } from "./style";
import { defaultValues, getDefaultConfig } from "./utils/get-default-config";
import { getEntityStateWatts } from "./states/utils/getEntityStateWatts";
import { getEntityState } from "./states/utils/getEntityState";
import { doesEntityExist } from "./states/utils/existenceEntity";
import { computeFlowRate } from "./utils/computeFlowRate";
import { getGridConsumptionState, getGridProductionState, getGridSecondaryState } from "./states/raw/grid";
import { getSolarSecondaryState } from "./states/raw/solar";
import { getSolarState } from "./states/raw/solar";
import { getBatteryInState, getBatteryOutState, getBatteryStateOfCharge } from "./states/raw/battery";
import { computeFieldIcon, computeFieldName } from "./utils/computeFieldAttributes";
import { adjustZeroTolerance } from "./states/tolerance/base";
import { getNonFossilHas, getNonFossilHasPercentage, getNonFossilSecondaryState } from "./states/raw/nonFossil";
import { getHomeSecondaryState } from "./states/raw/home";
import { GridObject, HomeSources, NewDur, TemplatesObj } from "./type";
import { displayValue } from "./utils/displayValue";
import { allDynamicStyles } from "./style/all";
import { nonFossilElement } from "./components/nonFossil";
import { solarElement } from "./components/solar";
import { gridElement } from "./components/grid";
import { homeElement } from "./components/home";
import { batteryElement } from "./components/battery";
import { flowElement } from "./components/flows";
import { dashboardLinkElement } from "./components/misc/dashboard_link";
import { IndividualObject, getIndividualObject } from "./states/raw/individual/getIndividualObject";
import { individualLeftTopElement } from "./components/individualLeftTopElement";
import { gridElement } from "./components/grid";
import { homeElement } from "./components/home";
import { individualLeftBottomElement } from "./components/individualLeftBottomElement";
import { individualLeftTopElement } from "./components/individualLeftTopElement";
import { individualRightBottomElement } from "./components/individualRightBottomElement";
import { individualRightTopElement } from "./components/individualRightTopElement";
import { dashboardLinkElement } from "./components/misc/dashboard_link";
import { nonFossilElement } from "./components/nonFossil";
import { solarElement } from "./components/solar";
import { handleAction } from "./ha/panels/lovelace/common/handle-action";
import { PowerFlowCardPlusConfig } from "./power-flow-card-plus-config";
import { getBatteryInState, getBatteryOutState, getBatteryStateOfCharge } from "./states/raw/battery";
import { getGridConsumptionState, getGridProductionState, getGridSecondaryState } from "./states/raw/grid";
import { getHomeSecondaryState } from "./states/raw/home";
import { getIndividualObject, IndividualObject } from "./states/raw/individual/getIndividualObject";
import { getNonFossilHas, getNonFossilHasPercentage, getNonFossilSecondaryState } from "./states/raw/nonFossil";
import { getSolarSecondaryState, getSolarState } from "./states/raw/solar";
import { adjustZeroTolerance } from "./states/tolerance/base";
import { doesEntityExist } from "./states/utils/existenceEntity";
import { getEntityState } from "./states/utils/getEntityState";
import { getEntityStateWatts } from "./states/utils/getEntityStateWatts";
import { styles } from "./style";
import { allDynamicStyles } from "./style/all";
import { RenderTemplateResult, subscribeRenderTemplate } from "./template/ha-websocket.js";
import { GridObject, HomeSources, NewDur, TemplatesObj } from "./type";
import { computeFieldIcon, computeFieldName } from "./utils/computeFieldAttributes";
import { computeFlowRate } from "./utils/computeFlowRate";
import {
checkHasBottomIndividual,
checkHasRightIndividual,
Expand All @@ -43,10 +41,10 @@ import {
getTopLeftIndividual,
getTopRightIndividual,
} from "./utils/computeIndividualPosition";
import { individualRightTopElement } from "./components/individualRightTopElement";
import { individualRightBottomElement } from "./components/individualRightBottomElement";
import { fireEvent } from "./ui-editor/utils/fire_event";
import { handleAction } from "./ha/panels/lovelace/common/handle-action";
import { displayValue } from "./utils/displayValue";
import { defaultValues, getDefaultConfig } from "./utils/get-default-config";
import { registerCustomCard } from "./utils/register-custom-card";
import { coerceNumber } from "./utils/utils";

const circleCircumference = 238.76104;

Expand Down Expand Up @@ -98,9 +96,6 @@ export class PowerFlowCardPlus extends LitElement {
mode: "sort_power",
},
};

if (this._config.entities?.individual && this._config.entities.individual.length > MAX_INDIVIDUAL_ENTITIES)
throw new Error(`Only ${MAX_INDIVIDUAL_ENTITIES} individual entities are supported`);
}

public connectedCallback() {
Expand Down Expand Up @@ -550,10 +545,12 @@ export class PowerFlowCardPlus extends LitElement {
isCardWideEnough,
});

const individualFieldLeftTop = getTopLeftIndividual(this._config, individualObjs);
const individualFieldLeftBottom = getBottomLeftIndividual(this._config, individualObjs);
const individualFieldRightTop = getTopRightIndividual(this._config, individualObjs);
const individualFieldRightBottom = getBottomRightIndividual(this._config, individualObjs);
const sortedIndividualObjects = this._config.sort_individual_devices ? sortIndividualObjects(individualObjs) : individualObjs;

const individualFieldLeftTop = getTopLeftIndividual(this._config, sortedIndividualObjects);
const individualFieldLeftBottom = getBottomLeftIndividual(this._config, sortedIndividualObjects);
const individualFieldRightTop = getTopRightIndividual(this._config, sortedIndividualObjects);
const individualFieldRightBottom = getBottomRightIndividual(this._config, sortedIndividualObjects);

return html`
<ha-card
Expand Down Expand Up @@ -635,7 +632,7 @@ export class PowerFlowCardPlus extends LitElement {

${battery.has ? batteryElement(this, this._config, { battery, entities }) : html`<div class="spacer"></div>`}
${individualFieldLeftBottom
? individualLeftBottomElement(this, this.hass, this._config, {
? individualLeftBottomElement(this, this._config, {
displayState: getIndividualDisplayState(individualFieldLeftBottom),
individualObj: individualFieldLeftBottom,
newDur,
Expand Down Expand Up @@ -776,3 +773,13 @@ export class PowerFlowCardPlus extends LitElement {

static styles = styles;
}

function sortIndividualObjects(individualObjs: IndividualObject[]) {
const sorted = [...individualObjs];
sorted
.sort((a, b) => {
return (a.state || 0) - (b.state || 0);
})
.reverse();
return sorted;
}
19 changes: 8 additions & 11 deletions src/ui-editor/components/individual-row-editor.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { mdiClose, mdiDrag, mdiPencil } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { HomeAssistant } from "custom-card-helpers";
import { css, CSSResultGroup, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { repeat } from "lit/directives/repeat.js";
import type { SortableEvent } from "sortablejs";
import localize from "../../localize/localize";
import { PowerFlowCardPlusConfig } from "../../power-flow-card-plus-config";
import { individualSchema } from "../schema/individual";
import { EditSubElementEvent, EntityConfig, LovelaceRowConfig } from "../types/entity-rows";
import { HomeAssistant } from "custom-card-helpers";
import { loadSortable, SortableInstance } from "../utils/sortable.ondemand";
import { fireEvent } from "../utils/fire_event";
import { sortableStyles } from "../utils/sortable_styles";
import { MAX_INDIVIDUAL_ENTITIES, PowerFlowCardPlusConfig } from "../../power-flow-card-plus-config";
import { loadHaForm } from "../utils/loadHAForm";
import { individualSchema } from "../schema/individual";
import localize from "../../localize/localize";
import { loadSortable, SortableInstance } from "../utils/sortable.ondemand";
import { sortableStyles } from "../utils/sortable_styles";

declare global {
interface HASSDomEvents {
Expand Down Expand Up @@ -137,10 +137,7 @@ export class IndividualRowEditor extends LitElement {
`
)}
</div>

${this.entities.length >= MAX_INDIVIDUAL_ENTITIES
? nothing
: html` <ha-entity-picker class="add-entity" .hass=${this.hass} @value-changed=${this._addEntity}></ha-entity-picker>`}
<ha-entity-picker class="add-entity" .hass=${this.hass} @value-changed=${this._addEntity}></ha-entity-picker>
`;
}

Expand Down
18 changes: 12 additions & 6 deletions src/ui-editor/schema/_schema-all.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import/extensions */
import { any, assign, boolean, integer, number, object, optional, string } from "superstruct";
import { mdiBatteryHigh, mdiHome, mdiLeaf, mdiTransmissionTower, mdiWeatherSunny } from "@mdi/js";
import memoizeOne from "memoize-one";
import { gridSchema } from "./grid";
import { any, assign, boolean, integer, number, object, optional, string } from "superstruct";
import { batterySchema } from "./battery";
import { solarSchema } from "./solar";
import { individualSchema } from "./individual";
import { displayZeroLinesSchema } from "./display_zero_lines";
import { nonFossilSchema } from "./fossil_fuel_percentage";
import { gridSchema } from "./grid";
import { homeSchema } from "./home";
import { displayZeroLinesSchema } from "./display_zero_lines";
import { mdiBattery90, mdiBatteryHigh, mdiCog, mdiHome, mdiLeaf, mdiTransmissionTower, mdiWeatherSunny } from "@mdi/js";
import { individualSchema } from "./individual";
import { solarSchema } from "./solar";

const baseLovelaceCardConfig = object({
type: string(),
Expand Down Expand Up @@ -50,6 +50,7 @@ export const cardConfigStruct = assign(
fossil_fuel_percentage: optional(any()),
individual: optional(any()),
}),
sort_individual_devices: optional(boolean()),
})
);

Expand Down Expand Up @@ -194,6 +195,11 @@ export const advancedOptionsSchema = memoizeOne((localize, displayZeroLinesMode:
label: "New Flow Model?",
selector: { boolean: {} },
},
{
name: "sort_individual_devices",
label: "Sort individual devices by usage",
selector: { boolean: {} },
},
],
},
{
Expand Down
Loading