Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
409 changes: 23 additions & 386 deletions custom_components/view_assist/__init__.py

Large diffs are not rendered by default.

57 changes: 35 additions & 22 deletions custom_components/view_assist/assets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@

_LOGGER = logging.getLogger(__name__)

ASSETS_MANAGER = "assets_manager"


class AssetClass(StrEnum):
"""Asset class."""
Expand Down Expand Up @@ -136,6 +134,14 @@ async def update_last_commit(self, asset_class: str, last_commit: str):
class AssetsManager:
"""Class to manage VA asset installs/updates/deletes etc."""

@classmethod
def get(cls, hass: HomeAssistant) -> "AssetsManager":
"""Get the asset manager."""
try:
return hass.data[DOMAIN][cls.__name__]
except KeyError:
return None

def __init__(self, hass: HomeAssistant, config: VAConfigEntry) -> None:
"""Initialise."""
self.hass = hass
Expand All @@ -148,7 +154,6 @@ def __init__(self, hass: HomeAssistant, config: VAConfigEntry) -> None:
async def async_setup(self) -> None:
"""Set up the AssetManager."""
try:
_LOGGER.debug("Setting up AssetsManager")
self.data = await self.store.load()

# Setup managers
Expand Down Expand Up @@ -196,6 +201,7 @@ async def async_setup(self) -> None:
timedelta(minutes=VERSION_CHECK_INTERVAL),
)
)

except Exception as ex:
_LOGGER.error("Error setting up AssetsManager. Error is %s", ex)
raise HomeAssistantError(f"Error setting up AssetsManager: {ex}") from ex
Expand Down Expand Up @@ -291,18 +297,17 @@ async def async_update_version_info(
# Reduces download by only getting version from repo if the last commit date is greater than
# we have stored
update_from_repo = True
if self.data.get("last_commit"):
if repo_last_commit := await manager.async_get_last_commit():
stored_last_commit = self.data.get("last_commit").get(asset_class)
if repo_last_commit == stored_last_commit:
_LOGGER.debug(
"No new updates in repo for %s",
asset_class,
)
update_from_repo = False
repo_last_commit = await manager.async_get_last_commit()
if repo_last_commit and self.data.get("last_commit"):
stored_last_commit = self.data.get("last_commit").get(asset_class)
if repo_last_commit == stored_last_commit:
_LOGGER.debug(
"No new updates in repo for %s",
asset_class,
)
update_from_repo = False

if update_from_repo:
repo_last_commit = await manager.async_get_last_commit()
_LOGGER.debug("New updates in repo for %s", asset_class)
self.data.setdefault("last_commit", {})
self.data["last_commit"][asset_class] = repo_last_commit
Expand All @@ -311,13 +316,14 @@ async def async_update_version_info(
if version_info := await manager.async_get_version_info(update_from_repo):
for name, versions in version_info.items():
self.data[asset_class][name] = versions
# Fire update entity update event
if versions["installed"]:
self._fire_updates_update(
asset_class,
name,
AwesomeVersion(versions["installed"]) >= versions["latest"],
)
# Fire update entity update event if asset is installed or new asset
self._fire_updates_update(
asset_class,
name,
AwesomeVersion(versions["installed"]) >= versions["latest"]
if versions["installed"]
else False,
)

await self.store.update(asset_class, None, self.data[asset_class])
_LOGGER.debug("Latest versions updated")
Expand Down Expand Up @@ -357,11 +363,18 @@ async def async_install_or_update(
await self.store.update(asset_class, name, self.data[asset_class][name])

def _fire_updates_update(
self, asset_class: AssetClass, name: str, remove: bool
self,
asset_class: AssetClass,
name: str,
remove: bool,
) -> None:
"""Fire update entity update event."""
async_dispatcher_send(
self.hass,
VA_ADD_UPDATE_ENTITY_EVENT,
{"asset_class": asset_class, "name": name, "remove": remove},
{
"asset_class": asset_class,
"name": name,
"remove": remove,
},
)
8 changes: 5 additions & 3 deletions custom_components/view_assist/assets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from dataclasses import dataclass
from typing import Any

from config.custom_components.view_assist.const import VA_ASSET_UPDATE_PROGRESS
from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_send

from ..const import VA_ASSET_UPDATE_PROGRESS # noqa: TID252
from ..typed import VAConfigEntry # noqa: TID252
from . import VAConfigEntry
from .download_manager import DownloadManager


Expand Down Expand Up @@ -58,7 +58,9 @@ async def async_get_latest_version(self, name: str) -> dict[str, Any]:
"""Get latest version of asset from repo."""
raise NotImplementedError

async def async_get_version_info(self) -> dict[str, Any]:
async def async_get_version_info(
self, update_from_repo: bool = True
) -> dict[str, Any]:
"""Update versions from repo."""
raise NotImplementedError

Expand Down
2 changes: 1 addition & 1 deletion custom_components/view_assist/assets/blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ def _copy_file_to_dir(self, source_file: Path, dest_file: Path) -> None:
"""Copy a file to a directory."""
try:
dest_file.parent.mkdir(parents=True, exist_ok=True)
with Path.open(dest_file, "wb") as f:
with Path.open(dest_file, "wb", encoding="utf-8") as f:
f.write(source_file.read_bytes())
except OSError as ex:
raise AssetManagerException(
Expand Down
50 changes: 47 additions & 3 deletions custom_components/view_assist/assets/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

from dataclasses import dataclass
import logging
import operator
from pathlib import Path
Expand Down Expand Up @@ -29,14 +30,57 @@
GITHUB_DEV_BRANCH,
)
from ..helpers import differ_to_json, get_key, json_to_dictdiffer # noqa: TID252
from ..typed import VAConfigEntry # noqa: TID252
from ..utils import dictdiff # noqa: TID252
from ..websocket import MockWSConnection # noqa: TID252
from . import VAConfigEntry
from .base import AssetManagerException, BaseAssetManager, InstallStatus
from .utils import dictdiff

_LOGGER = logging.getLogger(__name__)


class MockWSConnection:
"""Mock a websocket connection to be able to call websocket handler functions.

This is here for creating the View Assist dashboard
"""

@dataclass
class MockAdminUser:
"""Mock admin user for use in MockWSConnection."""

is_admin = True

def __init__(self, hass: HomeAssistant) -> None:
"""Initilise."""
self.hass = hass
self.user = self.MockAdminUser()

self.failed_request: bool = False

def send_result(self, id, item):
"""Receive result."""
self.failed_request = False

def send_error(self, id, code, msg):
"""Receive error."""
self.failed_request = True

def execute_ws_func(self, ws_type: str, msg: dict[str, Any]) -> bool:
"""Execute ws function."""
if self.hass.data["websocket_api"].get(ws_type):
try:
handler, schema = self.hass.data["websocket_api"][ws_type]
if schema is False:
handler(self.hass, self, msg)
else:
handler(self.hass, self, schema(msg))
except Exception as ex: # noqa: BLE001
_LOGGER.error("Error calling %s. Error is %s", ws_type, ex)
return False
else:
return True
return False


class DashboardManager(BaseAssetManager):
"""Class to manage dashboard assets."""

Expand Down
Loading