// @ts-ignore import dataTableStyles from "@material/data-table/dist/mdc.data-table.min.css"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS, } from "lit"; import { customElement, property, state } from "lit/decorators"; import { styleMap } from "lit/directives/style-map"; import { rgb2hex, lab2rgb, rgb2lab, hex2rgb, } from "../../../../common/color/convert-color"; import { labDarken } from "../../../../common/color/lab"; import { computeStateName } from "../../../../common/entity/compute_state_name"; import { formatNumber } from "../../../../common/number/format_number"; import "../../../../components/chart/statistics-chart"; import "../../../../components/ha-card"; import { EnergyData, energySourcesByType, getEnergyDataCollection, getEnergyGasUnit, } from "../../../../data/energy"; import { calculateStatisticSumGrowth } from "../../../../data/history"; import { SubscribeMixin } from "../../../../mixins/subscribe-mixin"; import { HomeAssistant } from "../../../../types"; import { LovelaceCard } from "../../types"; import { EnergySourcesTableCardConfig } from "../types"; @customElement("hui-energy-sources-table-card") export class HuiEnergySourcesTableCard extends SubscribeMixin(LitElement) implements LovelaceCard { @property({ attribute: false }) public hass!: HomeAssistant; @state() private _config?: EnergySourcesTableCardConfig; @state() private _data?: EnergyData; public hassSubscribe(): UnsubscribeFunc[] { return [ getEnergyDataCollection(this.hass, { key: this._config?.collection_key, }).subscribe((data) => { this._data = data; }), ]; } public getCardSize(): Promise | number { return 3; } public setConfig(config: EnergySourcesTableCardConfig): void { this._config = config; } protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; } if (!this._data) { return html`Loading...`; } let totalGrid = 0; let totalGridCost = 0; let totalSolar = 0; let totalBattery = 0; let totalGas = 0; let totalGasCost = 0; const types = energySourcesByType(this._data.prefs); const computedStyles = getComputedStyle(this); const solarColor = computedStyles .getPropertyValue("--energy-solar-color") .trim(); const batteryFromColor = computedStyles .getPropertyValue("--energy-battery-out-color") .trim(); const batteryToColor = computedStyles .getPropertyValue("--energy-battery-in-color") .trim(); const returnColor = computedStyles .getPropertyValue("--energy-grid-return-color") .trim(); const consumptionColor = computedStyles .getPropertyValue("--energy-grid-consumption-color") .trim(); const gasColor = computedStyles .getPropertyValue("--energy-gas-color") .trim(); const showCosts = types.grid?.[0].flow_from.some( (flow) => flow.stat_cost || flow.entity_energy_price || flow.number_energy_price ) || types.grid?.[0].flow_to.some( (flow) => flow.stat_compensation || flow.entity_energy_price || flow.number_energy_price ) || types.gas?.some( (flow) => flow.stat_cost || flow.entity_energy_price || flow.number_energy_price ); const gasUnit = getEnergyGasUnit(this.hass, this._data.prefs) || ""; return html` ${this._config.title ? html`

${this._config.title}

` : ""}
${showCosts ? html` ` : ""} ${types.solar?.map((source, idx) => { const entity = this.hass.states[source.stat_energy_from]; const energy = calculateStatisticSumGrowth( this._data!.stats[source.stat_energy_from] ) || 0; totalSolar += energy; const color = idx > 0 ? rgb2hex( lab2rgb(labDarken(rgb2lab(hex2rgb(solarColor)), idx)) ) : solarColor; return html` ${showCosts ? html`` : ""} `; })} ${types.solar ? html` ${showCosts ? html`` : ""} ` : ""} ${types.battery?.map((source, idx) => { const entityFrom = this.hass.states[source.stat_energy_from]; const entityTo = this.hass.states[source.stat_energy_to]; const energyFrom = calculateStatisticSumGrowth( this._data!.stats[source.stat_energy_from] ) || 0; const energyTo = calculateStatisticSumGrowth( this._data!.stats[source.stat_energy_to] ) || 0; totalBattery += energyFrom - energyTo; const fromColor = idx > 0 ? rgb2hex( lab2rgb( labDarken(rgb2lab(hex2rgb(batteryFromColor)), idx) ) ) : batteryFromColor; const toColor = idx > 0 ? rgb2hex( lab2rgb( labDarken(rgb2lab(hex2rgb(batteryToColor)), idx) ) ) : batteryToColor; return html` ${showCosts ? html`` : ""} ${showCosts ? html`` : ""} `; })} ${types.battery ? html` ${showCosts ? html`` : ""} ` : ""} ${types.grid?.map( (source) => html`${source.flow_from.map((flow, idx) => { const entity = this.hass.states[flow.stat_energy_from]; const energy = calculateStatisticSumGrowth( this._data!.stats[flow.stat_energy_from] ) || 0; totalGrid += energy; const cost_stat = flow.stat_cost || this._data!.info.cost_sensors[flow.stat_energy_from]; const cost = cost_stat ? calculateStatisticSumGrowth( this._data!.stats[cost_stat] ) || 0 : null; if (cost !== null) { totalGridCost += cost; } const color = idx > 0 ? rgb2hex( lab2rgb( labDarken(rgb2lab(hex2rgb(consumptionColor)), idx) ) ) : consumptionColor; return html` ${showCosts ? html` ` : ""} `; })} ${source.flow_to.map((flow, idx) => { const entity = this.hass.states[flow.stat_energy_to]; const energy = (calculateStatisticSumGrowth( this._data!.stats[flow.stat_energy_to] ) || 0) * -1; totalGrid += energy; const cost_stat = flow.stat_compensation || this._data!.info.cost_sensors[flow.stat_energy_to]; const cost = cost_stat ? (calculateStatisticSumGrowth( this._data!.stats[cost_stat] ) || 0) * -1 : null; if (cost !== null) { totalGridCost += cost; } const color = idx > 0 ? rgb2hex( lab2rgb(labDarken(rgb2lab(hex2rgb(returnColor)), idx)) ) : returnColor; return html` ${showCosts ? html` ` : ""} `; })}` )} ${types.grid ? html` ${showCosts ? html`` : ""} ` : ""} ${types.gas?.map((source, idx) => { const entity = this.hass.states[source.stat_energy_from]; const energy = calculateStatisticSumGrowth( this._data!.stats[source.stat_energy_from] ) || 0; totalGas += energy; const cost_stat = source.stat_cost || this._data!.info.cost_sensors[source.stat_energy_from]; const cost = cost_stat ? calculateStatisticSumGrowth(this._data!.stats[cost_stat]) || 0 : null; if (cost !== null) { totalGasCost += cost; } const color = idx > 0 ? rgb2hex( lab2rgb(labDarken(rgb2lab(hex2rgb(gasColor)), idx)) ) : gasColor; return html` ${showCosts ? html`` : ""} `; })} ${types.gas ? html` ${showCosts ? html`` : ""} ` : ""} ${totalGasCost && totalGridCost ? html`` : ""}
Source Energy Cost
${entity ? computeStateName(entity) : source.stat_energy_from} ${formatNumber(energy, this.hass.locale)} kWh
Solar total ${formatNumber(totalSolar, this.hass.locale)} kWh
${entityFrom ? computeStateName(entityFrom) : source.stat_energy_from} ${formatNumber(energyFrom, this.hass.locale)} kWh
${entityTo ? computeStateName(entityTo) : source.stat_energy_from} ${formatNumber(energyTo * -1, this.hass.locale)} kWh
Battery total ${formatNumber(totalBattery, this.hass.locale)} kWh
${entity ? computeStateName(entity) : flow.stat_energy_from} ${formatNumber(energy, this.hass.locale)} kWh ${cost !== null ? formatNumber(cost, this.hass.locale, { style: "currency", currency: this.hass.config.currency!, }) : ""}
${entity ? computeStateName(entity) : flow.stat_energy_to} ${formatNumber(energy, this.hass.locale)} kWh ${cost !== null ? formatNumber(cost, this.hass.locale, { style: "currency", currency: this.hass.config.currency!, }) : ""}
Grid total ${formatNumber(totalGrid, this.hass.locale)} kWh ${formatNumber(totalGridCost, this.hass.locale, { style: "currency", currency: this.hass.config.currency!, })}
${entity ? computeStateName(entity) : source.stat_energy_from} ${formatNumber(energy, this.hass.locale)} ${gasUnit} ${cost !== null ? formatNumber(cost, this.hass.locale, { style: "currency", currency: this.hass.config.currency!, }) : ""}
Gas total ${formatNumber(totalGas, this.hass.locale)} ${gasUnit} ${formatNumber(totalGasCost, this.hass.locale, { style: "currency", currency: this.hass.config.currency!, })}
Total costs ${formatNumber( totalGasCost + totalGridCost, this.hass.locale, { style: "currency", currency: this.hass.config.currency!, } )}
`; } static get styles(): CSSResultGroup { return css` ${unsafeCSS(dataTableStyles)} .mdc-data-table { width: 100%; border: 0; } .mdc-data-table__header-cell, .mdc-data-table__cell { color: var(--primary-text-color); border-bottom-color: var(--divider-color); } .mdc-data-table__row:not(.mdc-data-table__row--selected):hover { background-color: rgba(var(--rgb-primary-text-color), 0.04); } .total { --mdc-typography-body2-font-weight: 500; } .total .mdc-data-table__cell { border-top: 1px solid var(--divider-color); } ha-card { height: 100%; } .card-header { padding-bottom: 0; } .content { padding: 16px; } .has-header { padding-top: 0; } .cell-bullet { width: 32px; padding-right: 0; } .bullet { border-width: 1px; border-style: solid; border-radius: 4px; height: 16px; width: 32px; } `; } } declare global { interface HTMLElementTagNameMap { "hui-energy-sources-table-card": HuiEnergySourcesTableCard; } }