Backup
There are two main purposes for an integration to implement a backup platform:
- Add a backup agent that can upload backups to some local or remote location.
- Pause or prepare integration operations before creating a backup and/or run some operation after a backup.
Backup Agents
To add one or more backup agents, implement the two methods, async_get_backup_agents
and async_register_backup_agents_listener
in backup.py
. Example:
async def async_get_backup_agents(
hass: HomeAssistant,
) -> list[BackupAgent]:
"""Return a list of backup agents."""
if not hass.config_entries.async_loaded_entries(DOMAIN):
LOGGER.debug("No config entry found or entry is not loaded")
return []
return [ExampleBackupAgent()]
@callback
def async_register_backup_agents_listener(
hass: HomeAssistant,
*,
listener: Callable[[], None],
**kwargs: Any,
) -> Callable[[], None]:
"""Register a listener to be called when agents are added or removed.
:return: A function to unregister the listener.
"""
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_listener
The listener stored in async_register_backup_agents_listener
should be called every time there is the need to reload backup agents, to remove stale agents and add new ones, such as when the integration is reloaded. For example:
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload config entry."""
# Notify backup listeners
hass.async_create_task(_notify_backup_listeners(hass), eager_start=False)
return await hass.config_entries.async_unload_platforms(
entry, PLATFORMS
)
async def _notify_backup_listeners(hass: HomeAssistant) -> None:
for listener in hass.data.get(DATA_BACKUP_AGENT_LISTENERS, []):
listener()
A backup agent should implement the abstract interface of the BackupAgent
base class as shown in this example:
from homeassistant.components.backup import BackupAgent, BackupAgentError
from .const import DOMAIN
class ExampleBackupAgent(BackupAgent):
"""Backup agent interface."""
domain = DOMAIN
name = "example"
async def async_download_backup(
self,
backup_id: str,
**kwargs: Any,
) -> AsyncIterator[bytes]:
"""Download a backup file.
:param backup_id: The ID of the backup that was returned in async_list_backups.
:return: An async iterator that yields bytes.
"""
async def async_upload_backup(
self,
*,
open_stream: Callable[[], Coroutine[Any, Any, AsyncIterator[bytes]]],
backup: AgentBackup,
**kwargs: Any,
) -> None:
"""Upload a backup.
:param open_stream: A function returning an async iterator that yields bytes.
:param backup: Metadata about the backup that should be uploaded.
"""
async def async_delete_backup(
self,
backup_id: str,
**kwargs: Any,
) -> None:
"""Delete a backup file.
:param backup_id: The ID of the backup that was returned in async_list_backups.
"""
async def async_list_backups(self, **kwargs: Any) -> list[AgentBackup]:
"""List backups."""
async def async_get_backup(
self,
backup_id: str,
**kwargs: Any,
) -> AgentBackup | None:
"""Return a backup."""
Backup agents should raise a BackupAgentError
exception on error. Other exceptions are not expected to leave the backup agent.
Pre- and post-operations
When Home Assistant is creating a backup, there might be a need to pause certain operations in the integration, or dumping data so it can properly be restored.
This is done by adding two functions (async_pre_backup
and async_post_backup
) to backup.py
Adding support
The quickest way to add backup support to a new integration is by using our built-in scaffold template. From a Home Assistant dev environment, run python3 -m script.scaffold backup
and follow the instructions.
If you prefer to go the manual route, create a new file in your integration folder called backup.py
and implement the following method:
from homeassistant.core import HomeAssistant
async def async_pre_backup(hass: HomeAssistant) -> None:
"""Perform operations before a backup starts."""
async def async_post_backup(hass: HomeAssistant) -> None:
"""Perform operations after a backup finishes."""