Improve handling of units in energy dashboard (#13454)

This commit is contained in:
Erik Montnemery 2022-08-31 11:30:50 +02:00 committed by GitHub
parent 9b2dcbdb59
commit 1e19799da9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 68 additions and 51 deletions

View File

@ -243,8 +243,8 @@ class StatisticsChart extends LitElement {
if (!this.unit) { if (!this.unit) {
if (unit === undefined) { if (unit === undefined) {
unit = meta?.unit_of_measurement; unit = meta?.display_unit_of_measurement;
} else if (unit !== meta?.unit_of_measurement) { } else if (unit !== meta?.display_unit_of_measurement) {
unit = null; unit = null;
} }
} }

View File

@ -31,12 +31,23 @@ export class HaStatisticPicker extends LitElement {
@property({ type: Boolean }) public disabled?: boolean; @property({ type: Boolean }) public disabled?: boolean;
/** /**
* Show only statistics with these unit of measuments. * Show only statistics natively stored with these units of measurements.
* @type {Array} * @type {Array}
* @attr include-unit-of-measurement * @attr include-statistics-unit-of-measurement
*/ */
@property({ type: Array, attribute: "include-unit-of-measurement" }) @property({
public includeUnitOfMeasurement?: string[]; type: Array,
attribute: "include-statistics-unit-of-measurement",
})
public includeStatisticsUnitOfMeasurement?: string[];
/**
* Show only statistics displayed with these units of measurements.
* @type {Array}
* @attr include-display-unit-of-measurement
*/
@property({ type: Array, attribute: "include-display-unit-of-measurement" })
public includeDisplayUnitOfMeasurement?: string[];
/** /**
* Show only statistics with these device classes. * Show only statistics with these device classes.
@ -86,7 +97,8 @@ export class HaStatisticPicker extends LitElement {
private _getStatistics = memoizeOne( private _getStatistics = memoizeOne(
( (
statisticIds: StatisticsMetaData[], statisticIds: StatisticsMetaData[],
includeUnitOfMeasurement?: string[], includeStatisticsUnitOfMeasurement?: string[],
includeDisplayUnitOfMeasurement?: string[],
includeDeviceClasses?: string[], includeDeviceClasses?: string[],
entitiesOnly?: boolean entitiesOnly?: boolean
): Array<{ id: string; name: string; state?: HassEntity }> => { ): Array<{ id: string; name: string; state?: HassEntity }> => {
@ -101,9 +113,18 @@ export class HaStatisticPicker extends LitElement {
]; ];
} }
if (includeUnitOfMeasurement) { if (includeStatisticsUnitOfMeasurement) {
statisticIds = statisticIds.filter((meta) => statisticIds = statisticIds.filter((meta) =>
includeUnitOfMeasurement.includes(meta.unit_of_measurement) includeStatisticsUnitOfMeasurement.includes(
meta.statistics_unit_of_measurement
)
);
}
if (includeDisplayUnitOfMeasurement) {
statisticIds = statisticIds.filter((meta) =>
includeDisplayUnitOfMeasurement.includes(
meta.display_unit_of_measurement
)
); );
} }
@ -184,7 +205,8 @@ export class HaStatisticPicker extends LitElement {
if (this.hasUpdated) { if (this.hasUpdated) {
(this.comboBox as any).items = this._getStatistics( (this.comboBox as any).items = this._getStatistics(
this.statisticIds!, this.statisticIds!,
this.includeUnitOfMeasurement, this.includeStatisticsUnitOfMeasurement,
this.includeDisplayUnitOfMeasurement,
this.includeDeviceClasses, this.includeDeviceClasses,
this.entitiesOnly this.entitiesOnly
); );
@ -192,7 +214,8 @@ export class HaStatisticPicker extends LitElement {
this.updateComplete.then(() => { this.updateComplete.then(() => {
(this.comboBox as any).items = this._getStatistics( (this.comboBox as any).items = this._getStatistics(
this.statisticIds!, this.statisticIds!,
this.includeUnitOfMeasurement, this.includeStatisticsUnitOfMeasurement,
this.includeDisplayUnitOfMeasurement,
this.includeDeviceClasses, this.includeDeviceClasses,
this.entitiesOnly this.entitiesOnly
); );

View File

@ -597,7 +597,7 @@ export const getEnergySolarForecasts = (hass: HomeAssistant) =>
type: "energy/solar_forecast", type: "energy/solar_forecast",
}); });
export const ENERGY_GAS_VOLUME_UNITS = ["m³", "ft³"]; export const ENERGY_GAS_VOLUME_UNITS = ["m³"];
export const ENERGY_GAS_ENERGY_UNITS = ["kWh"]; export const ENERGY_GAS_ENERGY_UNITS = ["kWh"];
export const ENERGY_GAS_UNITS = [ export const ENERGY_GAS_UNITS = [
...ENERGY_GAS_VOLUME_UNITS, ...ENERGY_GAS_VOLUME_UNITS,
@ -607,18 +607,21 @@ export const ENERGY_GAS_UNITS = [
export type EnergyGasUnit = "volume" | "energy"; export type EnergyGasUnit = "volume" | "energy";
export const getEnergyGasUnitCategory = ( export const getEnergyGasUnitCategory = (
hass: HomeAssistant, prefs: EnergyPreferences,
prefs: EnergyPreferences statisticsMetaData: Record<string, StatisticsMetaData> = {},
excludeSource?: string
): EnergyGasUnit | undefined => { ): EnergyGasUnit | undefined => {
for (const source of prefs.energy_sources) { for (const source of prefs.energy_sources) {
if (source.type !== "gas") { if (source.type !== "gas") {
continue; continue;
} }
if (excludeSource && excludeSource === source.stat_energy_from) {
const entity = hass.states[source.stat_energy_from]; continue;
if (entity) { }
const statisticIdWithMeta = statisticsMetaData[source.stat_energy_from];
if (statisticIdWithMeta) {
return ENERGY_GAS_VOLUME_UNITS.includes( return ENERGY_GAS_VOLUME_UNITS.includes(
entity.attributes.unit_of_measurement! statisticIdWithMeta.display_unit_of_measurement
) )
? "volume" ? "volume"
: "energy"; : "energy";
@ -628,7 +631,6 @@ export const getEnergyGasUnitCategory = (
}; };
export const getEnergyGasUnit = ( export const getEnergyGasUnit = (
hass: HomeAssistant,
prefs: EnergyPreferences, prefs: EnergyPreferences,
statisticsMetaData: Record<string, StatisticsMetaData> = {} statisticsMetaData: Record<string, StatisticsMetaData> = {}
): string | undefined => { ): string | undefined => {
@ -636,18 +638,9 @@ export const getEnergyGasUnit = (
if (source.type !== "gas") { if (source.type !== "gas") {
continue; continue;
} }
const entity = hass.states[source.stat_energy_from];
if (entity?.attributes.unit_of_measurement) {
// Wh is normalized to kWh by stats generation
return entity.attributes.unit_of_measurement === "Wh"
? "kWh"
: entity.attributes.unit_of_measurement;
}
const statisticIdWithMeta = statisticsMetaData[source.stat_energy_from]; const statisticIdWithMeta = statisticsMetaData[source.stat_energy_from];
if (statisticIdWithMeta?.unit_of_measurement) { if (statisticIdWithMeta?.display_unit_of_measurement) {
return statisticIdWithMeta.unit_of_measurement === "Wh" return statisticIdWithMeta.display_unit_of_measurement;
? "kWh"
: statisticIdWithMeta.unit_of_measurement;
} }
} }
return undefined; return undefined;

View File

@ -82,7 +82,8 @@ export interface StatisticValue {
} }
export interface StatisticsMetaData { export interface StatisticsMetaData {
unit_of_measurement: string; display_unit_of_measurement: string;
statistics_unit_of_measurement: string;
statistic_id: string; statistic_id: string;
source: string; source: string;
name?: string | null; name?: string | null;

View File

@ -133,7 +133,7 @@ export class EnergyGasSettings extends LitElement {
private _addSource() { private _addSource() {
showEnergySettingsGasDialog(this, { showEnergySettingsGasDialog(this, {
unit: getEnergyGasUnitCategory(this.hass, this.preferences), unit: getEnergyGasUnitCategory(this.preferences, this.statsMetadata),
saveCallback: async (source) => { saveCallback: async (source) => {
delete source.unit_of_measurement; delete source.unit_of_measurement;
await this._savePreferences({ await this._savePreferences({
@ -149,7 +149,11 @@ export class EnergyGasSettings extends LitElement {
ev.currentTarget.closest(".row").source; ev.currentTarget.closest(".row").source;
showEnergySettingsGasDialog(this, { showEnergySettingsGasDialog(this, {
source: { ...origSource }, source: { ...origSource },
unit: getEnergyGasUnitCategory(this.hass, this.preferences), unit: getEnergyGasUnitCategory(
this.preferences,
this.statsMetadata,
origSource.stat_energy_from
),
saveCallback: async (newSource) => { saveCallback: async (newSource) => {
await this._savePreferences({ await this._savePreferences({
...this.preferences, ...this.preferences,

View File

@ -67,7 +67,7 @@ export class DialogEnergyBatterySettings
<ha-statistic-picker <ha-statistic-picker
.hass=${this.hass} .hass=${this.hass}
.includeUnitOfMeasurement=${energyUnits} .includeStatisticsUnitOfMeasurement=${energyUnits}
.includeDeviceClasses=${energyDeviceClasses} .includeDeviceClasses=${energyDeviceClasses}
.value=${this._source.stat_energy_to} .value=${this._source.stat_energy_to}
.label=${this.hass.localize( .label=${this.hass.localize(
@ -79,7 +79,7 @@ export class DialogEnergyBatterySettings
<ha-statistic-picker <ha-statistic-picker
.hass=${this.hass} .hass=${this.hass}
.includeUnitOfMeasurement=${energyUnits} .includeStatisticsUnitOfMeasurement=${energyUnits}
.includeDeviceClasses=${energyDeviceClasses} .includeDeviceClasses=${energyDeviceClasses}
.value=${this._source.stat_energy_from} .value=${this._source.stat_energy_from}
.label=${this.hass.localize( .label=${this.hass.localize(

View File

@ -69,7 +69,7 @@ export class DialogEnergyDeviceSettings
<ha-statistic-picker <ha-statistic-picker
.hass=${this.hass} .hass=${this.hass}
.includeUnitOfMeasurement=${energyUnits} .includeStatisticsUnitOfMeasurement=${energyUnits}
.includeDeviceClasses=${energyDeviceClasses} .includeDeviceClasses=${energyDeviceClasses}
.label=${this.hass.localize( .label=${this.hass.localize(
"ui.panel.config.energy.device_consumption.dialog.device_consumption_energy" "ui.panel.config.energy.device_consumption.dialog.device_consumption_energy"

View File

@ -90,7 +90,7 @@ export class DialogEnergyGasSettings
<ha-statistic-picker <ha-statistic-picker
.hass=${this.hass} .hass=${this.hass}
.includeUnitOfMeasurement=${this._params.unit === undefined .includeStatisticsUnitOfMeasurement=${this._params.unit === undefined
? ENERGY_GAS_UNITS ? ENERGY_GAS_UNITS
: this._params.unit === "energy" : this._params.unit === "energy"
? ENERGY_GAS_ENERGY_UNITS ? ENERGY_GAS_ENERGY_UNITS

View File

@ -93,7 +93,7 @@ export class DialogEnergyGridFlowSettings
<ha-statistic-picker <ha-statistic-picker
.hass=${this.hass} .hass=${this.hass}
.includeUnitOfMeasurement=${energyUnits} .includeStatisticsUnitOfMeasurement=${energyUnits}
.includeDeviceClasses=${energyDeviceClasses} .includeDeviceClasses=${energyDeviceClasses}
.value=${this._source[ .value=${this._source[
this._params.direction === "from" this._params.direction === "from"

View File

@ -79,7 +79,7 @@ export class DialogEnergySolarSettings
<ha-statistic-picker <ha-statistic-picker
.hass=${this.hass} .hass=${this.hass}
.includeUnitOfMeasurement=${energyUnits} .includeStatisticsUnitOfMeasurement=${energyUnits}
.includeDeviceClasses=${energyDeviceClasses} .includeDeviceClasses=${energyDeviceClasses}
.value=${this._source.stat_energy_from} .value=${this._source.stat_energy_from}
.label=${this.hass.localize( .label=${this.hass.localize(

View File

@ -211,7 +211,8 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
) { ) {
this._data.push({ this._data.push({
statistic_id: statisticId, statistic_id: statisticId,
unit_of_measurement: "", statistics_unit_of_measurement: "",
display_unit_of_measurement: "",
source: "", source: "",
state: this.hass.states[statisticId], state: this.hass.states[statisticId],
issues: issues[statisticId], issues: issues[statisticId],

View File

@ -135,7 +135,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
} else { } else {
const data = const data =
this._stats5min.length >= 2 ? this._stats5min : this._statsHour; this._stats5min.length >= 2 ? this._stats5min : this._statsHour;
const unit = this._params!.statistic.unit_of_measurement; const unit = this._params!.statistic.display_unit_of_measurement;
const rows: TemplateResult[] = []; const rows: TemplateResult[] = [];
for (let i = 1; i < data.length; i++) { for (let i = 1; i < data.length; i++) {
const stat = data[i]; const stat = data[i];
@ -221,7 +221,7 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
label="New Value" label="New Value"
.hass=${this.hass} .hass=${this.hass}
.selector=${this._amountSelector( .selector=${this._amountSelector(
this._params!.statistic.unit_of_measurement this._params!.statistic.display_unit_of_measurement
)} )}
.value=${this._amount} .value=${this._amount}
.disabled=${this._busy} .disabled=${this._busy}

View File

@ -315,11 +315,8 @@ class HuiEnergyDistrubutionCard
${formatNumber(gasUsage || 0, this.hass.locale, { ${formatNumber(gasUsage || 0, this.hass.locale, {
maximumFractionDigits: 1, maximumFractionDigits: 1,
})} })}
${getEnergyGasUnit( ${getEnergyGasUnit(prefs, this._data.statsMetadata) ||
this.hass, "m³"}
prefs,
this._data.statsMetadata
) || "m³"}
</div> </div>
<svg width="80" height="30"> <svg width="80" height="30">
<path d="M40 0 v30" id="gas" /> <path d="M40 0 v30" id="gas" />

View File

@ -274,8 +274,7 @@ export class HuiEnergyGasGraphCard
) as GasSourceTypeEnergyPreference[]; ) as GasSourceTypeEnergyPreference[];
this._unit = this._unit =
getEnergyGasUnit(this.hass, energyData.prefs, energyData.statsMetadata) || getEnergyGasUnit(energyData.prefs, energyData.statsMetadata) || "m³";
"m³";
const datasets: ChartDataset<"bar", ScatterDataPoint[]>[] = []; const datasets: ChartDataset<"bar", ScatterDataPoint[]>[] = [];

View File

@ -131,8 +131,7 @@ export class HuiEnergySourcesTableCard
); );
const gasUnit = const gasUnit =
getEnergyGasUnit(this.hass, this._data.prefs, this._data.statsMetadata) || getEnergyGasUnit(this._data.prefs, this._data.statsMetadata) || "";
"";
const compare = this._data.statsCompare !== undefined; const compare = this._data.statsCompare !== undefined;