def websocket_sign_path( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): """Handle a sign path request.""" connection.send_message(websocket_api.result_message(msg['id'], { 'path': async_sign_path(hass, connection.refresh_token_id, msg['path'], timedelta(seconds=msg['expires'])) }))
async def ws_delete_person(hass: HomeAssistantType, connection: websocket_api.ActiveConnection, msg): """Delete a person.""" manager = hass.data[DOMAIN] # type: PersonManager await manager.async_delete_person(msg['person_id']) connection.send_result(msg['id'])
def ws_list_person(hass: HomeAssistantType, connection: websocket_api.ActiveConnection, msg): """List persons.""" manager = hass.data[DOMAIN] # type: PersonManager connection.send_result(msg['id'], { 'storage': manager.storage_persons, 'config': manager.config_persons, })
def ws_list_person( hass: HomeAssistantType, connection: websocket_api.ActiveConnection, msg ): """List persons.""" yaml, storage = hass.data[DOMAIN] connection.send_result( msg[ATTR_ID], {"storage": storage.async_items(), "config": yaml.async_items()} )
async def ws_get_statistics_metadata( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict ) -> None: """Get metadata for a list of statistic_ids.""" instance = get_instance(hass) statistic_ids = await instance.async_add_executor_job( list_statistic_ids, hass, msg.get("statistic_ids") ) connection.send_result(msg["id"], statistic_ids)
async def hacs_repository_info( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any], ) -> None: """Return information about HACS.""" hacs: HacsBase = hass.data.get(DOMAIN) repository = hacs.repositories.get_by_id(msg["repository_id"]) if repository is None: connection.send_error(msg["id"], "repository_not_found", "Repository not found") return if not repository.updated_info: await repository.update_repository(ignore_issues=True, force=True) repository.updated_info = True connection.send_message( websocket_api.result_message( msg["id"], { "additional_info": repository.additional_info, "authors": repository.data.authors, "available_version": repository.display_available_version, "beta": repository.data.show_beta, "can_download": repository.can_download, "category": repository.data.category, "config_flow": repository.data.config_flow, "country": repository.repository_manifest.country, "custom": not hacs.repositories.is_default(str(repository.data.id)), "default_branch": repository.data.default_branch, "description": repository.data.description, "domain": repository.data.domain, "downloads": repository.data.downloads, "file_name": repository.data.file_name, "full_name": repository.data.full_name, "hide_default_branch": repository.repository_manifest.hide_default_branch, "homeassistant": repository.repository_manifest.homeassistant, "id": repository.data.id, "installed_version": repository.display_installed_version, "installed": repository.data.installed, "issues": repository.data.open_issues, "last_updated": repository.data.last_updated, "local_path": repository.content.path.local, "name": repository.display_name, "new": repository.data.new, "pending_upgrade": repository.pending_update, "releases": repository.data.published_tags, "ref": repository.ref, "selected_tag": repository.data.selected_tag, "stars": repository.data.stargazers_count, "state": repository.state, "status": repository.display_status, "topics": repository.data.topics, "version_or_commit": repository.display_version_or_commit, }, ) )
async def ws_validate_statistics(hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict) -> None: """Fetch a list of available statistic_id.""" statistic_ids = await hass.async_add_executor_job( validate_statistics, hass, ) connection.send_result(msg["id"], statistic_ids)
async def handle_remove( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict, ) -> None: """Remove a backup.""" manager: BackupManager = hass.data[DOMAIN] await manager.remove_backup(msg["slug"]) connection.send_result(msg["id"])
async def handle_create( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict, ) -> None: """Generate a backup.""" manager: BackupManager = hass.data[DOMAIN] backup = await manager.generate_backup() connection.send_result(msg["id"], backup)
async def ws_validate_statistics(hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict) -> None: """Fetch a list of available statistic_id.""" instance: Recorder = hass.data[DATA_INSTANCE] statistic_ids = await instance.async_add_executor_job( validate_statistics, hass, ) connection.send_result(msg["id"], statistic_ids)
def websocket_get_notifications(hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): """Return a list of persistent_notifications.""" connection.send_message( websocket_api.result_message(msg['id'], [{ key: data[key] for key in (ATTR_NOTIFICATION_ID, ATTR_MESSAGE, ATTR_STATUS, ATTR_TITLE, ATTR_CREATED_AT) } for data in hass.data[DOMAIN]['notifications'].values()]))
def websocket_sign_path(hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): """Handle a sign path request.""" connection.send_message( websocket_api.result_message( msg['id'], { 'path': async_sign_path(hass, connection.refresh_token_id, msg['path'], timedelta(seconds=msg['expires'])) }))
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. """ hass.data[DATA_INSTANCE].async_clear_statistics(msg["statistic_ids"]) connection.send_result(msg["id"])
async def ws_save_prefs( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict, manager: EnergyManager, ) -> None: """Handle get prefs command.""" msg_id = msg.pop("id") msg.pop("type") await manager.async_update(cast(EnergyPreferencesUpdate, msg)) connection.send_result(msg_id, manager.data)
def ws_list_person(hass: HomeAssistantType, connection: websocket_api.ActiveConnection, msg): """List persons.""" manager = hass.data[DOMAIN] # type: PersonManager connection.send_result( msg["id"], { "storage": manager.storage_persons, "config": manager.config_persons }, )
async def ws_backup_end(hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict) -> None: """Backup end notification.""" instance: Recorder = hass.data[DATA_INSTANCE] _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"])
def handle_get( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict ): """List all possible diagnostic handlers.""" domain = msg["domain"] if (info := hass.data[DOMAIN].get(domain)) is None: connection.send_error( msg["id"], websocket_api.ERR_NOT_FOUND, "Domain not supported" ) return
async def ws_get_list_statistic_ids(hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict) -> None: """Fetch a list of available statistic_id.""" statistic_ids = await get_instance(hass).async_add_executor_job( list_statistic_ids, hass, None, msg.get("statistic_type"), ) connection.send_result(msg["id"], statistic_ids)
def handle_info(hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict): """List all possible diagnostic handlers.""" connection.send_result( msg["id"], [{ "domain": domain, "handlers": {key: val is not None for key, val in info.items()}, } for domain, info in hass.data[DOMAIN].items()], )
async def hacs_repository_ignore( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any], ): """Ignore a repository.""" hacs: HacsBase = hass.data.get(DOMAIN) repository = hacs.repositories.get_by_id(msg["repository"]) hacs.common.ignored_repositories.append(repository.data.full_name) await hacs.data.async_write() connection.send_message(websocket_api.result_message(msg["id"]))
async def hacs_critical_list( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any], ): """List critical repositories.""" connection.send_message( websocket_api.result_message( msg["id"], (await async_load_from_store(hass, "critical") or []), ) )
async def hacs_repositories_removed( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any], ): """Get information about removed repositories.""" hacs: HacsBase = hass.data.get(DOMAIN) content = [] for repo in hacs.repositories.list_removed: if repo.repository not in hacs.common.ignored_repositories: content.append(repo.to_json()) connection.send_message(websocket_api.result_message(msg["id"], content))
def ws_get_prefs( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict, manager: EnergyManager, ) -> None: """Handle get prefs command.""" if manager.data is None: connection.send_error(msg["id"], websocket_api.ERR_NOT_FOUND, "No prefs") return connection.send_result(msg["id"], manager.data)
def ws_import_statistics( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict ) -> None: """Adjust sum statistics.""" metadata = msg["metadata"] stats = msg["stats"] 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"])
async def websocket_delete_refresh_token( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): """Handle a delete refresh token request.""" refresh_token = connection.user.refresh_tokens.get(msg["refresh_token_id"]) if refresh_token is None: return websocket_api.error_message(msg["id"], "invalid_token_id", "Received invalid token") await hass.auth.async_remove_refresh_token(refresh_token) connection.send_message(websocket_api.result_message(msg["id"], {}))
async def websocket_browse_media(hass: HomeAssistant, connection: ActiveConnection, msg: dict) -> None: """Browse available media.""" try: media = await async_browse_media(hass, msg.get("media_content_id", "")) connection.send_result( msg["id"], media.as_dict(), ) except BrowseError as err: connection.send_error(msg["id"], "browse_media_failed", str(err))
async def websocket_delete_refresh_token( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): """Handle a delete refresh token request.""" refresh_token = connection.user.refresh_tokens.get(msg['refresh_token_id']) if refresh_token is None: return websocket_api.error_message( msg['id'], 'invalid_token_id', 'Received invalid token') await hass.auth.async_remove_refresh_token(refresh_token) connection.send_message( websocket_api.result_message(msg['id'], {}))
async def hacs_repository_refresh( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any], ): """Refresh a repository.""" hacs: HacsBase = hass.data.get(DOMAIN) repository = hacs.repositories.get_by_id(msg["repository"]) await repository.update_repository(ignore_issues=True, force=True) await hacs.data.async_write() connection.send_message(websocket_api.result_message(msg["id"], {}))
async def ws_create_person(hass: HomeAssistantType, connection: websocket_api.ActiveConnection, msg): """Create a person.""" manager = hass.data[DOMAIN] # type: PersonManager try: person = await manager.async_create_person( name=msg['name'], user_id=msg.get('user_id'), device_trackers=msg['device_trackers']) connection.send_result(msg['id'], person) except ValueError as err: connection.send_error(msg['id'], websocket_api.const.ERR_INVALID_FORMAT, str(err))
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") instance = get_instance(hass) try: await instance.lock_database() except TimeoutError as err: connection.send_error(msg["id"], "timeout_error", str(err)) return connection.send_result(msg["id"])
def websocket_get_notifications( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): """Return a list of persistent_notifications.""" connection.send_message( websocket_api.result_message(msg['id'], [ { key: data[key] for key in (ATTR_NOTIFICATION_ID, ATTR_MESSAGE, ATTR_STATUS, ATTR_TITLE, ATTR_CREATED_AT) } for data in hass.data[DOMAIN]['notifications'].values() ]) )
async def hacs_repository_state( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any], ): """Set the state of a repository""" hacs: HacsBase = hass.data.get(DOMAIN) repository = hacs.repositories.get_by_id(msg["repository"]) repository.state = msg["state"] await hacs.data.async_write() connection.send_message(websocket_api.result_message(msg["id"], {}))
async def websocket_update_prefs(hass: HomeAssistant, connection: ActiveConnection, msg: dict) -> None: """Handle request for account info.""" prefs = hass.data[DATA_CAMERA_PREFS] changes = dict(msg) changes.pop("id") changes.pop("type") entity_id = changes.pop("entity_id") await prefs.async_update(entity_id, **changes) connection.send_result(msg["id"], prefs.get(entity_id).as_dict())
async def ws_delete_item( self, hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict ) -> None: """Delete a item.""" try: await self.storage_collection.async_delete_item(msg[self.item_id_key]) except ItemNotFound: connection.send_error( msg["id"], websocket_api.const.ERR_NOT_FOUND, f"Unable to find {self.item_id_key} {msg[self.item_id_key]}", ) connection.send_result(msg["id"])
async def ws_update_item( self, hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict ) -> None: """Update a item.""" data = dict(msg) msg_id = data.pop("id") item_id = data.pop(self.item_id_key) data.pop("type") try: item = await self.storage_collection.async_update_item(item_id, data) connection.send_result(msg_id, item) except ItemNotFound: connection.send_error( msg["id"], websocket_api.const.ERR_NOT_FOUND, f"Unable to find {self.item_id_key} {item_id}", ) except vol.Invalid as err: connection.send_error( msg["id"], websocket_api.const.ERR_INVALID_FORMAT, humanize_error(data, err), ) except ValueError as err: connection.send_error( msg_id, websocket_api.const.ERR_INVALID_FORMAT, str(err) )
async def ws_create_person(hass: HomeAssistantType, connection: websocket_api.ActiveConnection, msg): """Create a person.""" manager = hass.data[DOMAIN] # type: PersonManager try: person = await manager.async_create_person( name=msg['name'], user_id=msg.get('user_id'), device_trackers=msg['device_trackers'] ) connection.send_result(msg['id'], person) except ValueError as err: connection.send_error( msg['id'], websocket_api.const.ERR_INVALID_FORMAT, str(err))
async def ws_update_person(hass: HomeAssistantType, connection: websocket_api.ActiveConnection, msg): """Update a person.""" manager = hass.data[DOMAIN] # type: PersonManager changes = {} for key in ('name', 'user_id', 'device_trackers'): if key in msg: changes[key] = msg[key] try: person = await manager.async_update_person(msg['person_id'], **changes) connection.send_result(msg['id'], person) except ValueError as err: connection.send_error( msg['id'], websocket_api.const.ERR_INVALID_FORMAT, str(err))
async def websocket_create_long_lived_access_token( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): """Create or a long-lived access token.""" refresh_token = await hass.auth.async_create_refresh_token( connection.user, client_name=msg['client_name'], client_icon=msg.get('client_icon'), token_type=TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN, access_token_expiration=timedelta(days=msg['lifespan'])) access_token = hass.auth.async_create_access_token( refresh_token) connection.send_message( websocket_api.result_message(msg['id'], access_token))
def websocket_refresh_tokens( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): """Return metadata of users refresh tokens.""" current_id = connection.refresh_token_id connection.send_message(websocket_api.result_message(msg['id'], [{ 'id': refresh.id, 'client_id': refresh.client_id, 'client_name': refresh.client_name, 'client_icon': refresh.client_icon, 'type': refresh.token_type, 'created_at': refresh.created_at, 'is_current': refresh.id == current_id, 'last_used_at': refresh.last_used_at, 'last_used_ip': refresh.last_used_ip, } for refresh in connection.user.refresh_tokens.values()]))
async def handle_info(hass: HomeAssistantType, connection: websocket_api.ActiveConnection, msg: Dict): """Handle an info request.""" info_callbacks = hass.data.get(DOMAIN, {}).get('info', {}) data = OrderedDict() data['homeassistant'] = \ await hass.helpers.system_info.async_get_system_info() if info_callbacks: for domain, domain_data in zip(info_callbacks, await asyncio.gather(*[ _info_wrapper(hass, info_callback) for info_callback in info_callbacks.values() ])): data[domain] = domain_data connection.send_message(websocket_api.result_message(msg['id'], data))
async def websocket_current_user( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): """Return the current user.""" user = connection.user enabled_modules = await hass.auth.async_get_enabled_mfa(user) connection.send_message( websocket_api.result_message(msg['id'], { 'id': user.id, 'name': user.name, 'is_owner': user.is_owner, 'is_admin': user.is_admin, 'credentials': [{'auth_provider_type': c.auth_provider_type, 'auth_provider_id': c.auth_provider_id} for c in user.credentials], 'mfa_modules': [{ 'id': module.id, 'name': module.name, 'enabled': module.id in enabled_modules, } for module in hass.auth.auth_mfa_modules], }))
async def websocket_get_user_registrations( hass: HomeAssistantType, connection: ActiveConnection, msg: dict) -> None: """Return all registrations or just registrations for given user ID.""" user_id = msg.get(CONF_USER_ID, connection.user.id) if user_id != connection.user.id and not connection.user.is_admin: # If user ID is provided and is not current user ID and current user # isn't an admin user connection.send_error(msg['id'], ERR_UNAUTHORIZED, "Unauthorized") return user_registrations = [] for config_entry in hass.config_entries.async_entries(domain=DOMAIN): registration = config_entry.data if connection.user.is_admin or registration[CONF_USER_ID] is user_id: user_registrations.append(safe_registration(registration)) connection.send_message( result_message(msg['id'], user_registrations))
async def websocket_delete_registration(hass: HomeAssistantType, connection: ActiveConnection, msg: dict) -> None: """Delete the registration for the given webhook_id.""" user = connection.user webhook_id = msg.get(CONF_WEBHOOK_ID) if webhook_id is None: connection.send_error(msg['id'], ERR_INVALID_FORMAT, "Webhook ID not provided") return config_entry = hass.data[DOMAIN][DATA_CONFIG_ENTRIES][webhook_id] registration = config_entry.data if registration is None: connection.send_error(msg['id'], ERR_NOT_FOUND, "Webhook ID not found in storage") return if registration[CONF_USER_ID] != user.id and not user.is_admin: return error_message( msg['id'], ERR_UNAUTHORIZED, 'User is not registration owner') await hass.config_entries.async_remove(config_entry.entry_id) hass.data[DOMAIN][DATA_DELETED_IDS].append(webhook_id) store = hass.data[DOMAIN][DATA_STORE] try: await store.async_save(savable_state(hass)) except HomeAssistantError: return error_message( msg['id'], 'internal_error', 'Error deleting registration') if (CONF_CLOUDHOOK_URL in registration and "cloud" in hass.config.components): await async_delete_cloudhook(hass, webhook_id) connection.send_message(result_message(msg['id'], 'ok'))