2022-06-29 14:50:24 +00:00
|
|
|
"""The Recorder websocket API."""
|
2021-09-27 22:43:29 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2022-09-08 20:03:43 +00:00
|
|
|
from datetime import datetime as dt
|
2021-12-07 12:16:24 +00:00
|
|
|
import logging
|
2022-09-08 20:03:43 +00:00
|
|
|
from typing import Literal
|
2021-11-04 15:46:45 +00:00
|
|
|
|
2021-09-13 11:44:22 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
|
|
|
from homeassistant.components import websocket_api
|
2022-09-08 20:03:43 +00:00
|
|
|
from homeassistant.components.websocket_api import messages
|
2022-09-20 21:43:57 +00:00
|
|
|
from homeassistant.const import (
|
|
|
|
ENERGY_KILO_WATT_HOUR,
|
|
|
|
ENERGY_MEGA_WATT_HOUR,
|
|
|
|
ENERGY_WATT_HOUR,
|
|
|
|
VOLUME_CUBIC_FEET,
|
|
|
|
VOLUME_CUBIC_METERS,
|
|
|
|
)
|
2022-07-21 10:36:49 +00:00
|
|
|
from homeassistant.core import HomeAssistant, callback, valid_entity_id
|
|
|
|
from homeassistant.helpers import config_validation as cv
|
2022-09-08 20:03:43 +00:00
|
|
|
from homeassistant.helpers.json import JSON_DUMP
|
2022-09-22 16:31:50 +00:00
|
|
|
from homeassistant.util import dt as dt_util
|
2022-09-22 14:44:09 +00:00
|
|
|
from homeassistant.util.unit_conversion import (
|
|
|
|
EnergyConverter,
|
|
|
|
PowerConverter,
|
|
|
|
PressureConverter,
|
2022-09-22 16:31:50 +00:00
|
|
|
TemperatureConverter,
|
2022-09-21 12:48:38 +00:00
|
|
|
)
|
2021-09-13 11:44:22 +00:00
|
|
|
|
2022-07-22 09:58:26 +00:00
|
|
|
from .const import MAX_QUEUE_BACKLOG
|
2022-07-21 10:36:49 +00:00
|
|
|
from .statistics import (
|
|
|
|
async_add_external_statistics,
|
2022-09-27 06:44:58 +00:00
|
|
|
async_change_statistics_unit,
|
2022-07-21 10:36:49 +00:00
|
|
|
async_import_statistics,
|
|
|
|
list_statistic_ids,
|
2022-09-08 20:03:43 +00:00
|
|
|
statistics_during_period,
|
2022-07-21 10:36:49 +00:00
|
|
|
validate_statistics,
|
|
|
|
)
|
2022-07-22 13:11:34 +00:00
|
|
|
from .util import async_migration_in_progress, async_migration_is_live, get_instance
|
2021-11-04 15:46:45 +00:00
|
|
|
|
2021-12-07 12:16:24 +00:00
|
|
|
_LOGGER: logging.Logger = logging.getLogger(__package__)
|
|
|
|
|
2021-09-13 11:44:22 +00:00
|
|
|
|
|
|
|
@callback
|
|
|
|
def async_setup(hass: HomeAssistant) -> None:
|
|
|
|
"""Set up the recorder websocket API."""
|
2022-09-08 20:03:43 +00:00
|
|
|
websocket_api.async_register_command(hass, ws_adjust_sum_statistics)
|
|
|
|
websocket_api.async_register_command(hass, ws_backup_end)
|
|
|
|
websocket_api.async_register_command(hass, ws_backup_start)
|
2022-09-27 06:44:58 +00:00
|
|
|
websocket_api.async_register_command(hass, ws_change_statistics_unit)
|
2021-09-27 21:30:13 +00:00
|
|
|
websocket_api.async_register_command(hass, ws_clear_statistics)
|
2022-09-08 20:03:43 +00:00
|
|
|
websocket_api.async_register_command(hass, ws_get_statistics_during_period)
|
2022-03-22 04:14:47 +00:00
|
|
|
websocket_api.async_register_command(hass, ws_get_statistics_metadata)
|
2022-09-08 20:03:43 +00:00
|
|
|
websocket_api.async_register_command(hass, ws_list_statistic_ids)
|
2022-07-21 10:36:49 +00:00
|
|
|
websocket_api.async_register_command(hass, ws_import_statistics)
|
2022-09-08 20:03:43 +00:00
|
|
|
websocket_api.async_register_command(hass, ws_info)
|
|
|
|
websocket_api.async_register_command(hass, ws_update_statistics_metadata)
|
|
|
|
websocket_api.async_register_command(hass, ws_validate_statistics)
|
|
|
|
|
|
|
|
|
|
|
|
def _ws_get_statistics_during_period(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
msg_id: int,
|
|
|
|
start_time: dt,
|
2022-09-20 21:43:57 +00:00
|
|
|
end_time: dt | None,
|
|
|
|
statistic_ids: list[str] | None,
|
|
|
|
period: Literal["5minute", "day", "hour", "month"],
|
|
|
|
units: dict[str, str],
|
2022-09-08 20:03:43 +00:00
|
|
|
) -> str:
|
|
|
|
"""Fetch statistics and convert them to json in the executor."""
|
|
|
|
return JSON_DUMP(
|
|
|
|
messages.result_message(
|
|
|
|
msg_id,
|
2022-09-20 21:43:57 +00:00
|
|
|
statistics_during_period(
|
|
|
|
hass, start_time, end_time, statistic_ids, period, units=units
|
|
|
|
),
|
2022-09-08 20:03:43 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
async def ws_handle_get_statistics_during_period(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
|
|
|
"""Handle statistics websocket command."""
|
|
|
|
start_time_str = msg["start_time"]
|
|
|
|
end_time_str = msg.get("end_time")
|
|
|
|
|
|
|
|
if start_time := dt_util.parse_datetime(start_time_str):
|
|
|
|
start_time = dt_util.as_utc(start_time)
|
|
|
|
else:
|
|
|
|
connection.send_error(msg["id"], "invalid_start_time", "Invalid start_time")
|
|
|
|
return
|
|
|
|
|
|
|
|
if end_time_str:
|
|
|
|
if end_time := dt_util.parse_datetime(end_time_str):
|
|
|
|
end_time = dt_util.as_utc(end_time)
|
|
|
|
else:
|
|
|
|
connection.send_error(msg["id"], "invalid_end_time", "Invalid end_time")
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
end_time = None
|
|
|
|
|
|
|
|
connection.send_message(
|
|
|
|
await get_instance(hass).async_add_executor_job(
|
|
|
|
_ws_get_statistics_during_period,
|
|
|
|
hass,
|
|
|
|
msg["id"],
|
|
|
|
start_time,
|
|
|
|
end_time,
|
|
|
|
msg.get("statistic_ids"),
|
|
|
|
msg.get("period"),
|
2022-09-20 21:43:57 +00:00
|
|
|
msg.get("units"),
|
2022-09-08 20:03:43 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
vol.Required("type"): "recorder/statistics_during_period",
|
|
|
|
vol.Required("start_time"): str,
|
|
|
|
vol.Optional("end_time"): str,
|
|
|
|
vol.Optional("statistic_ids"): [str],
|
|
|
|
vol.Required("period"): vol.Any("5minute", "hour", "day", "month"),
|
2022-09-20 21:43:57 +00:00
|
|
|
vol.Optional("units"): vol.Schema(
|
|
|
|
{
|
2022-09-22 13:39:49 +00:00
|
|
|
vol.Optional("energy"): vol.In(EnergyConverter.VALID_UNITS),
|
|
|
|
vol.Optional("power"): vol.In(PowerConverter.VALID_UNITS),
|
2022-09-22 14:44:09 +00:00
|
|
|
vol.Optional("pressure"): vol.In(PressureConverter.VALID_UNITS),
|
2022-09-22 16:31:50 +00:00
|
|
|
vol.Optional("temperature"): vol.In(TemperatureConverter.VALID_UNITS),
|
2022-09-20 21:43:57 +00:00
|
|
|
vol.Optional("volume"): vol.Any(VOLUME_CUBIC_FEET, VOLUME_CUBIC_METERS),
|
|
|
|
}
|
|
|
|
),
|
2022-09-08 20:03:43 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
@websocket_api.async_response
|
|
|
|
async def ws_get_statistics_during_period(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
|
|
|
"""Handle statistics websocket command."""
|
|
|
|
await ws_handle_get_statistics_during_period(hass, connection, msg)
|
|
|
|
|
|
|
|
|
|
|
|
def _ws_get_list_statistic_ids(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
msg_id: int,
|
|
|
|
statistic_type: Literal["mean"] | Literal["sum"] | None = None,
|
|
|
|
) -> str:
|
|
|
|
"""Fetch a list of available statistic_id and convert them to json in the executor."""
|
|
|
|
return JSON_DUMP(
|
|
|
|
messages.result_message(msg_id, list_statistic_ids(hass, None, statistic_type))
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
async def ws_handle_list_statistic_ids(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
|
|
|
"""Fetch a list of available statistic_id."""
|
|
|
|
connection.send_message(
|
|
|
|
await get_instance(hass).async_add_executor_job(
|
|
|
|
_ws_get_list_statistic_ids,
|
|
|
|
hass,
|
|
|
|
msg["id"],
|
|
|
|
msg.get("statistic_type"),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
vol.Required("type"): "recorder/list_statistic_ids",
|
|
|
|
vol.Optional("statistic_type"): vol.Any("sum", "mean"),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
@websocket_api.async_response
|
|
|
|
async def ws_list_statistic_ids(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
|
|
|
"""Fetch a list of available statistic_id."""
|
|
|
|
await ws_handle_list_statistic_ids(hass, connection, msg)
|
2021-09-13 11:44:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
vol.Required("type"): "recorder/validate_statistics",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
@websocket_api.async_response
|
|
|
|
async def ws_validate_statistics(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
|
|
|
"""Fetch a list of available statistic_id."""
|
2022-07-22 09:58:26 +00:00
|
|
|
instance = get_instance(hass)
|
2022-03-18 09:09:01 +00:00
|
|
|
statistic_ids = await instance.async_add_executor_job(
|
2021-09-13 11:44:22 +00:00
|
|
|
validate_statistics,
|
|
|
|
hass,
|
|
|
|
)
|
|
|
|
connection.send_result(msg["id"], statistic_ids)
|
2021-09-27 21:30:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
@websocket_api.require_admin
|
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
vol.Required("type"): "recorder/clear_statistics",
|
|
|
|
vol.Required("statistic_ids"): [str],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
@callback
|
|
|
|
def ws_clear_statistics(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
|
|
|
"""Clear statistics for a list of statistic_ids.
|
|
|
|
|
|
|
|
Note: The WS call posts a job to the recorder's queue and then returns, it doesn't
|
|
|
|
wait until the job is completed.
|
|
|
|
"""
|
2022-07-22 09:58:26 +00:00
|
|
|
get_instance(hass).async_clear_statistics(msg["statistic_ids"])
|
2021-09-27 21:30:13 +00:00
|
|
|
connection.send_result(msg["id"])
|
2021-09-27 22:43:29 +00:00
|
|
|
|
|
|
|
|
2022-03-22 04:14:47 +00:00
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
vol.Required("type"): "recorder/get_statistics_metadata",
|
|
|
|
vol.Optional("statistic_ids"): [str],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
@websocket_api.async_response
|
|
|
|
async def ws_get_statistics_metadata(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
|
|
|
"""Get metadata for a list of statistic_ids."""
|
2022-07-22 09:58:26 +00:00
|
|
|
instance = get_instance(hass)
|
2022-03-24 13:15:09 +00:00
|
|
|
statistic_ids = await instance.async_add_executor_job(
|
2022-03-22 04:14:47 +00:00
|
|
|
list_statistic_ids, hass, msg.get("statistic_ids")
|
|
|
|
)
|
|
|
|
connection.send_result(msg["id"], statistic_ids)
|
|
|
|
|
|
|
|
|
2021-09-27 22:43:29 +00:00
|
|
|
@websocket_api.require_admin
|
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
vol.Required("type"): "recorder/update_statistics_metadata",
|
|
|
|
vol.Required("statistic_id"): str,
|
|
|
|
vol.Required("unit_of_measurement"): vol.Any(str, None),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
@callback
|
|
|
|
def ws_update_statistics_metadata(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
2022-09-15 16:01:24 +00:00
|
|
|
"""Update statistics metadata for a statistic_id.
|
|
|
|
|
|
|
|
Only the normalized unit of measurement can be updated.
|
|
|
|
"""
|
2022-07-22 09:58:26 +00:00
|
|
|
get_instance(hass).async_update_statistics_metadata(
|
2022-05-24 13:34:46 +00:00
|
|
|
msg["statistic_id"], new_unit_of_measurement=msg["unit_of_measurement"]
|
2021-09-27 22:43:29 +00:00
|
|
|
)
|
|
|
|
connection.send_result(msg["id"])
|
2021-11-04 15:46:45 +00:00
|
|
|
|
|
|
|
|
2022-09-27 06:44:58 +00:00
|
|
|
@websocket_api.require_admin
|
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
vol.Required("type"): "recorder/change_statistics_unit",
|
|
|
|
vol.Required("statistic_id"): str,
|
|
|
|
vol.Required("new_unit_of_measurement"): vol.Any(str, None),
|
|
|
|
vol.Required("old_unit_of_measurement"): vol.Any(str, None),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
@callback
|
|
|
|
def ws_change_statistics_unit(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
|
|
|
"""Change the unit_of_measurement for a statistic_id.
|
|
|
|
|
|
|
|
All existing statistics will be converted to the new unit.
|
|
|
|
"""
|
|
|
|
async_change_statistics_unit(
|
|
|
|
hass,
|
|
|
|
msg["statistic_id"],
|
|
|
|
new_unit_of_measurement=msg["new_unit_of_measurement"],
|
|
|
|
old_unit_of_measurement=msg["old_unit_of_measurement"],
|
|
|
|
)
|
|
|
|
connection.send_result(msg["id"])
|
|
|
|
|
|
|
|
|
2022-03-22 22:18:30 +00:00
|
|
|
@websocket_api.require_admin
|
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
vol.Required("type"): "recorder/adjust_sum_statistics",
|
|
|
|
vol.Required("statistic_id"): str,
|
|
|
|
vol.Required("start_time"): str,
|
|
|
|
vol.Required("adjustment"): vol.Any(float, int),
|
2022-09-20 21:43:57 +00:00
|
|
|
vol.Required("display_unit"): vol.Any(str, None),
|
2022-03-22 22:18:30 +00:00
|
|
|
}
|
|
|
|
)
|
2022-09-20 21:43:57 +00:00
|
|
|
@websocket_api.async_response
|
|
|
|
async def ws_adjust_sum_statistics(
|
2022-03-22 22:18:30 +00:00
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
2022-09-20 21:43:57 +00:00
|
|
|
"""Adjust sum statistics.
|
|
|
|
|
|
|
|
If the statistics is stored as kWh, it's allowed to make an adjustment in Wh or MWh
|
|
|
|
If the statistics is stored as m³, it's allowed to make an adjustment in ft³
|
|
|
|
"""
|
2022-03-22 22:18:30 +00:00
|
|
|
start_time_str = msg["start_time"]
|
|
|
|
|
|
|
|
if start_time := dt_util.parse_datetime(start_time_str):
|
|
|
|
start_time = dt_util.as_utc(start_time)
|
|
|
|
else:
|
|
|
|
connection.send_error(msg["id"], "invalid_start_time", "Invalid start time")
|
|
|
|
return
|
|
|
|
|
2022-09-20 21:43:57 +00:00
|
|
|
instance = get_instance(hass)
|
|
|
|
metadatas = await instance.async_add_executor_job(
|
|
|
|
list_statistic_ids, hass, (msg["statistic_id"],)
|
|
|
|
)
|
|
|
|
if not metadatas:
|
|
|
|
connection.send_error(msg["id"], "unknown_statistic_id", "Unknown statistic ID")
|
|
|
|
return
|
|
|
|
metadata = metadatas[0]
|
|
|
|
|
|
|
|
def valid_units(statistics_unit: str | None, display_unit: str | None) -> bool:
|
|
|
|
if statistics_unit == display_unit:
|
|
|
|
return True
|
|
|
|
if statistics_unit == ENERGY_KILO_WATT_HOUR and display_unit in (
|
|
|
|
ENERGY_MEGA_WATT_HOUR,
|
|
|
|
ENERGY_WATT_HOUR,
|
|
|
|
):
|
|
|
|
return True
|
|
|
|
if statistics_unit == VOLUME_CUBIC_METERS and display_unit == VOLUME_CUBIC_FEET:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
stat_unit = metadata["statistics_unit_of_measurement"]
|
|
|
|
if not valid_units(stat_unit, msg["display_unit"]):
|
|
|
|
connection.send_error(
|
|
|
|
msg["id"],
|
|
|
|
"invalid_units",
|
|
|
|
f"Can't convert {stat_unit} to {msg['display_unit']}",
|
|
|
|
)
|
|
|
|
return
|
|
|
|
|
2022-07-22 09:58:26 +00:00
|
|
|
get_instance(hass).async_adjust_statistics(
|
2022-09-20 21:43:57 +00:00
|
|
|
msg["statistic_id"], start_time, msg["adjustment"], msg["display_unit"]
|
2022-03-22 22:18:30 +00:00
|
|
|
)
|
|
|
|
connection.send_result(msg["id"])
|
|
|
|
|
|
|
|
|
2022-07-21 10:36:49 +00:00
|
|
|
@websocket_api.require_admin
|
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
vol.Required("type"): "recorder/import_statistics",
|
|
|
|
vol.Required("metadata"): {
|
|
|
|
vol.Required("has_mean"): bool,
|
|
|
|
vol.Required("has_sum"): bool,
|
|
|
|
vol.Required("name"): vol.Any(str, None),
|
|
|
|
vol.Required("source"): str,
|
|
|
|
vol.Required("statistic_id"): str,
|
|
|
|
vol.Required("unit_of_measurement"): vol.Any(str, None),
|
|
|
|
},
|
|
|
|
vol.Required("stats"): [
|
|
|
|
{
|
|
|
|
vol.Required("start"): cv.datetime,
|
|
|
|
vol.Optional("mean"): vol.Any(float, int),
|
|
|
|
vol.Optional("min"): vol.Any(float, int),
|
|
|
|
vol.Optional("max"): vol.Any(float, int),
|
|
|
|
vol.Optional("last_reset"): vol.Any(cv.datetime, None),
|
|
|
|
vol.Optional("state"): vol.Any(float, int),
|
|
|
|
vol.Optional("sum"): vol.Any(float, int),
|
|
|
|
}
|
|
|
|
],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
@callback
|
|
|
|
def ws_import_statistics(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
2022-09-20 21:43:57 +00:00
|
|
|
"""Import statistics."""
|
2022-07-21 10:36:49 +00:00
|
|
|
metadata = msg["metadata"]
|
|
|
|
stats = msg["stats"]
|
2022-09-15 16:01:24 +00:00
|
|
|
metadata["state_unit_of_measurement"] = metadata["unit_of_measurement"]
|
2022-07-21 10:36:49 +00:00
|
|
|
|
|
|
|
if valid_entity_id(metadata["statistic_id"]):
|
|
|
|
async_import_statistics(hass, metadata, stats)
|
|
|
|
else:
|
|
|
|
async_add_external_statistics(hass, metadata, stats)
|
|
|
|
connection.send_result(msg["id"])
|
|
|
|
|
|
|
|
|
2021-11-04 15:46:45 +00:00
|
|
|
@websocket_api.websocket_command(
|
|
|
|
{
|
|
|
|
vol.Required("type"): "recorder/info",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
@callback
|
|
|
|
def ws_info(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
|
|
|
"""Return status of the recorder."""
|
2022-07-22 09:58:26 +00:00
|
|
|
instance = get_instance(hass)
|
2021-11-04 15:46:45 +00:00
|
|
|
|
2022-05-03 20:56:22 +00:00
|
|
|
backlog = instance.backlog if instance else None
|
2021-11-05 09:40:56 +00:00
|
|
|
migration_in_progress = async_migration_in_progress(hass)
|
2022-07-22 13:11:34 +00:00
|
|
|
migration_is_live = async_migration_is_live(hass)
|
2021-11-04 15:46:45 +00:00
|
|
|
recording = instance.recording if instance else False
|
|
|
|
thread_alive = instance.is_alive() if instance else False
|
|
|
|
|
|
|
|
recorder_info = {
|
|
|
|
"backlog": backlog,
|
|
|
|
"max_backlog": MAX_QUEUE_BACKLOG,
|
|
|
|
"migration_in_progress": migration_in_progress,
|
2022-07-22 13:11:34 +00:00
|
|
|
"migration_is_live": migration_is_live,
|
2021-11-04 15:46:45 +00:00
|
|
|
"recording": recording,
|
|
|
|
"thread_running": thread_alive,
|
|
|
|
}
|
|
|
|
connection.send_result(msg["id"], recorder_info)
|
2021-12-07 12:16:24 +00:00
|
|
|
|
|
|
|
|
2021-12-09 00:49:35 +00:00
|
|
|
@websocket_api.ws_require_user(only_supervisor=True)
|
2021-12-07 12:16:24 +00:00
|
|
|
@websocket_api.websocket_command({vol.Required("type"): "backup/start"})
|
|
|
|
@websocket_api.async_response
|
|
|
|
async def ws_backup_start(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
|
|
|
"""Backup start notification."""
|
|
|
|
|
|
|
|
_LOGGER.info("Backup start notification, locking database for writes")
|
2022-07-22 09:58:26 +00:00
|
|
|
instance = get_instance(hass)
|
2021-12-07 12:16:24 +00:00
|
|
|
try:
|
|
|
|
await instance.lock_database()
|
|
|
|
except TimeoutError as err:
|
|
|
|
connection.send_error(msg["id"], "timeout_error", str(err))
|
|
|
|
return
|
|
|
|
connection.send_result(msg["id"])
|
|
|
|
|
|
|
|
|
2021-12-09 00:49:35 +00:00
|
|
|
@websocket_api.ws_require_user(only_supervisor=True)
|
2021-12-07 12:16:24 +00:00
|
|
|
@websocket_api.websocket_command({vol.Required("type"): "backup/end"})
|
|
|
|
@websocket_api.async_response
|
|
|
|
async def ws_backup_end(
|
|
|
|
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict
|
|
|
|
) -> None:
|
|
|
|
"""Backup end notification."""
|
|
|
|
|
2022-07-22 09:58:26 +00:00
|
|
|
instance = get_instance(hass)
|
2021-12-07 12:16:24 +00:00
|
|
|
_LOGGER.info("Backup end notification, releasing write lock")
|
|
|
|
if not instance.unlock_database():
|
|
|
|
connection.send_error(
|
|
|
|
msg["id"], "database_unlock_failed", "Failed to unlock database."
|
|
|
|
)
|
|
|
|
connection.send_result(msg["id"])
|