Add WS API to adjust incorrect energy statistics (#65147)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
Erik Montnemery 2022-03-22 23:18:30 +01:00 committed by GitHub
parent c5a3ba4065
commit b5c5da96ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 280 additions and 41 deletions

View file

@ -19,6 +19,7 @@ from sqlalchemy.exc import SQLAlchemyError, StatementError
from sqlalchemy.ext import baked
from sqlalchemy.orm.scoping import scoped_session
from sqlalchemy.sql.expression import literal_column, true
import voluptuous as vol
from homeassistant.const import (
PRESSURE_PA,
@ -163,6 +164,14 @@ def valid_statistic_id(statistic_id: str) -> bool:
return VALID_STATISTIC_ID.match(statistic_id) is not None
def validate_statistic_id(value: str) -> str:
"""Validate statistic ID."""
if valid_statistic_id(value):
return value
raise vol.Invalid(f"Statistics ID {value} is an invalid statistic ID")
@dataclasses.dataclass
class ValidationIssue:
"""Error or warning message."""
@ -567,6 +576,30 @@ def compile_statistics(instance: Recorder, start: datetime) -> bool:
return True
def _adjust_sum_statistics(
session: scoped_session,
table: type[Statistics | StatisticsShortTerm],
metadata_id: int,
start_time: datetime,
adj: float,
) -> None:
"""Adjust statistics in the database."""
try:
session.query(table).filter_by(metadata_id=metadata_id).filter(
table.start >= start_time
).update(
{
table.sum: table.sum + adj,
},
synchronize_session=False,
)
except SQLAlchemyError:
_LOGGER.exception(
"Unexpected exception when updating statistics %s",
id,
)
def _insert_statistics(
session: scoped_session,
table: type[Statistics | StatisticsShortTerm],
@ -606,7 +639,7 @@ def _update_statistics(
except SQLAlchemyError:
_LOGGER.exception(
"Unexpected exception when updating statistics %s:%s ",
id,
stat_id,
statistic,
)
@ -1249,7 +1282,7 @@ def add_external_statistics(
metadata: StatisticMetaData,
statistics: Iterable[StatisticData],
) -> bool:
"""Process an add_statistics job."""
"""Process an add_external_statistics job."""
with session_scope(
session=instance.get_session(), # type: ignore[misc]
@ -1265,3 +1298,35 @@ def add_external_statistics(
_insert_statistics(session, Statistics, metadata_id, stat)
return True
@retryable_database_job("adjust_statistics")
def adjust_statistics(
instance: Recorder,
statistic_id: str,
start_time: datetime,
sum_adjustment: float,
) -> bool:
"""Process an add_statistics job."""
with session_scope(session=instance.get_session()) as session: # type: ignore[misc]
metadata = get_metadata_with_session(
instance.hass, session, statistic_ids=(statistic_id,)
)
if statistic_id not in metadata:
return True
tables: tuple[type[Statistics | StatisticsShortTerm], ...] = (
Statistics,
StatisticsShortTerm,
)
for table in tables:
_adjust_sum_statistics(
session,
table,
metadata[statistic_id][0],
start_time,
sum_adjustment,
)
return True