forked from megakid/ha_octopus_intelligent
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
192 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
"""Persistent data storage for the integration, based on the HASS helpers.storage.Store class.""" | ||
import logging | ||
from dataclasses import asdict, dataclass, InitVar | ||
from typing import Any | ||
|
||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP | ||
from homeassistant.core import Event, HomeAssistant | ||
from homeassistant.exceptions import IntegrationError | ||
from homeassistant.helpers.storage import Store | ||
|
||
from .const import DOMAIN | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
@dataclass | ||
class PersistentData: | ||
"""JSON-serialisable data persistence backed by the hass helpers.storage.Store class. | ||
Frequently persisting data to "disk" can have undesired side effects when HASS is | ||
running on some edge devices like a Raspberry Pi, whose storage consists of an SD card | ||
that wears when data is written, leading to physical damage and data corruption. | ||
For this reason, by default, the data is only saved when the HASS STOP event event | ||
is fired, indicating that Home Assistant is quitting / restarting. This includes the | ||
frontend web UI 'Restart' command, CTRL-C on the command line, the "docker container | ||
stop" command, and generally when the SIGTERM signal is received by the HASS core | ||
process. | ||
""" | ||
# Note: InitVar fields are not persisted. They become arguments to __post_init__(). | ||
hass: InitVar[HomeAssistant] | ||
account_id: InitVar[str] | ||
|
||
# --------------------------------------------- | ||
# Start of JSON-serialisable persistent fields. | ||
# | ||
last_seen_planned_dispatch_source: str = "smart-charge" | ||
# | ||
# End of JSON-serialisable persistent fields. | ||
# --------------------------------------------- | ||
|
||
def __post_init__(self, hass: HomeAssistant, account_id: str): | ||
self._store = Store[dict[str, Any]]( | ||
hass=hass, | ||
key=f"{DOMAIN}.{account_id}", | ||
version=1, | ||
minor_version=1, | ||
) | ||
self._auto_save_on_hass_stop(hass) | ||
|
||
def _auto_save_on_hass_stop(self, hass: HomeAssistant): | ||
"""Automatically call self.save() when the HASS STOP event fires.""" | ||
|
||
async def _on_hass_stop(_: Event): | ||
await self.save(raise_on_error=False) | ||
|
||
hass.bus.async_listen(EVENT_HOMEASSISTANT_STOP, _on_hass_stop) | ||
|
||
async def load(self): | ||
"""Load the data from persistent storage.""" | ||
try: | ||
data: dict[str, Any] = await self._store.async_load() or {} | ||
except Exception as ex: # pylint: disable=broad-exception-caught | ||
data = {} | ||
_LOGGER.error( | ||
"Using default values for persistent data because of an error: %s", ex | ||
) | ||
# Explicitly save each field separately instead of using some '**data' | ||
# unpacking syntax in order to be future-proof against schema changes | ||
# that may add, remove or rename data fields. | ||
self.last_seen_planned_dispatch_source = data.get( | ||
"last_seen_planned_dispatch_source", self.last_seen_planned_dispatch_source | ||
) | ||
|
||
async def save(self, raise_on_error=True): | ||
"""Save the data to persistent storage.""" | ||
try: | ||
await self._store.async_save(asdict(self)) | ||
except Exception as ex: # pylint: disable=broad-exception-caught | ||
msg = f"Error saving persistent data: {ex}" | ||
if raise_on_error: | ||
raise IntegrationError(msg) from ex | ||
_LOGGER.error(msg) | ||
|
||
async def remove(self): | ||
"""Remove the data from persistent storage (delete the JSON file on disk).""" | ||
try: | ||
await self._store.async_remove() | ||
except Exception as ex: # pylint: disable=broad-exception-caught | ||
_LOGGER.error("Error removing persistent data: %s", ex) |