Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash HA on enabling integration #1508

Open
zalewskigrzegorz opened this issue Jun 18, 2024 · 29 comments
Open

Crash HA on enabling integration #1508

zalewskigrzegorz opened this issue Jun 18, 2024 · 29 comments
Labels

Comments

@zalewskigrzegorz
Copy link

Describe the bug
After installing this form HACS and adding integration from the menu, the entire machine froze.

To Reproduce
Steps to reproduce the behavior:

  1. Go to HACS.
  2. Install all required packages.
  3. Add integration from the menu.
  4. Wait for HA to crash.
  5. See over 4GB of logs.

Expected behavior
HA should work and not generate errors

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
Add any other context about the problem here.

Related Logs (can be found in the browser-console (F12))

Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/usr/src/homeassistant/homeassistant/__main__.py", line 223, in <module>
    sys.exit(main())
  File "/usr/src/homeassistant/homeassistant/__main__.py", line 209, in main
    exit_code = runner.run(runtime_conf)
  File "/usr/src/homeassistant/homeassistant/runner.py", line 190, in run
    return loop.run_until_complete(setup_and_run_hass(runtime_config))
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 672, in run_until_complete
    self.run_forever()
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 639, in run_forever
    self._run_once()
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 1988, in _run_once
    handle._run()
  File "/usr/local/lib/python3.12/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/src/homeassistant/homeassistant/core.py", line 2741, in async_call
    response_data = await coro
  File "/usr/src/homeassistant/homeassistant/core.py", line 2784, in _execute_service
    return await target(service_call)
  File "/config/custom_components/ui_lovelace_minimalist/base.py", line 509, in handle_reload
    # Copy chosen language file over to config dir
  File "/config/custom_components/ui_lovelace_minimalist/base.py", line 532, in reload_configuration
    )

2024-06-18 03:45:49.954 WARNING (MainThread) [homeassistant.util.loop] Detected blocking call to open inside the event loop by custom integration 'ui_lovelace_minimalist' at custom_components/ui_lovelace_minimalist/base.py, line 532: ) (offender: /usr/local/lib/python3.12/shutil.py, line 262: with open(dst, 'wb') as fdst:), please create a bug report at https://github.com/UI-Lovelace-Minimalist/UI/issues
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/usr/src/homeassistant/homeassistant/__main__.py", line 223, in <module>
    sys.exit(main())
  File "/usr/src/homeassistant/homeassistant/__main__.py", line 209, in main
    exit_code = runner.run(runtime_conf)
  File "/usr/src/homeassistant/homeassistant/runner.py", line 190, in run
    return loop.run_until_complete(setup_and_run_hass(runtime_config))
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 672, in run_until_complete
    self.run_forever()
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 639, in run_forever
    self._run_once()
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 1988, in _run_once
    handle._run()
  File "/usr/local/lib/python3.12/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/src/homeassistant/homeassistant/core.py", line 2741, in async_call
    response_data = await coro
  File "/usr/src/homeassistant/homeassistant/core.py", line 2784, in _execute_service
    return await target(service_call)
  File "/config/custom_components/ui_lovelace_minimalist/base.py", line 509, in handle_reload
    # Copy chosen language file over to config dir
  File "/config/custom_components/ui_lovelace_minimalist/base.py", line 532, in reload_configuration
    )
@dw-1987
Copy link

dw-1987 commented Jun 18, 2024

Hello, I have this same issue! After I install the add on via HACS I reboot HA and then I am trying to configure it in Add integration the hole system freezes.

@astumpf
Copy link

astumpf commented Jun 18, 2024

Same here. Addon v1.3.9 does not work at all. Cards are visualized broken.
HAOS:
Core 2024.6.3
Supervisor 2024.06.0
Operating System 12.4
Frontend 20240610.1

@JaroslawPalczynski
Copy link

Same here.

@reydelleon
Copy link

reydelleon commented Jun 18, 2024

Seems connected to the use of the shutil library to copy files in the base.py file. From what limited understanding I have, a synchronous call is being made (shutil.copy***) in an asynchronous context (async) methods. There is an aioshutil library that could be used for async calls, but I don't know enough python to make that change.

There is also the recommended use of hass.async_add_executor_job() by the Home Assistant developers documentation.

@zalewskigrzegorz
Copy link
Author

I tried to fix this last night with GPT 😄 but I give up. Since I don't want to recover backups on every try.

@reydelleon
Copy link

What approach did you try?

@dekiel123
Copy link

I have the same.
Anyone managed to solve this?
image

@corey-klempner
Copy link

corey-klempner commented Jun 20, 2024

Also having this issue. Likely related to the HA Core update earlier this week?

@boergegrunicke
Copy link

Same problem for me

@gondhijagapathi
Copy link

same problem, anyone solved it?

@ladykira2022
Copy link

Same issue here. Uninstalled and installed manually, crashes when I enable the community cards via github

@Amateur-God
Copy link

Amateur-God commented Jun 26, 2024

I tried to fix this last night with GPT 😄 but I give up. Since I don't want to recover backups on every try.

you dont need to restore backsups just use the home assistant dev enviroment or if you really want to dev on live then just

Go to the cmd shell (connect a monitor and keyboard).
Type “login” to get into the Linux shell.

Integrations are stored here:
/mnt/data/supervisor/homeassistant/.storage/core.config_entries

Using vi you can delete sections out of this file which removes the integration. (should be at the bottom if its the last integration you installed, make sure to remove the , from the close bracket of the entry before it since that becomes the last entry
Use vi core.config_entries
Then use i to enter insert mode and delete (backspace) the section you want to remove.
Then use esc to enter command mode again.
Use :wq to write and exit.

Some basics VI editor commands
i — Switch to Insert mode.
Esc — Switch to Command mode.
:w — Save and continue editing.
:wq or ZZ — Save and quit/exit vi.
:q! — Quit vi and do not save changes.

@Amateur-God
Copy link

Seems connected to the use of the shutil library to copy files in the base.py file. From what limited understanding I have, a synchronous call is being made (shutil.copy***) in an asynchronous context (async) methods. There is an aioshutil library that could be used for async calls, but I don't know enough python to make that change.

There is also the recommended use of hass.async_add_executor_job() by the Home Assistant developers documentation.

i tried this however this doesnt fix it, even with it set up for async jobs it crashes home assistant, im not entirely sure whats causing the crash

this is the approach i tried to get it working if anyone has any inputs

"""Base UI Lovelace Minimalist class."""


from __future__ import annotations
import asyncio
from dataclasses import asdict, dataclass, field
import logging
import os
import pathlib
import shutil
from typing import Any, Awaitable, Callable

from aiogithubapi import (
    GitHubAPI,
    GitHubAuthenticationException,
    GitHubException,
    GitHubNotModifiedException,
    GitHubRatelimitException,
)
from homeassistant.components.frontend import add_extra_js_url, async_remove_panel
from homeassistant.components.lovelace import _register_panel
from homeassistant.components.lovelace.dashboard import LovelaceYAML
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.core import HomeAssistant
from homeassistant.loader import Integration

from .const import (
    COMMUNITY_CARDS_FOLDER,
    DEFAULT_COMMUNITY_CARDS_ENABLED,
    DEFAULT_INCLUDE_OTHER_CARDS,
    DEFAULT_LANGUAGE,
    DEFAULT_SIDEPANEL_ENABLED,
    DEFAULT_SIDEPANEL_ICON,
    DEFAULT_SIDEPANEL_TITLE,
    DEFAULT_THEME,
    DEFAULT_THEME_PATH,
    DOMAIN,
    GITHUB_REPO,
    LANGUAGES,
    TV,
)
from .enums import ConfigurationType, UlmDisabledReason
from .utils.decode import decode_content

_LOGGER: logging.Logger = logging.getLogger(__name__)


@dataclass
class UlmSystem:
    """ULM System info."""

    disabled_reason: UlmDisabledReason | None = None
    running: bool = False

    @property
    def disabled(self) -> bool:
        """Return if ULM is disabled."""
        return self.disabled_reason is not None


@dataclass
class UlmConfiguration:
    """UlmConfiguration class."""

    config: dict[str, Any] = field(default_factory=dict)
    config_entry: ConfigEntry | None = None
    config_type: ConfigurationType | None = None
    sidepanel_enabled: bool = DEFAULT_SIDEPANEL_ENABLED
    sidepanel_icon: str = DEFAULT_SIDEPANEL_ICON
    sidepanel_title: str = DEFAULT_SIDEPANEL_TITLE
    adaptive_ui_enabled: bool = DEFAULT_SIDEPANEL_ENABLED
    adaptive_ui_icon: str = DEFAULT_SIDEPANEL_ICON
    adaptive_ui_title: str = DEFAULT_SIDEPANEL_TITLE
    theme_path: str = DEFAULT_THEME_PATH
    theme: str = DEFAULT_THEME
    plugin_path: str = "www/community/"
    include_other_cards: bool = DEFAULT_INCLUDE_OTHER_CARDS
    language: str = DEFAULT_LANGUAGE
    community_cards_enabled = bool = DEFAULT_COMMUNITY_CARDS_ENABLED
    community_cards: list = field(default_factory=list)
    all_community_cards: list = field(default_factory=list)
    token: str = None

    def to_dict(self) -> dict:
        """Return Dict."""
        return self.__dict__

    def to_json(self) -> str:
        """Return a json string."""
        return asdict(self)

    def update_from_dict(self, data: dict) -> None:
        """Set attributes from dicts."""
        if not isinstance(data, dict):
            raise Exception("Configuration is not valid.")

        for key in data:
            self.__setattr__(key, data[key])


class UlmBase:
    """Base UI Lovelace Minimalist."""

    integration: Integration | None = None
    configuration = UlmConfiguration()
    hass: HomeAssistant | None = None
    log: logging.Logger = _LOGGER
    githubapi: GitHubAPI | None = None
    system = UlmSystem()
    version: str | None = None

    @property
    def integration_dir(self) -> pathlib.Path:
        """Return the ULM integration dir."""
        return self.integration.file_path

    @property
    def templates_dir(self) -> pathlib.Path:
        """Return the Button Cards Template dir."""
        return pathlib.Path(f"{self.integration_dir}/__ui_minimalist__/ulm_templates")

    @property
    def community_cards_dir(self) -> pathlib.Path:
        """Return the Community cards dir inside Template dir."""
        return pathlib.Path(f"{self.templates_dir}/community_cards")

    def disable_ulm(self, reason: UlmDisabledReason) -> None:
        """Disable Ulm."""

        if self.system.disabled_reason == reason:
            return

        self.system.disabled_reason = reason
        if reason == UlmDisabledReason.INVALID_TOKEN:
            self.configuration.config_entry.state = ConfigEntryState.SETUP_ERROR
            self.configuration.config_entry.reason = "Authentication Failed"
            self.hass.add_job(
                self.configuration.config_entry.async_start_reauth, self.hass
            )

    def enable_ulm(self) -> None:
        """Enable Ulm."""
        if self.system.disabled_reason is not None:
            self.system.disabled_reason = None
            self.log.info("ULM is enabled")

    async def async_save_file(self, file_path: str, content: Any) -> bool:
        """Save a file."""

        self.log.debug("Saving file: %s" % file_path)

        def _write_file():
            os.makedirs(os.path.dirname(file_path), exist_ok=True)
            with open(
                file_path,
                mode="w" if isinstance(content, str) else "wb",
                encoding="utf-8" if isinstance(content, str) else None,
                errors="ignore" if isinstance(content, str) else None,
            ) as file_handler:
                file_handler.write(content)

        try:
            await self.hass.async_add_executor_job(_write_file)
        except BaseException as error:  # lgtm [py/catch-base-exception] pylint: disable=broad-except
            self.log.error(f"Could not write data to {file_path} - {error}")
            return False

        return os.path.exists(file_path)

    async def async_github_get_file(self, filename: str) -> list:
        """Get the content of a file."""
        self.log.debug("Fetching github file: %s" % filename)
        response = await self.async_github_api_method(
            method=self.githubapi.repos.contents.get,
            repository=GITHUB_REPO,
            path=filename,
        )
        if response is None:
            return []
        return decode_content(response.data.content)

    async def async_github_get_tree(self, path: str) -> list:
        """Get the content of a directory."""
        self.log.debug("Fetching github tree: %s" % path)
        response = await self.async_github_api_method(
            method=self.githubapi.repos.contents.get, repository=GITHUB_REPO, path=path
        )
        if response is None:
            return []
        return response.data

    async def async_github_api_method(
        self,
        method: Callable[[], Awaitable[TV]],
        *args,
        raise_exception: bool = True,
        **kwargs,
    ) -> TV | None:
        """Call a GitHub API method."""
        _exception = None

        try:
            return await method(*args, **kwargs)
        except GitHubAuthenticationException as exception:
            self.disable_ulm(UlmDisabledReason.INVALID_TOKEN)
            _exception = exception
        except GitHubRatelimitException as exception:
            _exception = exception
        except GitHubNotModifiedException as exception:
            raise exception
        except GitHubException as exception:
            _exception = exception
        except BaseException as exception:  # lgtm [py/catch-base-exception] pylint: disable=broad-except
            self.log.exception(exception)
            _exception = exception

        if raise_exception and _exception is not None:
            raise Exception(_exception)
        return None

    async def fetch_cards(self) -> None:
        """Fetch list of cards."""
        response = await self.async_github_api_method(
            method=self.githubapi.repos.contents.get,
            repository=GITHUB_REPO,
            path=COMMUNITY_CARDS_FOLDER,
        )
        if response is None:
            return []
        self.configuration.all_community_cards = [
            c.name for c in response.data if c.type == "dir"
        ]

    async def configure_community_cards(self) -> None:
        """Configure selected community cards."""
        self.log.info("Configuring selected community cards")

        language = LANGUAGES[self.configuration.language]
        os.makedirs(self.community_cards_dir, exist_ok=True)

        if (
            not self.configuration.community_cards_enabled
            or self.configuration.community_cards == []
        ):
            await self.hass.async_add_executor_job(shutil.rmtree, f"{self.community_cards_dir}/", True)
        elif self.configuration.community_cards_enabled:
            existing_cards = [
                f.path for f in os.scandir(self.community_cards_dir) if f.is_dir()
            ]
            for e in existing_cards:
                card_dir = os.path.basename(e)
                # Delete unselected folders
                if card_dir not in self.configuration.community_cards:
                    self.log.debug(
                        f"Deleting community card folder {card_dir}, not selected anymore."
                    )
                    await self.hass.async_add_executor_job(shutil.rmtree, e, True)
                if card_dir not in self.configuration.all_community_cards:
                    self.log.debug(
                        f"Deleting community card folder {card_dir}, that is not existing anymore on Github."
                    )
                    await self.hass.async_add_executor_job(shutil.rmtree, e, True)

            for card in self.configuration.community_cards:
                if card not in self.configuration.all_community_cards:
                    self.configuration.community_cards.remove(card)
                else:
                    card_files = await self.async_github_get_tree(
                        path=f"{COMMUNITY_CARDS_FOLDER}/{card}"
                    )
                    for f in card_files:
                        if f.type == "file":
                            card_file_path = (
                                f"{self.community_cards_dir}/{card}/{f.name}"
                            )
                            if (
                                not os.path.exists(card_file_path)
                                or os.path.getsize(card_file_path) != f.size
                            ):
                                await self.async_save_file(
                                    file_path=card_file_path,
                                    content=await self.async_github_get_file(
                                        filename=f.path
                                    ),
                                )
                        elif f.type == "dir" and f.name == "languages":
                            language_files = await self.async_github_get_tree(
                                path=f.path
                            )
                            for lang in language_files:
                                lang_file_path = f"{self.community_cards_dir}/{card}/languages/{lang.name}"
                                if pathlib.Path(lang.name).stem == language:
                                    if (
                                        not os.path.exists(lang_file_path)
                                        or os.path.getsize(lang_file_path) != lang.size
                                    ):
                                        await self.async_save_file(
                                            file_path=lang_file_path,
                                            content=await self.async_github_get_file(
                                                filename=lang.path
                                            ),
                                        )

    async def configure_plugins(self) -> bool:
        """Configure the Plugins ULM depends on."""
        self.log.debug("Checking Dependencies.")

        try:
            if not os.path.exists(
                self.hass.config.path("custom_components/browser_mod")
            ):
                self.log.error('HACS Integration repo "browser mod" is not installed!')

            depenceny_resource_paths = [
                "button-card",
                "light-entity-card",
                "lovelace-card-mod",
                "lovelace-auto-entities",
                "mini-graph-card",
                "mini-media-player",
                "my-cards",
                "simple-weather-card",
                "lovelace-layout-card",
                "lovelace-state-switch",
                "weather-radar-card",
            ]
            for p in depenceny_resource_paths:
                if not self.configuration.include_other_cards:
                    if not os.path.exists(self.hass.config.path(f"www/community/{p}")):
                        self.log.error(
                            f'HACS Frontend repo "{p}" is not installed, See Integration Configuration.'
                        )
                else:
                    if os.path.exists(self.hass.config.path(f"www/community/{p}")):
                        _LOGGER.error(
                            f'HACS Frontend repo "{p}" is already installed, Remove it or disable include custom cards'
                        )

            if self.configuration.include_other_cards:
                for c in depenceny_resource_paths:
                    add_extra_js_url(
                        self.hass, f"/ui_lovelace_minimalist/cards/{c}/{c}.js"
                    )

            # Register
            self.hass.http.register_static_path(
                "/ui_lovelace_minimalist/cards",
                self.hass.config.path(f"{self.integration_dir}/cards"),
                True,
            )

        except Exception as exception:
            self.log.error(exception)
            self.disable_ulm(UlmDisabledReason.LOAD_ULM)
            return False

        return True

    async def configure_dashboard(self) -> bool:
        """Configure the ULM Dashboards."""

        dashboard_url = "ui-lovelace-minimalist"
        dashboard_config = {
            "mode": "yaml",
            "icon": self.configuration.sidepanel_icon,
            "title": self.configuration.sidepanel_title,
            "filename": "ui_lovelace_minimalist/dashboard/ui-lovelace.yaml",
            "show_in_sidebar": True,
            "require_admin": False,
        }

        adv_dashboard_url = "adaptive-dash"
        adv_dashboard_config = {
            "mode": "yaml",
            "icon": self.configuration.adaptive_ui_icon,
            "title": self.configuration.adaptive_ui_title,
            "filename": "ui_lovelace_minimalist/dashboard/adaptive-dash/adaptive-ui.yaml",
            "show_in_sidebar": True,
            "require_admin": False,
        }
        # Optoinal override can be done with config_flow?
        # if not dashboard_url in hass.data["lovelace"]["dashboards"]:
        try:
            if self.configuration.sidepanel_enabled:
                self.hass.data["lovelace"]["dashboards"][dashboard_url] = LovelaceYAML(
                    self.hass, dashboard_url, dashboard_config
                )

                _register_panel(
                    self.hass, dashboard_url, "yaml", dashboard_config, True
                )
            else:
                if dashboard_url in self.hass.data["lovelace"]["dashboards"]:
                    async_remove_panel(self.hass, "ui-lovelace-minimalist")

            if self.configuration.adaptive_ui_enabled:
                self.hass.data["lovelace"]["dashboards"][
                    adv_dashboard_url
                ] = LovelaceYAML(self.hass, adv_dashboard_url, adv_dashboard_config)

                _register_panel(
                    self.hass, adv_dashboard_url, "yaml", adv_dashboard_config, True
                )
            else:
                if adv_dashboard_url in self.hass.data["lovelace"]["dashboards"]:
                    async_remove_panel(self.hass, "adaptive-dash")

        except Exception as exception:
            self.log.error(exception)
            self.disable_ulm(UlmDisabledReason.LOAD_ULM)
            return False

        return True

    async def configure_ulm(self) -> bool:
        """Configure initial dashboard & cards directory."""
        self.log.info("Setup ULM Configuration")

        try:

            # Cleanup
            await self.hass.async_add_executor_job(shutil.rmtree, self.hass.config.path(f"{DOMAIN}/configs"), True)
            await self.hass.async_add_executor_job(shutil.rmtree, self.hass.config.path(f"{DOMAIN}/addons"), True)
            # Create config dir
            os.makedirs(self.hass.config.path(f"{DOMAIN}/dashboard"), exist_ok=True)
            os.makedirs(self.hass.config.path(f"{DOMAIN}/custom_cards"), exist_ok=True)
            os.makedirs(self.hass.config.path(f"{DOMAIN}/custom_actions"), exist_ok=True)

            if os.path.exists(self.hass.config.path(f"{DOMAIN}/dashboard")):
                os.makedirs(self.templates_dir, exist_ok=True)

                # Translations
                language = LANGUAGES[self.configuration.language]

                # Copy default language file over to config dir
                await self.hass.async_add_executor_job(
                    shutil.copy2,
                    f"{self.integration_dir}/lovelace/translations/default.yaml",
                    f"{self.templates_dir}/default.yaml",
                )
                # Copy example dashboard file over to user config dir if not exists
                if self.configuration.sidepanel_enabled:
                    if not os.path.exists(
                        self.hass.config.path(f"{DOMAIN}/dashboard/ui-lovelace.yaml")
                    ):
                        await self.hass.async_add_executor_job(
                            shutil.copy2,
                            f"{self.integration_dir}/lovelace/ui-lovelace.yaml",
                            self.hass.config.path(
                                f"{DOMAIN}/dashboard/ui-lovelace.yaml"
                            ),
                        )
                # Copy adaptive dashboard if not exists and is selected as option
                if self.configuration.adaptive_ui_enabled:
                    if not os.path.exists(
                        self.hass.config.path(f"{DOMAIN}/dashboard/adaptive-dash")
                    ):
                        await self.hass.async_add_executor_job(
                            lambda: shutil.copytree(
                                f"{self.integration_dir}/lovelace/adaptive-dash",
                                self.hass.config.path(f"{DOMAIN}/dashboard/adaptive-dash"),
                                dirs_exist_ok=True,
                            )
                        )
                # Copy example custom actions file over to user config dir if not exists
                if not os.path.exists(
                    self.hass.config.path(
                        f"{DOMAIN}/custom_actions/custom_actions.yaml"
                    )
                ):
                    await self.hass.async_add_executor_job(
                        shutil.copy2,
                        f"{self.integration_dir}/lovelace/custom_actions.yaml",
                        self.hass.config.path(
                            f"{DOMAIN}/custom_actions/custom_actions.yaml"
                        ),
                    )
                # Copy chosen language file over to config dir
                await self.hass.async_add_executor_job(
                    shutil.copy2,
                    f"{self.integration_dir}/lovelace/translations/{language}.yaml",
                    f"{self.templates_dir}/language.yaml",
                )
                # Copy over cards from integration
                await self.hass.async_add_executor_job(
                    lambda: shutil.copytree(
                        f"{self.integration_dir}/lovelace/ulm_templates",
                        f"{self.templates_dir}",
                        dirs_exist_ok=True,
                    )
                )
                # Copy over manually installed custom_cards from user
                await self.hass.async_add_executor_job(
                    lambda: shutil.copytree(
                        self.hass.config.path(f"{DOMAIN}/custom_cards"),
                        f"{self.templates_dir}/custom_cards",
                        dirs_exist_ok=True,
                    )
                )
                # Copy over manually installed custom_actions from user
                await self.hass.async_add_executor_job(
                    lambda: shutil.copytree(
                        self.hass.config.path(f"{DOMAIN}/custom_actions"),
                        f"{self.templates_dir}/custom_actions",
                        dirs_exist_ok=True,
                    )
                )
                # Copy over themes to defined themes folder
                await self.hass.async_add_executor_job(
                    lambda: shutil.copytree(
                        f"{self.integration_dir}/lovelace/themefiles",
                        self.hass.config.path(f"{self.configuration.theme_path}/"),
                        dirs_exist_ok=True,
                    )
                )

            self.hass.bus.async_fire("ui_lovelace_minimalist_reload")

            async def handle_reload(call):
                _LOGGER.debug("Reload UI Lovelace Minimalist Configuration")

                self.reload_configuration()

            # Register servcie ui_lovelace_minimalist.reload
            self.hass.services.async_register(DOMAIN, "reload", handle_reload)

        except Exception as exception:
            self.log.error(exception)
            self.disable_ulm(UlmDisabledReason.LOAD_ULM)
            return False

        return True

    def reload_configuration(self):
        """Reload Configuration."""
        if os.path.exists(self.hass.config.path(f"{DOMAIN}/custom_cards")):
            # Copy over manually installed custom_cards from user
            self.hass.async_add_executor_job(
                lambda: shutil.copytree(
                    self.hass.config.path(f"{DOMAIN}/custom_cards"),
                    f"{self.templates_dir}/custom_cards",
                    dirs_exist_ok=True,
                )
            )
        if os.path.exists(self.hass.config.path(f"{DOMAIN}/custom_actions")):
            # Copy over manually installed custom_actions from user
            self.hass.async_add_executor_job(
                lambda: shutil.copytree(
                    self.hass.config.path(f"{DOMAIN}/custom_actions"),
                    f"{self.templates_dir}/custom_actions",
                    dirs_exist_ok=True,
                )
            )
        self.hass.bus.async_fire("ui_lovelace_minimalist_reload")

@reydelleon
Copy link

reydelleon commented Jun 26, 2024

I tried that same approach on a fork and the thing still crashes. I think we need someone more versed in Home Assistant development to either work it out or at least gives pointers on where to look.

@VNDCK
Copy link

VNDCK commented Jun 27, 2024

I'm experiencing the same issue. Since i'm installing from scratch, it's unusable at the moment.

@droans
Copy link

droans commented Jun 27, 2024

It looks like the integration gets stuck in a loop. I enabled debug logging and it begins checking every half-second if the other front-end cards are installed and then reloading itself if they are not.

...

2024-06-27 15:09:06.179 DEBUG (MainThread) [custom_components.ui_lovelace_minimalist] Reload the config entry
2024-06-27 15:09:06.179 INFO (MainThread) [custom_components.ui_lovelace_minimalist.base] Setup ULM Configuration
2024-06-27 15:09:06.667 DEBUG (MainThread) [custom_components.ui_lovelace_minimalist.base] Checking Dependencies.
2024-06-27 15:09:06.667 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Integration repo "browser mod" is not installed!
2024-06-27 15:09:06.668 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "light-entity-card" is not installed, See Integration Configuration.
2024-06-27 15:09:06.668 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "mini-media-player" is not installed, See Integration Configuration.
2024-06-27 15:09:06.668 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "my-cards" is not installed, See Integration Configuration.
2024-06-27 15:09:06.668 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "simple-weather-card" is not installed, See Integration Configuration.
2024-06-27 15:09:06.668 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "weather-radar-card" is not installed, See Integration Configuration.
2024-06-27 15:09:06.668 DEBUG (MainThread) [custom_components.ui_lovelace_minimalist] Reload the config entry
2024-06-27 15:09:06.668 INFO (MainThread) [custom_components.ui_lovelace_minimalist.base] Setup ULM Configuration
2024-06-27 15:09:07.217 DEBUG (MainThread) [custom_components.ui_lovelace_minimalist.base] Checking Dependencies.
2024-06-27 15:09:07.217 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Integration repo "browser mod" is not installed!
2024-06-27 15:09:07.217 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "light-entity-card" is not installed, See Integration Configuration.
2024-06-27 15:09:07.217 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "mini-media-player" is not installed, See Integration Configuration.
2024-06-27 15:09:07.217 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "my-cards" is not installed, See Integration Configuration.
2024-06-27 15:09:07.217 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "simple-weather-card" is not installed, See Integration Configuration.
2024-06-27 15:09:07.218 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "weather-radar-card" is not installed, See Integration Configuration.
2024-06-27 15:09:07.218 DEBUG (MainThread) [custom_components.ui_lovelace_minimalist] Reload the config entry
2024-06-27 15:09:07.218 INFO (MainThread) [custom_components.ui_lovelace_minimalist.base] Setup ULM Configuration
2024-06-27 15:09:07.680 DEBUG (MainThread) [custom_components.ui_lovelace_minimalist.base] Checking Dependencies.
2024-06-27 15:09:07.680 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Integration repo "browser mod" is not installed!
2024-06-27 15:09:07.680 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "light-entity-card" is not installed, See Integration Configuration.
2024-06-27 15:09:07.680 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "mini-media-player" is not installed, See Integration Configuration.
2024-06-27 15:09:07.680 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "my-cards" is not installed, See Integration Configuration.
2024-06-27 15:09:07.680 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "simple-weather-card" is not installed, See Integration Configuration.
2024-06-27 15:09:07.680 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "weather-radar-card" is not installed, See Integration Configuration.
2024-06-27 15:09:07.680 DEBUG (MainThread) [custom_components.ui_lovelace_minimalist] Reload the config entry
2024-06-27 15:09:07.680 INFO (MainThread) [custom_components.ui_lovelace_minimalist.base] Setup ULM Configuration
2024-06-27 15:09:08.171 DEBUG (MainThread) [custom_components.ui_lovelace_minimalist.base] Checking Dependencies.
2024-06-27 15:09:08.171 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Integration repo "browser mod" is not installed!
2024-06-27 15:09:08.171 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "light-entity-card" is not installed, See Integration Configuration.
2024-06-27 15:09:08.171 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "mini-media-player" is not installed, See Integration Configuration.
2024-06-27 15:09:08.171 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "my-cards" is not installed, See Integration Configuration.
2024-06-27 15:09:08.171 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "simple-weather-card" is not installed, See Integration Configuration.
2024-06-27 15:09:08.171 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "weather-radar-card" is not installed, See Integration Configuration.
2024-06-27 15:09:08.172 DEBUG (MainThread) [custom_components.ui_lovelace_minimalist] Reload the config entry
2024-06-27 15:09:08.172 INFO (MainThread) [custom_components.ui_lovelace_minimalist.base] Setup ULM Configuration
2024-06-27 15:09:08.677 DEBUG (MainThread) [custom_components.ui_lovelace_minimalist.base] Checking Dependencies.
2024-06-27 15:09:08.677 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Integration repo "browser mod" is not installed!
2024-06-27 15:09:08.677 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "light-entity-card" is not installed, See Integration Configuration.
2024-06-27 15:09:08.677 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "mini-media-player" is not installed, See Integration Configuration.
2024-06-27 15:09:08.677 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "my-cards" is not installed, See Integration Configuration.
2024-06-27 15:09:08.678 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "simple-weather-card" is not installed, See Integration Configuration.
2024-06-27 15:09:08.678 ERROR (MainThread) [custom_components.ui_lovelace_minimalist.base] HACS Frontend repo "weather-radar-card" is not installed, See Integration Configuration.
2024-06-27 15:09:08.678 DEBUG (MainThread) [custom_components.ui_lovelace_minimalist] Reload the config entry
2024-06-27 15:09:08.678 INFO (MainThread) [custom_components.ui_lovelace_minimalist.base] Setup ULM Configuration
...

Within about five minutes, it has produced over 4,000 lines in my log file while completely locking Home Assistant up because it's an endless loop.

@ademtoday
Copy link

Tried to use previous version (1.3.8 instead of 13.9) , still nothin changed. Looks like its a HA update problem...

@wilbiev
Copy link
Contributor

wilbiev commented Jun 28, 2024

I was able to fix some issues related to 'Detected blocking' and hanging. See issue #1501.

@cornmacabre
Copy link

Experienced the same issue as others here, show stopping bug. Attempting to enable the integration will lock HA. It was particularly nasty for me, and ultimately required a fresh SD flash and manual backup restore (no fun.)

@wilbiev
Copy link
Contributor

wilbiev commented Jul 5, 2024

Fixed hanging issues for (first-time) users not using the GitHub option. Update in https://github.com/wilbiev/UI/blob/main/custom_components/ui_lovelace_minimalist/__init__.py.
PR created.
Other issues were fixed in new available version v1.3.10

@lyneld, @karelkryda this should solve your hanging issue

@detlefh68
Copy link

Hi,
I tried to run the setup with version 1.3.10. but it hang with and without enabling GitHup option. The Problem seem not to be solved.

@wilbiev
Copy link
Contributor

wilbiev commented Jul 6, 2024

Replace the code in init.py with https://github.com/wilbiev/UI/blob/main/custom_components/ui_lovelace_minimalist/__init__.py.
This fix is not part of the v1.3.10 release. A pull request is created.

@detlefh68
Copy link

I replaced that file and and could install the integration.

Thank You for the tip.

@reydelleon
Copy link

I can confirm that @wilbiev's fix works as well.

@StarScream159
Copy link

StarScream159 commented Jul 13, 2024

Thanks @wilbiev your fix allowed me to save the configuration. However there are still issues related to the "Enable the ability to configure community cards with this integrations, Does require GitHub authentication!" setting. Not sure if this is all related. If it isn't I can create a new issue - sorry about that.

But I never had that setting enabled. I am trying to enable it so I get automatic updates of the custom cards.

Without your fix trying to enable it would hang my entire home assistant and force a reboot when I attempted to save the settings. With your fix in place I can now save the settings. However, after I save the settings and then go back in to select my custom cards, the custom cards selected do not save. Further if I restart home assistant with the custom cards setting enabled, UI Lovelace Minimalist fails to start.

When I save:

2024-07-12 20:15:45.725 ERROR (MainThread) [homeassistant.config_entries] Error unloading entry UI Lovelace Minimalist for ui_lovelace_minimalist
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 801, in async_unload
    result = await component.async_unload_entry(hass, self)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/ui_lovelace_minimalist/__init__.py", line 162, in async_unload_entry
    return await async_initialize_integration(hass=hass, config_entry=config_entry)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/ui_lovelace_minimalist/__init__.py", line 103, in async_initialize_integration
    startup_result = await async_startup()
                     ^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/ui_lovelace_minimalist/__init__.py", line 83, in async_startup
    ulm.disable_ulm(UlmDisabledReason.INVALID_TOKEN)
  File "/config/custom_components/ui_lovelace_minimalist/base.py", line 135, in disable_ulm
    self.configuration.config_entry.state = ConfigEntryState.SETUP_ERROR
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 441, in __setattr__
    raise AttributeError(f"{key} cannot be changed")
AttributeError: state cannot be changed
2024-07-12 20:16:01.600 ERROR (Recorder) [homeassistant] Error doing job: Task exception was never retrieved (None)
Traceback (most recent call last):
  File "/config/custom_components/ui_lovelace_minimalist/__init__.py", line 155, in config_entry_update_listener
    await hass.config_entries.async_reload(config_entry.entry_id)
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 1897, in async_reload
    unload_result = await self.async_unload(entry_id, _lock=False)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 1846, in async_unload
    raise OperationNotAllowed(
homeassistant.config_entries.OperationNotAllowed: The config entry 'UI Lovelace Minimalist' (ui_lovelace_minimalist) with entry_id '469269b94faab5c925ba1f1813a53a93' cannot be unloaded because it is in the non recoverable state ConfigEntryState.FAILED_UNLOAD

When I restart:

Logger: homeassistant.config_entries
Source: config_entries.py:586
First occurred: 8:22:26 PM (1 occurrences)
Last logged: 8:22:26 PM

Error setting up entry UI Lovelace Minimalist for ui_lovelace_minimalist
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 586, in async_setup
    result = await component.async_setup_entry(hass, self)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/ui_lovelace_minimalist/__init__.py", line 136, in async_setup_entry
    return await async_initialize_integration(hass=hass, config_entry=config_entry)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/ui_lovelace_minimalist/__init__.py", line 103, in async_initialize_integration
    startup_result = await async_startup()
                     ^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/ui_lovelace_minimalist/__init__.py", line 83, in async_startup
    ulm.disable_ulm(UlmDisabledReason.INVALID_TOKEN)
  File "/config/custom_components/ui_lovelace_minimalist/base.py", line 135, in disable_ulm
    self.configuration.config_entry.state = ConfigEntryState.SETUP_ERROR
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 441, in __setattr__
    raise AttributeError(f"{key} cannot be changed")
AttributeError: state cannot be changed

I'm on v1.3.10 of Minimalist with your patch applied and Github integration enabled and connected. Home assistant core 2024.7.2.

EDIT:

My config does get updated though when I save. However the UI doesn't reflect that and I don't see the custom cards downloading. And if I restart home assistant IU Minimalist won't start.

      {
        "data": {
          "language": "English (GB)",
          "sidepanel_enabled": false,
          "sidepanel_title": "UI Lovelace Minimalist",
          "sidepanel_icon": "mdi:flower",
          "theme": "minimalist-desktop",
          "theme_path": "themes/",
          "include_other_cards": false
        },
        "disabled_by": null,
        "domain": "ui_lovelace_minimalist",
        "entry_id": "469269b94faab5c925ba1f1813a53a93",
        "minor_version": 1,
        "options": {
          "language": "English (GB)",
          "sidepanel_enabled": false,
          "sidepanel_title": "UI Lovelace Minimalist",
          "sidepanel_icon": "mdi:flower",
          "adaptive_ui_enabled": false,
          "adaptive_ui_title": "UI Lovelace Minimalist",
          "adaptive_ui_icon": "mdi:flower",
          "theme": "minimalist-desktop",
          "theme_path": "themes/",
          "include_other_cards": false,
          "community_cards_enabled": true,
          "community_cards": [
            "custom_card_apexcharts",
            "custom_card_camera"
          ]
        },
        "pref_disable_new_entities": false,
        "pref_disable_polling": false,
        "source": "user",
        "title": "UI Lovelace Minimalist",
        "unique_id": null,
        "version": 1
      },

@wilbiev
Copy link
Contributor

wilbiev commented Jul 27, 2024

@StarScream159 I see in the provided log you do not have an GitHub token configured. You need to enable the GitHub option when installing the integration. In your case you need to remove and install the integration again to enable this.

@GeekDenCode
Copy link

GeekDenCode commented Sep 4, 2024

It's still crashing at 2024.8.1
HA reloaded itself with about 10 minutes after dropped connection 😳

@StarScream159
Copy link

StarScream159 commented Sep 5, 2024

@wilbiev Not sure how I missed your reply. Thanks.

I see you mentioned that the logs say I don't have a github token, but I do. I have the github integration configured and active. When I click on Settings -> Devices & Services -> Github -> Configure I get a little loader and then within a second I see my repos listed with a checkbox. So it's using my token/key to pull the repos list - it is configured correctly.

I can also see a "HACS" and "Home Assistant GitHub Integration" under my https://github.com/settings/applications page. Both say used within the last week.

@PieterWigleven
Copy link

Getting the same on a freshly installed HA - GitHub auth has been configured correctly but getting:

Error setting up entry for ui_lovelace_minimalist
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 604, in async_setup
    result = await component.async_setup_entry(hass, self)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/ui_lovelace_minimalist/__init__.py", line 123, in async_setup_entry
    return await async_initialize_integration(hass=hass, config_entry=config_entry)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/ui_lovelace_minimalist/__init__.py", line 103, in async_initialize_integration
    startup_result = await async_startup()
                     ^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/ui_lovelace_minimalist/__init__.py", line 83, in async_startup
    ulm.disable_ulm(UlmDisabledReason.INVALID_TOKEN)
  File "/config/custom_components/ui_lovelace_minimalist/base.py", line 135, in disable_ulm
    self.configuration.config_entry.state = ConfigEntryState.SETUP_ERROR
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 457, in __setattr__
    raise AttributeError(f"{key} cannot be changed")
AttributeError: state cannot be changed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests