Backup
Add a backup agent that stores Home Assistant backups somewhere, or prepare your integration for a backup.
An integration can take part in backups in two ways, both in a backup.py platform file:
- A backup agent stores backups somewhere: a network share, a cloud storage service, or anything else. Users pick the agents in the backup settings.
- Pre and post hooks pause or prepare your integration before a backup, and resume after it.
A backup agent extends BackupAgent from homeassistant.components.backup, and implements five methods:
from collections.abc import AsyncIterator, Callable, Coroutine
from typing import Any
from homeassistant.components.backup import (
AgentBackup,
BackupAgent,
BackupAgentError,
BackupNotFound,
OnProgressCallback,
)
class ExampleBackupAgent(BackupAgent):
"""Store backups at Example."""
domain = DOMAIN
def __init__(self, entry: ExampleConfigEntry) -> None:
"""Initialize the agent."""
super().__init__()
self._client = entry.runtime_data
self.name = entry.title
self.unique_id = entry.entry_id
async def async_upload_backup(
self,
*,
open_stream: Callable[[], Coroutine[Any, Any, AsyncIterator[bytes]]],
backup: AgentBackup,
on_progress: OnProgressCallback,
**kwargs: Any,
) -> None:
"""Upload a backup."""
async def async_download_backup(
self, backup_id: str, **kwargs: Any
) -> AsyncIterator[bytes]:
"""Download a backup."""
async def async_delete_backup(self, backup_id: str, **kwargs: Any) -> None:
"""Delete a backup."""
async def async_list_backups(self, **kwargs: Any) -> list[AgentBackup]:
"""List the backups."""
async def async_get_backup(
self, backup_id: str, **kwargs: Any
) -> AgentBackup:
"""Return one backup."""domain,name, andunique_ididentify the agent. Keepunique_idstable.async_upload_backupgets a function that opens a stream of the backup, and the metadata of the backup inbackup.async_download_backup,async_delete_backup, andasync_get_backupraiseBackupNotFoundwhen the backup does not exist.- On any other error, raise
BackupAgentError, or an exception that extends it. Other exceptions are not expected to leave the agent.
Call on_progress while you upload, for example after each chunk, with the total number of bytes uploaded so far. Home Assistant uses it to show the progress of the upload in the UI.
on_progress(bytes_uploaded=bytes_sent)Home Assistant gets your agents from two functions in backup.py:
from homeassistant.core import HomeAssistant, callback
async def async_get_backup_agents(hass: HomeAssistant) -> list[BackupAgent]:
"""Return the backup agents."""
return [
ExampleBackupAgent(entry)
for entry in hass.config_entries.async_loaded_entries(DOMAIN)
]
@callback
def async_register_backup_agents_listener(
hass: HomeAssistant,
*,
listener: Callable[[], None],
**kwargs: Any,
) -> Callable[[], None]:
"""Register a listener for when agents are added or removed."""
hass.data.setdefault(DATA_BACKUP_AGENT_LISTENERS, []).append(listener)
@callback
def remove_listener() -> None:
"""Remove the listener."""
hass.data[DATA_BACKUP_AGENT_LISTENERS].remove(listener)
return remove_listenerCall the listeners whenever your agents change, so Home Assistant asks for them again. For agents that follow config entries, call them when an entry is loaded or unloaded, in async_setup_entry:
def _notify_backup_listeners() -> None:
for listener in hass.data.get(DATA_BACKUP_AGENT_LISTENERS, []):
listener()
entry.async_on_unload(entry.async_on_state_change(_notify_backup_listeners))DATA_BACKUP_AGENT_LISTENERS is a key you define yourself, in const.py.
Some integrations need to pause or write their data before a backup, so it can be restored properly. Add these two functions to backup.py, or run python3 -m script.scaffold backup:
from homeassistant.core import HomeAssistant
async def async_pre_backup(hass: HomeAssistant) -> None:
"""Prepare for a backup."""
async def async_post_backup(hass: HomeAssistant) -> None:
"""Resume after a backup."""