Add change option to statistics chart (#14396)

This commit is contained in:
Bram Kragten 2022-11-16 18:09:54 +01:00 committed by GitHub
parent c5ec1797f6
commit 185d2f1d52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 38 deletions

View File

@ -32,7 +32,7 @@ import {
import type { HomeAssistant } from "../../types"; import type { HomeAssistant } from "../../types";
import "./ha-chart-base"; import "./ha-chart-base";
export type ExtendedStatisticType = StatisticType | "state"; export type ExtendedStatisticType = StatisticType | "state" | "change";
export const statTypeMap: Record<ExtendedStatisticType, StatisticType> = { export const statTypeMap: Record<ExtendedStatisticType, StatisticType> = {
mean: "mean", mean: "mean",
@ -40,7 +40,9 @@ export const statTypeMap: Record<ExtendedStatisticType, StatisticType> = {
max: "max", max: "max",
sum: "sum", sum: "sum",
state: "sum", state: "sum",
change: "sum",
}; };
@customElement("statistics-chart") @customElement("statistics-chart")
class StatisticsChart extends LitElement { class StatisticsChart extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@ -361,6 +363,7 @@ class StatisticsChart extends LitElement {
let prevDate: Date | null = null; let prevDate: Date | null = null;
// Process chart data. // Process chart data.
let firstSum: number | null = null;
let prevSum: number | null = null; let prevSum: number | null = null;
stats.forEach((stat) => { stats.forEach((stat) => {
const date = new Date(stat.start); const date = new Date(stat.start);
@ -372,12 +375,19 @@ class StatisticsChart extends LitElement {
statTypes.forEach((type) => { statTypes.forEach((type) => {
let val: number | null; let val: number | null;
if (type === "sum") { if (type === "sum") {
if (prevSum === null) { if (firstSum === null) {
val = 0; val = 0;
prevSum = stat.sum; firstSum = stat.sum;
} else { } else {
val = (stat.sum || 0) - prevSum; val = (stat.sum || 0) - firstSum;
} }
} else if (type === "change") {
if (prevSum === null) {
prevSum = stat.sum;
return;
}
val = (stat.sum || 0) - prevSum;
prevSum = stat.sum;
} else { } else {
val = stat[type]; val = stat[type];
} }
@ -386,9 +396,6 @@ class StatisticsChart extends LitElement {
pushData(date, dataValues); pushData(date, dataValues);
}); });
// Add an entry for final values
pushData(endTime, prevValues);
// Concat two arrays // Concat two arrays
Array.prototype.push.apply(totalDataSets, statDataSets); Array.prototype.push.apply(totalDataSets, statDataSets);
}); });

View File

@ -89,23 +89,25 @@ export class HaSelectSelector extends LitElement {
!this.value || this.value === "" ? [] : (this.value as string[]); !this.value || this.value === "" ? [] : (this.value as string[]);
return html` return html`
<ha-chip-set> ${value?.length
${value?.map( ? html`<ha-chip-set>
(item, idx) => ${value.map(
html` (item, idx) =>
<ha-chip hasTrailingIcon> html`
${options.find((option) => option.value === item)?.label || <ha-chip hasTrailingIcon>
item} ${options.find((option) => option.value === item)
<ha-svg-icon ?.label || item}
slot="trailing-icon" <ha-svg-icon
.path=${mdiClose} slot="trailing-icon"
.idx=${idx} .path=${mdiClose}
@click=${this._removeItem} .idx=${idx}
></ha-svg-icon> @click=${this._removeItem}
</ha-chip> ></ha-svg-icon>
` </ha-chip>
)} `
</ha-chip-set> )}
</ha-chip-set>`
: ""}
<ha-combo-box <ha-combo-box
item-value-path="value" item-value-path="value"
@ -116,7 +118,7 @@ export class HaSelectSelector extends LitElement {
.disabled=${this.disabled} .disabled=${this.disabled}
.required=${this.required && !value.length} .required=${this.required && !value.length}
.value=${this._filter} .value=${this._filter}
.items=${options.filter( .filteredItems=${options.filter(
(option) => !option.disabled && !value?.includes(option.value) (option) => !option.disabled && !value?.includes(option.value)
)} )}
@filter-changed=${this._filterChanged} @filter-changed=${this._filterChanged}

View File

@ -1,3 +1,4 @@
import { HassEntity } from "home-assistant-js-websocket";
import { import {
css, css,
CSSResultGroup, CSSResultGroup,
@ -18,6 +19,7 @@ import {
StatisticsMetaData, StatisticsMetaData,
} from "../../../data/recorder"; } from "../../../data/recorder";
import { HomeAssistant } from "../../../types"; import { HomeAssistant } from "../../../types";
import { findEntities } from "../common/find-entities";
import { hasConfigOrEntitiesChanged } from "../common/has-changed"; import { hasConfigOrEntitiesChanged } from "../common/has-changed";
import { processConfigEntities } from "../common/process-config-entities"; import { processConfigEntities } from "../common/process-config-entities";
import { LovelaceCard } from "../types"; import { LovelaceCard } from "../types";
@ -30,8 +32,25 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard {
return document.createElement("hui-statistics-graph-card-editor"); return document.createElement("hui-statistics-graph-card-editor");
} }
public static getStubConfig(): StatisticsGraphCardConfig { public static getStubConfig(
return { type: "statistics-graph", entities: [] }; hass: HomeAssistant,
entities: string[],
entitiesFill: string[]
): StatisticsGraphCardConfig {
const includeDomains = ["sensor"];
const maxEntities = 1;
const foundEntities = findEntities(
hass,
maxEntities,
entities,
entitiesFill,
includeDomains,
(stateObj: HassEntity) => "state_class" in stateObj.attributes
);
return {
type: "statistics-graph",
entities: foundEntities.length ? [foundEntities[0]] : [],
};
} }
@property({ attribute: false }) public hass?: HomeAssistant; @property({ attribute: false }) public hass?: HomeAssistant;

View File

@ -23,7 +23,10 @@ import { fireEvent } from "../../../../common/dom/fire_event";
import { ensureArray } from "../../../../common/ensure-array"; import { ensureArray } from "../../../../common/ensure-array";
import type { LocalizeFunc } from "../../../../common/translations/localize"; import type { LocalizeFunc } from "../../../../common/translations/localize";
import { deepEqual } from "../../../../common/util/deep-equal"; import { deepEqual } from "../../../../common/util/deep-equal";
import { statTypeMap } from "../../../../components/chart/statistics-chart"; import {
ExtendedStatisticType,
statTypeMap,
} from "../../../../components/chart/statistics-chart";
import "../../../../components/entity/ha-statistics-picker"; import "../../../../components/entity/ha-statistics-picker";
import "../../../../components/ha-form/ha-form"; import "../../../../components/ha-form/ha-form";
import type { HaFormSchema } from "../../../../components/ha-form/types"; import type { HaFormSchema } from "../../../../components/ha-form/types";
@ -44,6 +47,7 @@ import { entitiesConfigStruct } from "../structs/entities-struct";
const statTypeStruct = union([ const statTypeStruct = union([
literal("state"), literal("state"),
literal("sum"), literal("sum"),
literal("change"),
literal("min"), literal("min"),
literal("max"), literal("max"),
literal("mean"), literal("mean"),
@ -71,7 +75,14 @@ const cardConfigStruct = assign(
); );
const periods = ["5minute", "hour", "day", "week", "month"] as const; const periods = ["5minute", "hour", "day", "week", "month"] as const;
const stat_types = ["mean", "min", "max", "sum", "state"] as const; const stat_types = [
"mean",
"min",
"max",
"sum",
"state",
"change",
] as ExtendedStatisticType[];
@customElement("hui-statistics-graph-card-editor") @customElement("hui-statistics-graph-card-editor")
export class HuiStatisticsGraphCardEditor export class HuiStatisticsGraphCardEditor
@ -165,6 +176,7 @@ export class HuiStatisticsGraphCardEditor
selector: { selector: {
select: { select: {
multiple: true, multiple: true,
mode: "list",
options: stat_types.map((stat_type) => ({ options: stat_types.map((stat_type) => ({
value: stat_type, value: stat_type,
label: localize( label: localize(
@ -222,13 +234,13 @@ export class HuiStatisticsGraphCardEditor
this._metaDatas this._metaDatas
); );
const configured_stat_types = this._config!.stat_types const configured_stat_types = this._config!.stat_types
? Array.isArray(this._config!.stat_types) ? ensureArray(this._config.stat_types)
? this._config!.stat_types : stat_types.filter(
: [this._config!.stat_types] (stat_type) =>
: stat_types.filter((stat_type) => stat_type !== "change" &&
this._metaDatas?.every((metaData) => this._metaDatas?.every((metaData) =>
statisticsMetaHasType(metaData, statTypeMap[stat_type]) statisticsMetaHasType(metaData, statTypeMap[stat_type])
) )
); );
const data = { const data = {
chart_type: "line", chart_type: "line",

View File

@ -525,7 +525,8 @@
"max": "max", "max": "max",
"mean": "mean", "mean": "mean",
"state": "state", "state": "state",
"sum": "sum" "sum": "sum",
"change": "change"
} }
}, },
"service-picker": { "service-picker": {
@ -4063,7 +4064,8 @@
"min": "Min", "min": "Min",
"max": "Max", "max": "Max",
"state": "State", "state": "State",
"sum": "Sum (change during period)" "sum": "Sum",
"change": "Change"
}, },
"chart_type": "Chart type", "chart_type": "Chart type",
"periods": { "periods": {