imhotep / hass-unifi-access

Unifi Access Integration for Home Assistant
Apache License 2.0
68 stars 16 forks source link

Unable to install #34

Closed ghostracer34 closed 5 months ago

ghostracer34 commented 6 months ago

First thanks for this integration I'm unfortunately unable to install it, when I add the integration I get the error: Config flow could not be loaded: {“message”:“Invalid handler specified”}. This appears when clicking on the integration in the add integration pop up on the integration dashboard. Home Assistant is in a docker container, I've tried downloading via HACS and cloning the repository. log details below: Logger: homeassistant.config_entries Source: config_entries.py:2444 First occurred: 9 May 2024 at 15:31:17 (5 occurrences) Last logged: 14:53:46

Error occurred loading flow for integration unifi_access: cannot import name 'ConfigFlowResult' from 'homeassistant.config_entries' (/usr/src/homeassistant/homeassistant/config_entries.py)

schizza commented 6 months ago

What version of Home Assistant do you have?

ghostracer34 commented 6 months ago

Core 2024.3.1 Frontend 20240307.0

schizza commented 6 months ago

This is wild works for me on

Core.  2024.5.2
Supervisor. 2024.05.1
Operating System
Frontend.  20240501.1

even on:

Core  2024.6.0.dev0
Frontend  20240501.0

do you see anything else in the logs?

ghostracer34 commented 6 months ago

Nothing more than already posted full log view doesn't show any more unfortunately

schizza commented 6 months ago

Nothing more than already posted full log view doesn't show any more unfortunately

try to comment lines in custom_components/unifi_access/confg_flow.py as this:

   # VERSION = 1

   # CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL

on line 61 and 63

ghostracer34 commented 6 months ago

commented out those lines failed again then commented out #from homeassistant.config_entries import ConfigFlowResult line 11 after which was able to get the install screen and install the integration

imhotep commented 6 months ago

@ghostracer34 could you post the modified version of config_flow.py that works for you? Is everything working as expected after you made the change?

ghostracer34 commented 6 months ago

Sorry still bit new to github where should I post the file. After the changes the integration installed, I now see controls to unlock the access hub, sensors for door position and doorbell, and events for access and doorbell press. the controls are working as well as the sensors

imhotep commented 6 months ago

@ghostracer34 you can follow these instructions

ghostracer34 commented 6 months ago

from __future__ import annotations

import logging
from typing import Any

import voluptuous as vol

from homeassistant import config_entries
# from homeassistant.config_entries import ConfigFlowResult
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError

from .const import DOMAIN
from .hub import UnifiAccessHub

_LOGGER = logging.getLogger(__name__)

STEP_USER_DATA_SCHEMA = vol.Schema(
    {
        vol.Required("host"): str,
        vol.Required("api_token"): str,
        vol.Required("verify_ssl"): bool,
        vol.Required("use_polling"): bool,
    }
)

async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, Any]:
    """Validate the user input allows us to connect.

    Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user.
    """

    api = UnifiAccessHub(data["host"], data["verify_ssl"], data["use_polling"])

    auth_response = await hass.async_add_executor_job(
        api.authenticate, data["api_token"]
    )

    match auth_response:
        case "cannot_connect":
            raise CannotConnect
        case "api_error":
            raise CannotConnect
        case "api_auth_error":
            raise InvalidApiKey
        case "ssl_error":
            raise SSLVerificationError
        case "ok":
            _LOGGER.info("Unifi Access API authorized")

    # Return info that you want to store in the config entry.
    return {"title": "Unifi Access Doors"}

class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
    """Handle a config flow for Unifi Access."""

   # VERSION = 1

   # CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL

    async def async_step_user(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Handle the initial step."""
        errors: dict[str, str] = {}
        if user_input is not None:
            try:
                info = await validate_input(self.hass, user_input)
            except CannotConnect:
                errors["base"] = "cannot_connect"
            except InvalidApiKey:
                errors["base"] = "invalid_api_key"
            except SSLVerificationError:
                errors["base"] = "ssl_error"
            except Exception:  # pylint: disable=broad-except
                _LOGGER.exception("Unexpected exception")
                errors["base"] = "unknown"
            else:
                return self.async_create_entry(title=info["title"], data=user_input)

        return self.async_show_form(
            step_id="user",
            data_schema=STEP_USER_DATA_SCHEMA,
            errors=errors,
        )

class CannotConnect(HomeAssistantError):
    """Error to indicate we cannot connect."""

class SSLVerificationError(HomeAssistantError):
    """Error to indicate there is failed SSL certificate verification."""

class InvalidApiKey(HomeAssistantError):
    """Error to indicate there is invalid auth."""
imhotep commented 6 months ago

commented out those lines failed again then commented out #from homeassistant.config_entries import ConfigFlowResult line 11 after which was able to get the install screen and install the integration

This doesn't really make sense to me as the symbol is used as a return value of async_step_user further down in the file.

This does highlight the need to clean up the imports from config_entries and just import ConfigFlow/ConfigFlowResult

The CONNECTION_CLASS is deprecated so it's probably safe to remove.

The lack of VERSION is also strange.

@ghostracer34 would you mind trying the config_flow file below and let me know whether it works or not? You may need to delete and re-add the integration.

config_flow.py ```Python from __future__ import annotations import logging from typing import Any import voluptuous as vol from homeassistant.config_entries import ConfigFlow, ConfigFlowResult from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from .const import DOMAIN from .hub import UnifiAccessHub _LOGGER = logging.getLogger(__name__) STEP_USER_DATA_SCHEMA = vol.Schema( { vol.Required("host"): str, vol.Required("api_token"): str, vol.Required("verify_ssl"): bool, vol.Required("use_polling"): bool, } ) async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, Any]: """Validate the user input allows us to connect. Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user. """ api = UnifiAccessHub(data["host"], data["verify_ssl"], data["use_polling"]) auth_response = await hass.async_add_executor_job( api.authenticate, data["api_token"] ) match auth_response: case "cannot_connect": raise CannotConnect case "api_error": raise CannotConnect case "api_auth_error": raise InvalidApiKey case "ssl_error": raise SSLVerificationError case "ok": _LOGGER.info("Unifi Access API authorized") # Return info that you want to store in the config entry. return {"title": "Unifi Access Doors"} class ConfigFlow(ConfigFlow, domain=DOMAIN): """Handle a config flow for Unifi Access.""" VERSION = 1 async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: """Handle the initial step.""" errors: dict[str, str] = {} if user_input is not None: try: info = await validate_input(self.hass, user_input) except CannotConnect: errors["base"] = "cannot_connect" except InvalidApiKey: errors["base"] = "invalid_api_key" except SSLVerificationError: errors["base"] = "ssl_error" except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected exception") errors["base"] = "unknown" else: return self.async_create_entry(title=info["title"], data=user_input) return self.async_show_form( step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors, ) class CannotConnect(HomeAssistantError): """Error to indicate we cannot connect.""" class SSLVerificationError(HomeAssistantError): """Error to indicate there is failed SSL certificate verification.""" class InvalidApiKey(HomeAssistantError): """Error to indicate there is invalid auth.""" ```
ghostracer34 commented 6 months ago

Using that config_flow.py to install integration worked as well.

imhotep commented 6 months ago

@ghostracer34 awesome! I will update that in the upcoming release. Thanks for trying it out.

ghostracer34 commented 5 months ago

So something broke after a restart and the integration stopped working so I tried reinstalling, using the new config flow but getting same error again.

Logger: homeassistant.config_entries
Source: config_entries.py:2444
First occurred: 09:24:50 (1 occurrences)
Last logged: 09:24:50

Error occurred loading flow for integration unifi_access: cannot import name 'ConfigFlowResult' from 'homeassistant.config_entries' (/usr/src/homeassistant/homeassistant/config_entries.py)

I managed to install it again by commenting out configflowresult in the imports

config_flow.py

``` from __future__ import annotations import logging from typing import Any import voluptuous as vol from homeassistant.config_entries import ConfigFlow#, ConfigFlowResult from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from .const import DOMAIN from .hub import UnifiAccessHub _LOGGER = logging.getLogger(__name__) STEP_USER_DATA_SCHEMA = vol.Schema( { vol.Required("host"): str, vol.Required("api_token"): str, vol.Required("verify_ssl"): bool, vol.Required("use_polling"): bool, } ) async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, Any]: """Validate the user input allows us to connect. Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user. """ api = UnifiAccessHub(data["host"], data["verify_ssl"], data["use_polling"]) auth_response = await hass.async_add_executor_job( api.authenticate, data["api_token"] ) match auth_response: case "cannot_connect": raise CannotConnect case "api_error": raise CannotConnect case "api_auth_error": raise InvalidApiKey case "ssl_error": raise SSLVerificationError case "ok": _LOGGER.info("Unifi Access API authorized") # Return info that you want to store in the config entry. return {"title": "Unifi Access Doors"} class ConfigFlow(ConfigFlow, domain=DOMAIN): """Handle a config flow for Unifi Access.""" VERSION = 1 async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: """Handle the initial step.""" errors: dict[str, str] = {} if user_input is not None: try: info = await validate_input(self.hass, user_input) except CannotConnect: errors["base"] = "cannot_connect" except InvalidApiKey: errors["base"] = "invalid_api_key" except SSLVerificationError: errors["base"] = "ssl_error" except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected exception") errors["base"] = "unknown" else: return self.async_create_entry(title=info["title"], data=user_input) return self.async_show_form( step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors, ) class CannotConnect(HomeAssistantError): """Error to indicate we cannot connect.""" class SSLVerificationError(HomeAssistantError): """Error to indicate there is failed SSL certificate verification.""" class InvalidApiKey(HomeAssistantError): """Error to indicate there is invalid auth.""" ```

imhotep commented 5 months ago

@ghostracer34 thanks for the update. Is there a reason you're running an older version of home assistant? I just wonder whether updating would help. ConfigFlowResult is definitely now in the upstream branch of Home Assistant.