More statistics validation (#10146)

Co-authored-by: Philip Allgaier <mail@spacegaier.de>
This commit is contained in:
Bram Kragten 2021-10-04 23:21:21 +02:00 committed by GitHub
parent dc3bad56f2
commit 6f4593508b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 246 additions and 44 deletions

View File

@ -77,18 +77,42 @@ export interface StatisticsMetaData {
}
export type StatisticsValidationResult =
| StatisticsValidationResultUnsupportedUnit
| StatisticsValidationResultUnitsChanged;
| StatisticsValidationResultEntityNotRecorded
| StatisticsValidationResultUnsupportedStateClass
| StatisticsValidationResultUnitsChanged
| StatisticsValidationResultUnsupportedUnitMetadata
| StatisticsValidationResultUnsupportedUnitState;
export interface StatisticsValidationResultUnsupportedUnit {
type: "unsupported_unit";
data: { statistic_id: string; device_class: string; state_unit: string };
export interface StatisticsValidationResultEntityNotRecorded {
type: "entity_not_recorded";
data: { statistic_id: string };
}
export interface StatisticsValidationResultUnsupportedStateClass {
type: "unsupported_state_class";
data: { statistic_id: string; state_class: string };
}
export interface StatisticsValidationResultUnitsChanged {
type: "units_changed";
data: { statistic_id: string; state_unit: string; metadata_unit: string };
}
export interface StatisticsValidationResultUnsupportedUnitMetadata {
type: "unsupported_unit_metadata";
data: {
statistic_id: string;
device_class: string;
metadata_unit: string;
supported_unit: string;
};
}
export interface StatisticsValidationResultUnsupportedUnitState {
type: "unsupported_unit_state";
data: { statistic_id: string; device_class: string; metadata_unit: string };
}
export interface StatisticsValidationResults {
[statisticId: string]: StatisticsValidationResult[];
}

View File

@ -17,7 +17,15 @@ import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { showFixStatisticsUnitsChangedDialog } from "./show-dialog-statistics-fix-units-changed";
import { showFixStatisticsUnsupportedUnitMetadataDialog } from "./show-dialog-statistics-fix-unsupported-unit-meta";
const FIX_ISSUES_ORDER = {
entity_not_recorded: 1,
unsupported_unit_state: 2,
unsupported_state_class: 3,
units_changed: 4,
unsupported_unit_metadata: 5,
};
@customElement("developer-tools-statistics")
class HaPanelDevStatistics extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@ -119,48 +127,115 @@ class HaPanelDevStatistics extends LitElement {
validateStatistics(this.hass),
]);
this._data = statisticIds.map((statistic) => ({
...statistic,
state: this.hass.states[statistic.statistic_id],
issues: issues[statistic.statistic_id],
}));
const statsIds = new Set();
this._data = statisticIds.map((statistic) => {
statsIds.add(statistic.statistic_id);
return {
...statistic,
state: this.hass.states[statistic.statistic_id],
issues: issues[statistic.statistic_id],
};
});
Object.keys(issues).forEach((statisticId) => {
if (!statsIds.has(statisticId)) {
this._data.push({
statistic_id: statisticId,
unit_of_measurement: "",
state: this.hass.states[statisticId],
issues: issues[statisticId],
});
}
});
}
private _fixIssue(ev) {
const issue = ev.currentTarget.data[0] as StatisticsValidationResult;
if (issue.type === "unsupported_unit") {
showAlertDialog(this, {
title: "Unsupported unit",
text: html`The unit of your entity is not a supported unit for the
device class of the entity, ${issue.data.device_class}.
<br />Statistics can not be generated until this entity has a
supported unit.<br /><br />If this unit was provided by an
integration, this is a bug. Please report an issue.<br /><br />If you
have set this unit yourself, and want to have statistics generated,
make sure the unit matched the device class. The supported units are
documented in the
<a
href="https://developers.home-assistant.io/docs/core/entity/sensor"
target="_blank"
>
developer documentation</a
>.`,
});
return;
const issues = (ev.currentTarget.data as StatisticsValidationResult[]).sort(
(itemA, itemB) =>
(FIX_ISSUES_ORDER[itemA.type] ?? 99) -
(FIX_ISSUES_ORDER[itemB.type] ?? 99)
);
const issue = issues[0];
switch (issue.type) {
case "entity_not_recorded":
showAlertDialog(this, {
title: "Entity not recorded",
text: html`State changes of this entity are not recorded, therefore,
we can not track long term statistics for it. <br /><br />You
probably excluded this entity, or have just included some
entities.<br /><br />See the
<a
href="https://www.home-assistant.io/integrations/recorder/#configure-filter"
target="_blank"
rel="noreferrer noopener"
>
recorder documentation</a
>
for more information.`,
});
break;
case "unsupported_state_class":
showAlertDialog(this, {
title: "Unsupported state class",
text: html`The state class of this entity, ${issue.data.state_class}
is not supported. <br />Statistics can not be generated until this
entity has a supported state class.<br /><br />If this state class
was provided by an integration, this is a bug. Please report an
issue.<br /><br />If you have set this state class yourself, please
correct it. The different state classes and when to use which can be
found in the
<a
href="https://developers.home-assistant.io/docs/core/entity/sensor/#long-term-statistics"
target="_blank"
rel="noreferrer noopener"
>
developer documentation</a
>.`,
});
break;
case "unsupported_unit_metadata":
showFixStatisticsUnsupportedUnitMetadataDialog(this, {
issue,
fixedCallback: () => {
this._validateStatistics();
},
});
break;
case "unsupported_unit_state":
showAlertDialog(this, {
title: "Unsupported unit",
text: html`The unit of your entity is not a supported unit for the
device class of the entity, ${issue.data.device_class}.
<br />Statistics can not be generated until this entity has a
supported unit.<br /><br />If this unit was provided by an
integration, this is a bug. Please report an issue.<br /><br />If
you have set this unit yourself, and want to have statistics
generated, make sure the unit matches the device class. The
supported units are documented in the
<a
href="https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes"
target="_blank"
rel="noreferrer noopener"
>
developer documentation</a
>.`,
});
break;
case "units_changed":
showFixStatisticsUnitsChangedDialog(this, {
issue,
fixedCallback: () => {
this._validateStatistics();
},
});
break;
default:
showAlertDialog(this, {
title: "Fix issue",
text: "Fixing this issue is not supported yet.",
});
}
if (issue.type === "units_changed") {
showFixStatisticsUnitsChangedDialog(this, {
issue,
fixedCallback: () => {
this._validateStatistics();
},
});
return;
}
showAlertDialog(this, {
title: "Fix issue",
text: "Fixing this issue is not supported yet.",
});
}
static get styles(): CSSResultGroup {

View File

@ -0,0 +1,79 @@
import "@material/mwc-button/mwc-button";
import { LitElement, TemplateResult, html, CSSResultGroup } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-dialog";
import { fireEvent } from "../../../common/dom/fire_event";
import { haStyle, haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { updateStatisticsMetadata } from "../../../data/history";
import "../../../components/ha-formfield";
import "../../../components/ha-radio";
import { DialogStatisticsUnsupportedUnitMetaParams } from "./show-dialog-statistics-fix-unsupported-unit-meta";
@customElement("dialog-statistics-fix-unsupported-unit-meta")
export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _params?: DialogStatisticsUnsupportedUnitMetaParams;
public showDialog(params: DialogStatisticsUnsupportedUnitMetaParams): void {
this._params = params;
}
public closeDialog(): void {
this._params = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected render(): TemplateResult | void {
if (!this._params) {
return html``;
}
return html`
<ha-dialog
open
@closed=${this.closeDialog}
heading="Unsupported unit in recorded statistics"
>
<p>
The unit of the statistics in your database for this entity is not a
supported unit for the device class of the entity,
${this._params.issue.data.device_class}. It should be
${this._params.issue.data.supported_unit}.
</p>
<p>
Do you want to update the unit of the history statistics to
${this._params.issue.data.supported_unit}?
</p>
<mwc-button slot="primaryAction" @click=${this._fixIssue}>
Fix
</mwc-button>
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
${this.hass.localize("ui.common.close")}
</mwc-button>
</ha-dialog>
`;
}
private async _fixIssue(): Promise<void> {
await updateStatisticsMetadata(
this.hass,
this._params!.issue.data.statistic_id,
this._params!.issue.data.supported_unit
);
this._params?.fixedCallback();
this.closeDialog();
}
static get styles(): CSSResultGroup {
return [haStyle, haStyleDialog];
}
}
declare global {
interface HTMLElementTagNameMap {
"dialog-statistics-fix-unsupported-unit-meta": DialogStatisticsFixUnsupportedUnitMetadata;
}
}

View File

@ -0,0 +1,21 @@
import { fireEvent } from "../../../common/dom/fire_event";
import { StatisticsValidationResultUnsupportedUnitMetadata } from "../../../data/history";
export const loadFixUnsupportedUnitMetaDialog = () =>
import("./dialog-statistics-fix-unsupported-unit-meta");
export interface DialogStatisticsUnsupportedUnitMetaParams {
issue: StatisticsValidationResultUnsupportedUnitMetadata;
fixedCallback: () => void;
}
export const showFixStatisticsUnsupportedUnitMetadataDialog = (
element: HTMLElement,
detailParams: DialogStatisticsUnsupportedUnitMetaParams
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-statistics-fix-unsupported-unit-meta",
dialogImport: loadFixUnsupportedUnitMetaDialog,
dialogParams: detailParams,
});
};

View File

@ -3728,7 +3728,10 @@
"issue": "Issue",
"issues": {
"units_changed": "The unit of this entity changed from ''{metadata_unit}'' to ''{state_unit}''.",
"unsupported_unit": "The unit (''{state_unit}'') of this entity doesn't match a unit of device class ''{device_class}''."
"unsupported_unit_state": "The unit (''{state_unit}'') of this entity doesn't match a unit of device class ''{device_class}''.",
"unsupported_unit_metadata": "The unit (''{state_unit}'') of the recorded statistics doesn't match a unit of device class ''{device_class}''.",
"unsupported_state_class": "The state class ''{state_class}'' of this entity is not supported.",
"entity_not_recorded": "This entity is excluded from being recorded."
},
"fix_issue": {
"units_changed": {