Skip to content

Commit

Permalink
Augment history panel with Long Term Statistics (#18213)
Browse files Browse the repository at this point in the history
Co-authored-by: Bram Kragten <[email protected]>
  • Loading branch information
karwosts and bramkragten authored Nov 28, 2023
1 parent 7727f34 commit b6a7581
Show file tree
Hide file tree
Showing 5 changed files with 294 additions and 8 deletions.
62 changes: 57 additions & 5 deletions src/components/chart/state-history-chart-line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export class StateHistoryChartLine extends LitElement {

@state() private _entityIds: string[] = [];

private _datasetToDataIndex: number[] = [];

@state() private _chartOptions?: ChartOptions;

@state() private _yWidth = 0;
Expand Down Expand Up @@ -81,6 +83,7 @@ export class StateHistoryChartLine extends LitElement {
changedProps.has("showNames") ||
changedProps.has("startTime") ||
changedProps.has("endTime") ||
changedProps.has("unit") ||
changedProps.has("logarithmicScale")
) {
this._chartOptions = {
Expand Down Expand Up @@ -141,15 +144,32 @@ export class StateHistoryChartLine extends LitElement {
plugins: {
tooltip: {
callbacks: {
label: (context) =>
`${context.dataset.label}: ${formatNumber(
label: (context) => {
let label = `${context.dataset.label}: ${formatNumber(
context.parsed.y,
this.hass.locale,
getNumberFormatOptions(
undefined,
this.hass.entities[this._entityIds[context.datasetIndex]]
)
)} ${this.unit}`,
)} ${this.unit}`;
const dataIndex =
this._datasetToDataIndex[context.datasetIndex];
const data = this.data[dataIndex];
if (data.statistics && data.statistics.length > 0) {
const source =
data.states.length === 0 ||
context.parsed.x < data.states[0].last_changed
? `\n${this.hass.localize(
"ui.components.history_charts.source_stats"
)}`
: `\n${this.hass.localize(
"ui.components.history_charts.source_history"
)}`;
label += source;
}
return label;
},
},
},
filler: {
Expand All @@ -171,6 +191,19 @@ export class StateHistoryChartLine extends LitElement {
hitRadius: 50,
},
},
segment: {
borderColor: (context) => {
// render stat data with a slightly transparent line
const dataIndex = this._datasetToDataIndex[context.datasetIndex];
const data = this.data[dataIndex];
return data.statistics &&
data.statistics.length > 0 &&
(data.states.length === 0 ||
context.p0.parsed.x < data.states[0].last_changed)
? this._chartData!.datasets[dataIndex].borderColor + "7F"
: undefined;
},
},
// @ts-expect-error
locale: numberFormatToLocale(this.hass.locale),
onClick: (e: any) => {
Expand Down Expand Up @@ -216,14 +249,15 @@ export class StateHistoryChartLine extends LitElement {
const entityStates = this.data;
const datasets: ChartDataset<"line">[] = [];
const entityIds: string[] = [];
const datasetToDataIndex: number[] = [];
if (entityStates.length === 0) {
return;
}

this._chartTime = new Date();
const endTime = this.endTime;
const names = this.names || {};
entityStates.forEach((states) => {
entityStates.forEach((states, dataIdx) => {
const domain = states.domain;
const name = names[states.entity_id] || states.name;
// array containing [value1, value2, etc]
Expand Down Expand Up @@ -268,6 +302,7 @@ export class StateHistoryChartLine extends LitElement {
data: [],
});
entityIds.push(states.entity_id);
datasetToDataIndex.push(dataIdx);
};

if (
Expand Down Expand Up @@ -474,7 +509,7 @@ export class StateHistoryChartLine extends LitElement {

// Process chart data.
// When state is `unknown`, calculate the value and break the line.
states.states.forEach((entityState) => {
const processData = (entityState: LineChartState) => {
const value = safeParseFloat(entityState.state);
const date = new Date(entityState.last_changed);
if (value !== null && lastNullDate) {
Expand Down Expand Up @@ -503,6 +538,22 @@ export class StateHistoryChartLine extends LitElement {
) {
lastNullDate = date;
}
};

if (states.statistics) {
const stopTime =
!states.states || states.states.length === 0
? 0
: states.states[0].last_changed;
for (let i = 0; i < states.statistics.length; i++) {
if (stopTime && states.statistics[i].last_changed >= stopTime) {
break;
}
processData(states.statistics[i]);
}
}
states.states.forEach((entityState) => {
processData(entityState);
});
if (lastNullDate !== null) {
pushData(lastNullDate, [null]);
Expand All @@ -520,6 +571,7 @@ export class StateHistoryChartLine extends LitElement {
datasets,
};
this._entityIds = entityIds;
this._datasetToDataIndex = datasetToDataIndex;
}
}
customElements.define("state-history-chart-line", StateHistoryChartLine);
Expand Down
94 changes: 94 additions & 0 deletions src/components/ha-date-range-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ import "@material/mwc-list/mwc-list-item";
import { mdiCalendar } from "@mdi/js";
import {
addDays,
addMonths,
addYears,
endOfDay,
endOfWeek,
endOfMonth,
endOfYear,
startOfDay,
startOfWeek,
startOfMonth,
startOfYear,
} from "date-fns";
import {
css,
Expand Down Expand Up @@ -60,6 +66,8 @@ export class HaDateRangePicker extends LitElement {

@property({ type: Boolean }) private minimal = false;

@property({ type: Boolean }) public extendedPresets = false;

@property() public openingDirection?: "right" | "left" | "center" | "inline";

@state() private _calcedOpeningDirection?:
Expand Down Expand Up @@ -132,6 +140,92 @@ export class HaDateRangePicker extends LitElement {
[this.hass.localize(
"ui.components.date-range-picker.ranges.last_week"
)]: [addDays(weekStart, -7), addDays(weekEnd, -7)],
...(this.extendedPresets
? {
[this.hass.localize(
"ui.components.date-range-picker.ranges.this_month"
)]: [
calcDate(
today,
startOfMonth,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
),
calcDate(
today,
endOfMonth,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
),
],
[this.hass.localize(
"ui.components.date-range-picker.ranges.last_month"
)]: [
calcDate(
addMonths(today, -1),
startOfMonth,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
),
calcDate(
addMonths(today, -1),
endOfMonth,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
),
],
[this.hass.localize(
"ui.components.date-range-picker.ranges.this_year"
)]: [
calcDate(
today,
startOfYear,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
),
calcDate(today, endOfYear, this.hass.locale, this.hass.config, {
weekStartsOn,
}),
],
[this.hass.localize(
"ui.components.date-range-picker.ranges.last_year"
)]: [
calcDate(
addYears(today, -1),
startOfYear,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
),
calcDate(
addYears(today, -1),
endOfYear,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
),
],
}
: {}),
};
}
}
Expand Down
1 change: 1 addition & 0 deletions src/data/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export interface LineChartEntity {
name: string;
entity_id: string;
states: LineChartState[];
statistics?: LineChartState[];
}

export interface LineChartUnit {
Expand Down
Loading

0 comments on commit b6a7581

Please sign in to comment.