diff --git a/src/data/recorder.ts b/src/data/recorder.ts
index 23b63a6d1cb4..f4ab0cb80498 100644
--- a/src/data/recorder.ts
+++ b/src/data/recorder.ts
@@ -47,6 +47,14 @@ export interface StatisticsMetaData {
unit_class: string | null;
}
+export const STATISTIC_TYPES: StatisticsValidationResult["type"][] = [
+ "entity_not_recorded",
+ "entity_no_longer_recorded",
+ "unsupported_state_class",
+ "units_changed",
+ "no_state",
+];
+
export type StatisticsValidationResult =
| StatisticsValidationResultNoState
| StatisticsValidationResultEntityNotRecorded
diff --git a/src/panels/config/repairs/ha-config-repairs.ts b/src/panels/config/repairs/ha-config-repairs.ts
index 4e46d47741ab..3446fb305b21 100644
--- a/src/panels/config/repairs/ha-config-repairs.ts
+++ b/src/panels/config/repairs/ha-config-repairs.ts
@@ -12,11 +12,16 @@ import {
fetchRepairsIssueData,
type RepairsIssue,
} from "../../../data/repairs";
+import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
import type { HomeAssistant } from "../../../types";
import { brandsUrl } from "../../../util/brands-url";
+import { fixStatisticsIssue } from "../../developer-tools/statistics/fix-statistics";
import { showRepairsFlowDialog } from "./show-dialog-repair-flow";
import { showRepairsIssueDialog } from "./show-repair-issue-dialog";
-import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
+import {
+ STATISTIC_TYPES,
+ StatisticsValidationResult,
+} from "../../../data/recorder";
@customElement("ha-config-repairs")
class HaConfigRepairs extends LitElement {
@@ -130,6 +135,31 @@ class HaConfigRepairs extends LitElement {
continueFlowId: data.issue_data.flow_id as string,
});
}
+ } else if (
+ issue.domain === "sensor" &&
+ issue.translation_key &&
+ STATISTIC_TYPES.includes(issue.translation_key as any)
+ ) {
+ const localize =
+ await this.hass.loadFragmentTranslation("developer-tools");
+ const data = await fetchRepairsIssueData(
+ this.hass.connection,
+ issue.domain,
+ issue.issue_id
+ );
+ if ("issue_type" in data.issue_data) {
+ await fixStatisticsIssue(
+ this,
+ this.hass,
+ localize || this.hass.localize,
+ {
+ type: data.issue_data
+ .issue_type as StatisticsValidationResult["type"],
+ data: data.issue_data as any,
+ }
+ );
+ this.hass.callWS({ type: "recorder/update_statistics_issues" });
+ }
} else {
showRepairsIssueDialog(this, {
issue,
diff --git a/src/panels/developer-tools/statistics/developer-tools-statistics.ts b/src/panels/developer-tools/statistics/developer-tools-statistics.ts
index 8d40dc0b42a9..a169eeb1799a 100644
--- a/src/panels/developer-tools/statistics/developer-tools-statistics.ts
+++ b/src/panels/developer-tools/statistics/developer-tools-statistics.ts
@@ -5,28 +5,22 @@ import { CSSResultGroup, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
-import { LocalizeFunc } from "../../../common/translations/localize";
import { computeStateName } from "../../../common/entity/compute_state_name";
+import { LocalizeFunc } from "../../../common/translations/localize";
import "../../../components/data-table/ha-data-table";
import type { DataTableColumnContainer } from "../../../components/data-table/ha-data-table";
import { subscribeEntityRegistry } from "../../../data/entity_registry";
import {
- clearStatistics,
getStatisticIds,
StatisticsMetaData,
StatisticsValidationResult,
validateStatistics,
} from "../../../data/recorder";
-import {
- showAlertDialog,
- showConfirmationDialog,
-} from "../../../dialogs/generic/show-dialog-box";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
+import { fixStatisticsIssue } from "./fix-statistics";
import { showStatisticsAdjustSumDialog } from "./show-dialog-statistics-adjust-sum";
-import { showFixStatisticsUnitsChangedDialog } from "./show-dialog-statistics-fix-units-changed";
-import { documentationUrl } from "../../../util/documentation-url";
const FIX_ISSUES_ORDER = {
no_state: 0,
@@ -264,162 +258,30 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
});
}
- private _fixIssue = (ev) => {
+ private _fixIssue = async (ev) => {
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 "no_state":
- showConfirmationDialog(this, {
- title: this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.no_state.title"
- ),
- text: html`${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.no_state.info_text_1"
- )}
${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.no_state.info_text_2",
- { statistic_id: issue.data.statistic_id }
- )}`,
- confirmText: this.hass.localize("ui.common.delete"),
- destructive: true,
- confirm: async () => {
- await clearStatistics(this.hass, [issue.data.statistic_id]);
- this._deletedStatistics.add(issue.data.statistic_id);
- this._validateStatistics();
- },
- });
- break;
- case "entity_not_recorded":
- showAlertDialog(this, {
- title: this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.title"
- ),
- text: html`${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_1"
- )}
${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_2"
- )}
-
- ${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_3_link"
- )}`,
- });
- break;
- case "entity_no_longer_recorded":
- showConfirmationDialog(this, {
- title: this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.title"
- ),
- text: html`${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_1"
- )}
- ${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_2"
- )}
-
- ${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_3_link"
- )}
- ${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_4"
- )}`,
- confirmText: this.hass.localize("ui.common.delete"),
- destructive: true,
- confirm: async () => {
- await clearStatistics(this.hass, [issue.data.statistic_id]);
- this._deletedStatistics.add(issue.data.statistic_id);
- this._validateStatistics();
- },
- });
- break;
- case "unsupported_state_class":
- showConfirmationDialog(this, {
- title: this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.unsupported_state_class.title"
- ),
- text: html`${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.unsupported_state_class.info_text_1",
- { state_class: issue.data.state_class }
- )}
- ${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.unsupported_state_class.info_text_2"
- )}
-
- ${this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.unsupported_state_class.info_text_6",
- { statistic_id: issue.data.statistic_id }
- )}`,
- confirmText: this.hass.localize("ui.common.delete"),
- destructive: true,
- confirm: async () => {
- await clearStatistics(this.hass, [issue.data.statistic_id]);
- this._deletedStatistics.add(issue.data.statistic_id);
- this._validateStatistics();
- },
- });
- break;
- case "units_changed":
- showFixStatisticsUnitsChangedDialog(this, {
- issue,
- fixedCallback: () => {
- this._validateStatistics();
- },
- });
- break;
- default:
- showAlertDialog(this, {
- title: this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.no_support.title"
- ),
- text: this.hass.localize(
- "ui.panel.developer-tools.tabs.statistics.fix_issue.no_support.info_text_1"
- ),
- });
+ const result = await fixStatisticsIssue(
+ this,
+ this.hass,
+ this.hass.localize,
+ issue
+ );
+ if (
+ result &&
+ [
+ "no_state",
+ "entity_no_longer_recorded",
+ "unsupported_state_class",
+ ].includes(issue.type)
+ ) {
+ this._deletedStatistics.add(issue.data.statistic_id);
}
+ this._validateStatistics();
};
static get styles(): CSSResultGroup {
diff --git a/src/panels/developer-tools/statistics/dialog-statistics-fix-units-changed.ts b/src/panels/developer-tools/statistics/dialog-statistics-fix-units-changed.ts
index 682fa58b2cbe..e2bb70720898 100644
--- a/src/panels/developer-tools/statistics/dialog-statistics-fix-units-changed.ts
+++ b/src/panels/developer-tools/statistics/dialog-statistics-fix-units-changed.ts
@@ -7,6 +7,7 @@ import "../../../components/ha-formfield";
import "../../../components/ha-radio";
import {
clearStatistics,
+ getStatisticLabel,
updateStatisticsMetadata,
} from "../../../data/recorder";
import { haStyle, haStyleDialog } from "../../../resources/styles";
@@ -27,6 +28,10 @@ export class DialogStatisticsFixUnitsChanged extends LitElement {
}
public closeDialog(): void {
+ this._cancel();
+ }
+
+ private _closeDialog(): void {
this._params = undefined;
this._action = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
@@ -40,7 +45,9 @@ export class DialogStatisticsFixUnitsChanged extends LitElement {
return html`
-
+
${this.hass.localize("ui.common.close")}
@@ -109,6 +121,11 @@ export class DialogStatisticsFixUnitsChanged extends LitElement {
this._action = ev.target.value;
}
+ private _cancel(): void {
+ this._params?.cancelCallback!();
+ this._closeDialog();
+ }
+
private async _fixIssue(): Promise {
if (this._action === "clear") {
await clearStatistics(this.hass, [this._params!.issue.data.statistic_id]);
@@ -119,8 +136,8 @@ export class DialogStatisticsFixUnitsChanged extends LitElement {
this._params!.issue.data.state_unit
);
}
- this._params?.fixedCallback();
- this.closeDialog();
+ this._params?.fixedCallback!();
+ this._closeDialog();
}
static get styles(): CSSResultGroup {
diff --git a/src/panels/developer-tools/statistics/fix-statistics.ts b/src/panels/developer-tools/statistics/fix-statistics.ts
new file mode 100644
index 000000000000..6b2d6a7affca
--- /dev/null
+++ b/src/panels/developer-tools/statistics/fix-statistics.ts
@@ -0,0 +1,169 @@
+import { html } from "lit";
+import {
+ clearStatistics,
+ getStatisticLabel,
+ StatisticsValidationResult,
+} from "../../../data/recorder";
+import { documentationUrl } from "../../../util/documentation-url";
+import {
+ showConfirmationDialog,
+ showAlertDialog,
+} from "../../lovelace/custom-card-helpers";
+import { showFixStatisticsUnitsChangedDialog } from "./show-dialog-statistics-fix-units-changed";
+import { LocalizeFunc } from "../../../common/translations/localize";
+import { HomeAssistant } from "../../../types";
+
+export const fixStatisticsIssue = async (
+ element: HTMLElement,
+ hass: HomeAssistant,
+ localize: LocalizeFunc,
+ issue: StatisticsValidationResult
+) => {
+ switch (issue.type) {
+ case "no_state":
+ return showConfirmationDialog(element, {
+ title: localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.no_state.title"
+ ),
+ text: html`${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.no_state.info_text_1",
+ {
+ name: getStatisticLabel(hass, issue.data.statistic_id, undefined),
+ }
+ )}
${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.no_state.info_text_2",
+ { statistic_id: issue.data.statistic_id }
+ )}`,
+ confirmText: localize("ui.common.delete"),
+ destructive: true,
+ confirm: async () => {
+ await clearStatistics(hass, [issue.data.statistic_id]);
+ },
+ });
+ case "entity_not_recorded":
+ return showAlertDialog(element, {
+ title: localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.title"
+ ),
+ text: html`${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_1",
+ {
+ name: getStatisticLabel(hass, issue.data.statistic_id, undefined),
+ }
+ )}
${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_2"
+ )}
+
+ ${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_not_recorded.info_text_3_link"
+ )}`,
+ });
+ case "entity_no_longer_recorded":
+ return showConfirmationDialog(element, {
+ title: localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.title"
+ ),
+ text: html`${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_1",
+ {
+ name: getStatisticLabel(hass, issue.data.statistic_id, undefined),
+ }
+ )}
+ ${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_2"
+ )}
+
+ ${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_3_link"
+ )}
+ ${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.entity_no_longer_recorded.info_text_4"
+ )}`,
+ confirmText: localize("ui.common.delete"),
+ destructive: true,
+ confirm: async () => {
+ await clearStatistics(hass, [issue.data.statistic_id]);
+ },
+ });
+ case "unsupported_state_class":
+ return showConfirmationDialog(element, {
+ title: localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.unsupported_state_class.title"
+ ),
+ text: html`${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.unsupported_state_class.info_text_1",
+ {
+ name: getStatisticLabel(hass, issue.data.statistic_id, undefined),
+ state_class: issue.data.state_class,
+ }
+ )}
+ ${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.unsupported_state_class.info_text_2"
+ )}
+
+ ${localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.unsupported_state_class.info_text_6",
+ { statistic_id: issue.data.statistic_id }
+ )}`,
+ confirmText: localize("ui.common.delete"),
+ destructive: true,
+ confirm: async () => {
+ await clearStatistics(hass, [issue.data.statistic_id]);
+ },
+ });
+ case "units_changed":
+ return showFixStatisticsUnitsChangedDialog(element, {
+ issue,
+ });
+ default:
+ return showAlertDialog(element, {
+ title: localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.no_support.title"
+ ),
+ text: localize(
+ "ui.panel.developer-tools.tabs.statistics.fix_issue.no_support.info_text_1"
+ ),
+ });
+ }
+};
diff --git a/src/panels/developer-tools/statistics/show-dialog-statistics-fix-units-changed.ts b/src/panels/developer-tools/statistics/show-dialog-statistics-fix-units-changed.ts
index 1b6d7ee116a5..3305fc897bcd 100644
--- a/src/panels/developer-tools/statistics/show-dialog-statistics-fix-units-changed.ts
+++ b/src/panels/developer-tools/statistics/show-dialog-statistics-fix-units-changed.ts
@@ -6,16 +6,29 @@ export const loadFixUnitsDialog = () =>
export interface DialogStatisticsUnitsChangedParams {
issue: StatisticsValidationResultUnitsChanged;
- fixedCallback: () => void;
+ fixedCallback?: () => void;
+ cancelCallback?: () => void;
}
export const showFixStatisticsUnitsChangedDialog = (
element: HTMLElement,
detailParams: DialogStatisticsUnitsChangedParams
-): void => {
- fireEvent(element, "show-dialog", {
- dialogTag: "dialog-statistics-fix-units-changed",
- dialogImport: loadFixUnitsDialog,
- dialogParams: detailParams,
+) =>
+ new Promise((resolve) => {
+ const origCallback = detailParams.fixedCallback;
+
+ fireEvent(element, "show-dialog", {
+ dialogTag: "dialog-statistics-fix-units-changed",
+ dialogImport: loadFixUnitsDialog,
+ dialogParams: {
+ ...detailParams,
+ cancelCallback: () => {
+ resolve(false);
+ },
+ fixedCallback: () => {
+ resolve(true);
+ origCallback?.();
+ },
+ },
+ });
});
-};
diff --git a/src/translations/en.json b/src/translations/en.json
index e46030363356..a56ef23928f4 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -6955,25 +6955,25 @@
},
"no_state": {
"title": "Entity has no state",
- "info_text_1": "This entity has no state at the moment, if this is an orphaned entity, you may want to delete the long term statistics of it from your database.",
+ "info_text_1": "{name} has no state at the moment, if this is an orphaned entity, you may want to delete the long term statistics of it from your database.",
"info_text_2": "Do you want to permanently delete the long term statistics of {statistic_id} from your database?"
},
"entity_not_recorded": {
- "title": "Entity not recorded",
- "info_text_1": "State changes of this entity are not recorded, therefore, we cannot track long term statistics for it.",
+ "title": "Entity is not recorded",
+ "info_text_1": "State changes of {name} are not recorded, therefore, we cannot track long term statistics for it.",
"info_text_2": "You probably excluded this entity, or have just included some entities.",
"info_text_3_link": "See the recorder documentation for more information."
},
"entity_no_longer_recorded": {
- "title": "Entity no longer recorded",
- "info_text_1": "We have generated statistics for this entity in the past, but state changes of this entity are no longer recorded, therefore, we cannot track long term statistics for it anymore.",
+ "title": "Entity is no longer recorded",
+ "info_text_1": "We have generated statistics for {name} in the past, but state changes of this entity are no longer recorded, therefore, we cannot track long term statistics for it anymore.",
"info_text_2": "You probably excluded this entity, or have just included some entities.",
"info_text_3_link": "See the recorder documentation for more information.",
"info_text_4": "If you no longer wish to keep the long term statistics recorded in the past, you may delete them now."
},
"unsupported_state_class": {
"title": "Unsupported state class",
- "info_text_1": "The state class of this entity, {state_class} is not supported.",
+ "info_text_1": "The state class of {name}, {state_class} is not supported.",
"info_text_2": "Statistics cannot be generated until this entity has a supported state class.",
"info_text_3": "If this state class was provided by an integration, this is a bug. Please report an issue.",
"info_text_4": "If you have set this state class yourself, please correct it.",
@@ -6982,11 +6982,11 @@
"info_text_6": "Do you want to permanently delete the long term statistics of {statistic_id} from your database?"
},
"units_changed": {
- "title": "The unit of this entity changed",
+ "title": "The unit changed",
"update": "Update the unit of the historic statistic values from ''{metadata_unit}'' to ''{state_unit}'', without converting.",
"clear": "Delete all old statistic data for this entity",
"how_to_fix": "How do you want to fix this issue?",
- "info_text_1": "The unit of this entity changed to ''{current_unit}'' which can't be converted to the previously stored unit, ''{previous_unit}''.",
+ "info_text_1": "The unit of {name} changed to ''{current_unit}'' which can't be converted to the previously stored unit, ''{previous_unit}''.",
"info_text_2": "If the historic statistic values have a wrong unit, you can update the units of the old values. The values will not be updated.",
"info_text_3": "Otherwise you can choose to delete all historic statistic values, and start over."
},