hon icon indicating copy to clipboard operation
hon copied to clipboard

HA 2025.7.0 Haier integration not working

Open Asom-Velz opened this issue 6 months ago • 54 comments

I have updated HA from Ver. 2025.5.3 to Ver. 2025.7.0. Integration is not loading.

Logger: homeassistant.config_entries Source: config_entries.py:749 First occurred: 11:11:34 (1 occurrence) Last logged: 11:11:34

Error setting up entry [email protected] for hon Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/config_entries.py", line 749, in __async_setup_with_context result = await component.async_setup_entry(hass, self) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/config/custom_components/hon/init.py", line 79, in async_setup_entry hass.config_entries.async_forward_entry_setup(entry, platform) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'ConfigEntries' object has no attribute 'async_forward_entry_setup'. Did you mean: 'async_forward_entry_setups'?

Asom-Velz avatar Jul 03 '25 08:07 Asom-Velz

in the file hon/init.py I change -> hass.config_entries.async_forward_entry_setup(entry, platform) By -> await hass.config_entries.async_forward_entry_setups(entry, [platform]) except for hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, [platform]) ) I just replace setup ->setups:

hass.async_create_task( hass.config_entries.async_forward_entry_setups(entry, [platform]) )

Now it's working good in my side but still can't add in my dashboard

kaddou69200 avatar Jul 03 '25 21:07 kaddou69200

Hi @kaddou69200 ,

what do you mean it is working good in my side if you can't add in the dashboard??

Could you sent a copy of the modified init.py file?

Asom-Velz avatar Jul 04 '25 07:07 Asom-Velz

Hi @Asom-Velz

All my connection errors have disappeared and I have finally been able to add my Haier Hon account and find my washing machine and all the entities.

When I click on add dashboard I get an error ‘no configuration found’ but my default dashboard does exist. It is possible that this is due to a problem on my side I am new to the subject Home Assistant

And there is my init.py file

init.txt

kaddou69200 avatar Jul 04 '25 07:07 kaddou69200

Thank you @kaddou69200 I will try it

Asom-Velz avatar Jul 04 '25 07:07 Asom-Velz

The syntax update for async_forward_entry_setup -> async_forward_entry_setups in the __init__.py worked for me as well. Anyone willing to prep that quick PR?

ndom91 avatar Jul 05 '25 11:07 ndom91

Hi all, in orde to fix the issue I replacede in custom_components/hon/init.py

the below code:

# for platform in PLATFORMS:
#     hass.async_create_task(
#         hass.config_entries.async_forward_entry_setup(entry, platform)
#     )

with: await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

this change works for me Regards.

cavaliere78 avatar Jul 06 '25 09:07 cavaliere78

Hi all, in orde to fix the issue I replacede in custom_components/hon/init.py

the below code:

# for platform in PLATFORMS:
#     hass.async_create_task(
#         hass.config_entries.async_forward_entry_setup(entry, platform)
#     )

with: await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

this change works for me Regards.

Thanks, worked for me too.

allthepies avatar Jul 06 '25 14:07 allthepies

Can anyone send new version to repo with fix this?

On HA 2025.7.1 is the same bug

liske310 avatar Jul 06 '25 20:07 liske310

The init file needed some improvements, but with the code below, the integration finally works correctly and loads all entities. here is what was fixed:

  • Fixed logger definition: Changed LOGGER = logging.getLogger(name_) to _LOGGER = logging.getLogger(name)
  • Simplified platform setup: Used the modern async_forward_entry_setups method directly instead of creating tasks in a loop
  • Added await for unload: Added await before async_unload_platforms
  • Fixed cleanup logic: Properly remove the specific entry from hass.data[DOMAIN] before checking if the domain is empty
  • Improved formatting: Added proper spacing and line breaks for better readability

Here is correct code for the init file (UPDATE: this time with proper formatting using tripple backticks):


import logging
from pathlib import Path
from typing import Any
import voluptuous as vol  # type: ignore[import-untyped]
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.helpers import config_validation as cv, aiohttp_client
from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from pyhon import Hon
from .const import DOMAIN, PLATFORMS, MOBILE_ID, CONF_REFRESH_TOKEN

_LOGGER = logging.getLogger(__name__)

HON_SCHEMA = vol.Schema(
    {
        vol.Required(CONF_EMAIL): cv.string,
        vol.Required(CONF_PASSWORD): cv.string,
    }
)

CONFIG_SCHEMA = vol.Schema(
    {DOMAIN: vol.Schema(vol.All(cv.ensure_list, [HON_SCHEMA]))},
    extra=vol.ALLOW_EXTRA,
)


async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
    session = aiohttp_client.async_get_clientsession(hass)
    if (config_dir := hass.config.config_dir) is None:
        raise ValueError("Missing Config Dir")
    
    hon = await Hon(
        email=entry.data[CONF_EMAIL],
        password=entry.data[CONF_PASSWORD],
        mobile_id=MOBILE_ID,
        session=session,
        test_data_path=Path(config_dir),
        refresh_token=entry.data.get(CONF_REFRESH_TOKEN, ""),
    ).create()
    
    # Save the new refresh token
    hass.config_entries.async_update_entry(
        entry, data={**entry.data, CONF_REFRESH_TOKEN: hon.api.auth.refresh_token}
    )
    
    coordinator: DataUpdateCoordinator[dict[str, Any]] = DataUpdateCoordinator(
        hass, _LOGGER, name=DOMAIN
    )
    hon.subscribe_updates(coordinator.async_set_updated_data)
    
    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.unique_id] = {"hon": hon, "coordinator": coordinator}
    
    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
    
    return True


async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
    refresh_token = hass.data[DOMAIN][entry.unique_id]["hon"].api.auth.refresh_token
    hass.config_entries.async_update_entry(
        entry, data={**entry.data, CONF_REFRESH_TOKEN: refresh_token}
    )
    
    unload = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
    if unload:
        hass.data[DOMAIN].pop(entry.unique_id, None)
        if not hass.data[DOMAIN]:
            hass.data.pop(DOMAIN, None)
    
    return unload
_______________________________________________________________

SleepyDelegate avatar Jul 12 '25 06:07 SleepyDelegate

Can somebody help me, please? Tried to fix the issues with the above-mentioned solutions, but no luck.

It says: Failed to setup, check the logs. But it also shows my dishwasher with all the entities. (but it seems they are not refreshing)

I have 2 errors according to this integration:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 749, in __async_setup_with_context
    result = await component.async_setup_entry(hass, self)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/hon/__init__.py", line 57, in async_setup_entry
    hass.async_create_task(
    ~~~~~~~~~~~~~~~~~~~~~~^
        await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/usr/src/homeassistant/homeassistant/core.py", line 805, in async_create_task
    return self.async_create_task_internal(target, name, eager_start)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 827, in async_create_task_internal
    task = create_eager_task(target, name=name, loop=self.loop)
  File "/usr/src/homeassistant/homeassistant/util/async_.py", line 44, in create_eager_task
    return Task(coro, loop=loop, name=name, eager_start=True)
TypeError: a coroutine was expected, got None

And the second one says:

Logger: homeassistant.config_entries
Source: config_entries.py:749
First occurred: 8:20:51 PM (30 occurrences)
Last logged: 8:53:14 PM

Error setting up entry [email protected] for binary_sensor
Error setting up entry [email protected] for climate
Error setting up entry [email protected] for fan
Error setting up entry [email protected] for light
Error setting up entry [email protected] for lock
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 749, in __async_setup_with_context
    result = await component.async_setup_entry(hass, self)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 99, in async_setup_entry
    return await hass.data[DATA_COMPONENT].async_setup_entry(entry)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 219, in async_setup_entry
    raise ValueError(
    ...<2 lines>...
    )
ValueError: Config entry [email protected] (01K02F6NKWNXZQTMY*****) for hon.sensor has already been setup!

itradesize avatar Jul 13 '25 18:07 itradesize

Hi all, in orde to fix the issue I replacede in custom_components/hon/init.py

the below code:

# for platform in PLATFORMS:
#     hass.async_create_task(
#         hass.config_entries.async_forward_entry_setup(entry, platform)
#     )

with: await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

this change works for me Regards.

+1 for this - thanks for the contribution!

stewartpriest avatar Jul 14 '25 11:07 stewartpriest

Just replace the entire init file content with the code I posted above. That is the clean, perfectly working code with all improvements possible. Works like a charm. You just need to deal with the formatting of the post, but that should be easy...

SleepyDelegate avatar Jul 14 '25 16:07 SleepyDelegate

Just replace the entire init file content with the code I posted above. That is the clean, perfectly working code with all improvements possible. Works like a charm. You just need to deal with the formatting of the post, but that should be easy...

Thank you for your reply.

I tried, but I encountered several errors, so I had to restore the original file. However, I'm now unable to proceed because when I try to add the integration, it prompts me for credentials as it normally does but then it displays the message:

"Haier hOn already configured."

Despite this message, I cannot find it listed under the integrations.

I decided to SSH into my server, delete the entire 'hon' folder, restart the server, and then install a fresh download of 'hon.' Unfortunately, the situation remains the same.

Can someone help me understand what went wrong?

itradesize avatar Jul 15 '25 14:07 itradesize

I tried, but I encountered several errors, so I had to restore the original file. However, I'm now unable to proceed because when I try to add the integration, it prompts me for credentials as it normally does but then it displays the message:

Could it be because of the way this forum formats the code? Because I pasted entire block of code, but this forum decided to highlight only portions of it as a code and the rest as a plain text. I can imagine, that pasting it can be nightmare...

Unfortunately I do not know how to bypass it. But the code I provided above if pasted correctly is perfect, there should be zero issues...

SleepyDelegate avatar Jul 15 '25 14:07 SleepyDelegate

I tried, but I encountered several errors, so I had to restore the original file. However, I'm now unable to proceed because when I try to add the integration, it prompts me for credentials as it normally does but then it displays the message:

Could it be because of the way this forum formats the code? Because I pasted entire block of code, but this forum decided to highlight only portions of it as a code and the rest as a plain text. I can imagine, that pasting it can be nightmare...

Unfortunately I do not know how to bypass it. But the code I provided above if pasted correctly is perfect, there should be zero issues...

You should use the following characters for code blocks : '' '' or click on the code format inside this text field for the block of code.

itradesize avatar Jul 15 '25 14:07 itradesize

That's what I do, I use the "Code" button above, but it splits the code into chunks anyway. I found solution - use triple backticks:

import logging
from pathlib import Path
from typing import Any
import voluptuous as vol  # type: ignore[import-untyped]
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.helpers import config_validation as cv, aiohttp_client
from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from pyhon import Hon
from .const import DOMAIN, PLATFORMS, MOBILE_ID, CONF_REFRESH_TOKEN

_LOGGER = logging.getLogger(__name__)

HON_SCHEMA = vol.Schema(
    {
        vol.Required(CONF_EMAIL): cv.string,
        vol.Required(CONF_PASSWORD): cv.string,
    }
)

CONFIG_SCHEMA = vol.Schema(
    {DOMAIN: vol.Schema(vol.All(cv.ensure_list, [HON_SCHEMA]))},
    extra=vol.ALLOW_EXTRA,
)


async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
    session = aiohttp_client.async_get_clientsession(hass)
    if (config_dir := hass.config.config_dir) is None:
        raise ValueError("Missing Config Dir")
    
    hon = await Hon(
        email=entry.data[CONF_EMAIL],
        password=entry.data[CONF_PASSWORD],
        mobile_id=MOBILE_ID,
        session=session,
        test_data_path=Path(config_dir),
        refresh_token=entry.data.get(CONF_REFRESH_TOKEN, ""),
    ).create()
    
    # Save the new refresh token
    hass.config_entries.async_update_entry(
        entry, data={**entry.data, CONF_REFRESH_TOKEN: hon.api.auth.refresh_token}
    )
    
    coordinator: DataUpdateCoordinator[dict[str, Any]] = DataUpdateCoordinator(
        hass, _LOGGER, name=DOMAIN
    )
    hon.subscribe_updates(coordinator.async_set_updated_data)
    
    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.unique_id] = {"hon": hon, "coordinator": coordinator}
    
    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
    
    return True


async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
    refresh_token = hass.data[DOMAIN][entry.unique_id]["hon"].api.auth.refresh_token
    hass.config_entries.async_update_entry(
        entry, data={**entry.data, CONF_REFRESH_TOKEN: refresh_token}
    )
    
    unload = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
    if unload:
        hass.data[DOMAIN].pop(entry.unique_id, None)
        if not hass.data[DOMAIN]:
            hass.data.pop(DOMAIN, None)
    
    return unload

SleepyDelegate avatar Jul 15 '25 14:07 SleepyDelegate

Triple back ticks in general = code blocks.

So the triple back ticks wrapping the python function comments were messing you up.

This looks good though ^^

Is there a PR prepped for this change against main?

ndom91 avatar Jul 15 '25 15:07 ndom91

Tripple backticks actually solved it, before I was only using double backticks and that messed the code up...

SleepyDelegate avatar Jul 15 '25 15:07 SleepyDelegate

God bless you m8, now it's working perfectly without any issues.

A separate question: What's the time of this integration for fetching data from the Haier-Candy services? (server sync time) As the door sensor (under the entities) indicates a closed state and does not change by itself, even when I manually open the door, unless I click 'Reload' on the integration.

itradesize avatar Jul 15 '25 15:07 itradesize

I do not know. I observe the same behavior in my HA, it does not update the status of the fridge doors unless I manually reload the integration...

SleepyDelegate avatar Jul 15 '25 15:07 SleepyDelegate

Got it, I've never faced an issue like this before. When it comes to the fridge, mine is an LG one, and it's working perfectly. Regarding the Haier integration, I started a program on the dishwasher, but it only shows a 'Ready' state until I reload the configuration, at which point it changes to 'Program running'. Additionally, the dishwasher program entity displays irrelevant information. This makes the integration essentially useless for me. Is it syncing well for you?

itradesize avatar Jul 15 '25 16:07 itradesize

Replace code in original 0.14.0 with above code in file "init.py", but nothing is changed. Addon is dead for like 1 year i cant use my haier ac

Doktor-X avatar Jul 15 '25 16:07 Doktor-X

Got it, I've never faced an issue like this before. When it comes to the fridge, mine is an LG one, and it's working perfectly. Regarding the Haier integration, I started a program on the dishwasher, but it only shows a 'Ready' state until I reload the configuration, at which point it changes to 'Program running'. Additionally, the dishwasher program entity displays irrelevant information. This makes the integration essentially useless for me. Is it syncing well for you?

The problem is, that the integration is relying on push updates from the Haier cloud and in this case it is either not setup properly or not working on the Haier side. So the clumsy workaround is to include polling in the init file and check for updates through the Haier API every 30 seconds. I tried it and it works, although it results in unnecessary polling. But it is the only way to make it work without going through the entire code of the integration. If you try it now, it will work, it will take maximum 30 seconds to change the state of the entity (for example the open fridge doors) but it will help:

import logging
from pathlib import Path
from typing import Any
from datetime import timedelta

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import HomeAssistant
from homeassistant.helpers import aiohttp_client
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from pyhon import Hon

from .const import DOMAIN, PLATFORMS, MOBILE_ID, CONF_REFRESH_TOKEN

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    session = aiohttp_client.async_get_clientsession(hass)
    hon = await Hon(
        email=entry.data[CONF_EMAIL],
        password=entry.data[CONF_PASSWORD],
        mobile_id=MOBILE_ID,
        session=session,
        test_data_path=Path(hass.config.config_dir),
        refresh_token=entry.data.get(CONF_REFRESH_TOKEN, ""),
    ).create()

    # Save the new refresh token
    hass.config_entries.async_update_entry(
        entry, data={**entry.data, CONF_REFRESH_TOKEN: hon.api.auth.refresh_token}
    )

    async def async_update_data():
        try:
            appliances_data = await hon.api.load_appliances()
            for new_appliance_data in appliances_data:
                mac = new_appliance_data["macAddress"]
                for appliance in hon.appliances:
                    if appliance.mac_address == mac:
                        appliance._data = new_appliance_data
        except Exception as exc:
            _LOGGER.warning("Error during Hon API poll: %s", exc)
        return {}

    coordinator: DataUpdateCoordinator[dict[str, Any]] = DataUpdateCoordinator(
        hass,
        _LOGGER,
        name=DOMAIN,
        update_method=async_update_data,
        update_interval=timedelta(seconds=30),  # Poll every 30 seconds to refresh appliance states
    )
    hon.subscribe_updates(coordinator.async_set_updated_data)

    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.unique_id] = {"hon": hon, "coordinator": coordinator}

    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

    return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    refresh_token = hass.data[DOMAIN][entry.unique_id]["hon"].api.auth.refresh_token
    hass.config_entries.async_update_entry(
        entry, data={**entry.data, CONF_REFRESH_TOKEN: refresh_token}
    )

    unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
    if unload_ok:
        hass.data[DOMAIN].pop(entry.unique_id)
        if not hass.data[DOMAIN]:
            hass.data.pop(DOMAIN)

    return unload_ok

SleepyDelegate avatar Jul 15 '25 16:07 SleepyDelegate

Try this version, it handles the errors from Haier cloud better - there were errors because API sometimes returns data without mac address and the integration expects it, so this version solves that:

import logging
from pathlib import Path
from typing import Any
from datetime import timedelta

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import HomeAssistant
from homeassistant.helpers import aiohttp_client
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from pyhon import Hon

from .const import DOMAIN, PLATFORMS, MOBILE_ID, CONF_REFRESH_TOKEN

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    session = aiohttp_client.async_get_clientsession(hass)
    hon = await Hon(
        email=entry.data[CONF_EMAIL],
        password=entry.data[CONF_PASSWORD],
        mobile_id=MOBILE_ID,
        session=session,
        test_data_path=Path(hass.config.config_dir),
        refresh_token=entry.data.get(CONF_REFRESH_TOKEN, ""),
    ).create()

    # Save the new refresh token
    hass.config_entries.async_update_entry(
        entry, data={**entry.data, CONF_REFRESH_TOKEN: hon.api.auth.refresh_token}
    )

    async def async_update_data():
        try:
            appliances_data = await hon.api.load_appliances()
            if not isinstance(appliances_data, list):
                _LOGGER.warning("Unexpected appliances_data type: %s", type(appliances_data))
                return {}
            for new_appliance_data in appliances_data:
                if not isinstance(new_appliance_data, dict):
                    continue
                mac = new_appliance_data.get("macAddress")
                if not mac:
                    continue
                for appliance in hon.appliances:
                    if appliance.mac_address == mac:
                        appliance._data = new_appliance_data
                        break
        except Exception as exc:
            _LOGGER.warning("Error during Hon API poll: %s", exc)
        return {}

    coordinator: DataUpdateCoordinator[dict[str, Any]] = DataUpdateCoordinator(
        hass,
        _LOGGER,
        name=DOMAIN,
        update_method=async_update_data,
        update_interval=timedelta(seconds=30),  # Poll every 30 seconds to refresh appliance states
    )
    hon.subscribe_updates(coordinator.async_set_updated_data)

    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.unique_id] = {"hon": hon, "coordinator": coordinator}

    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

    return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    refresh_token = hass.data[DOMAIN][entry.unique_id]["hon"].api.auth.refresh_token
    hass.config_entries.async_update_entry(
        entry, data={**entry.data, CONF_REFRESH_TOKEN: refresh_token}
    )

    unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
    if unload_ok:
        hass.data[DOMAIN].pop(entry.unique_id)
        if not hass.data[DOMAIN]:
            hass.data.pop(DOMAIN)

    return unload_ok

SleepyDelegate avatar Jul 15 '25 17:07 SleepyDelegate

dont know if last reply was for me, but nothing change, config is made but:

hOn Authentication Error 1 200 - https://account2.hon-smarthome.com/hOnRedirect?startURL=/setup/secur/RemoteAccessAuthorizationPage.apexp?source%LONG STRING OF NUMBER AND LETTERS

Error setting up entry [email protected] for hon Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/config_entries.py", line 749, in __async_setup_with_context result = await component.async_setup_entry(hass, self) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/config/custom_components/hon/__init__.py", line 20, in async_setup_entry hon = await Hon( ^^^^^^^^^^ ...<6 lines>... ).create() ^^^^^^^^^^ File "/usr/local/lib/python3.13/site-packages/pyhon/hon.py", line 77, in create await self.setup() File "/usr/local/lib/python3.13/site-packages/pyhon/hon.py", line 104, in setup appliances = await self.api.load_appliances() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.13/site-packages/pyhon/connection/api.py", line 86, in load_appliances async with self._hon.get(f"{const.API_URL}/commands/v1/appliance") as resp: ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.13/contextlib.py", line 214, in __aenter__ return await anext(self.gen) ^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.13/site-packages/pyhon/connection/handler/base.py", line 64, in get async with self._intercept(*args, **kwargs) as response: ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.13/contextlib.py", line 214, in __aenter__ return await anext(self.gen) ^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.13/site-packages/pyhon/connection/handler/hon.py", line 75, in _intercept kwargs["headers"] = await self._check_headers(kwargs.get("headers", {})) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.13/site-packages/pyhon/connection/handler/hon.py", line 64, in _check_headers await self.auth.authenticate() File "/usr/local/lib/python3.13/site-packages/pyhon/connection/auth.py", line 265, in authenticate if not await self._get_token(url): ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.13/site-packages/pyhon/connection/auth.py", line 237, in _get_token await self._error_logger(response) File "/usr/local/lib/python3.13/site-packages/pyhon/connection/auth.py", line 96, in _error_logger raise exceptions.HonAuthenticationError("Can't login") pyhon.exceptions.HonAuthenticationError: Can't login

Doktor-X avatar Jul 15 '25 17:07 Doktor-X

Try this version, it handles the errors from Haier cloud better - there were errors because API sometimes returns data without mac address and the integration expects it, so this version solves that:

import logging
from pathlib import Path
from typing import Any
from datetime import timedelta

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import HomeAssistant
from homeassistant.helpers import aiohttp_client
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from pyhon import Hon

from .const import DOMAIN, PLATFORMS, MOBILE_ID, CONF_REFRESH_TOKEN

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    session = aiohttp_client.async_get_clientsession(hass)
    hon = await Hon(
        email=entry.data[CONF_EMAIL],
        password=entry.data[CONF_PASSWORD],
        mobile_id=MOBILE_ID,
        session=session,
        test_data_path=Path(hass.config.config_dir),
        refresh_token=entry.data.get(CONF_REFRESH_TOKEN, ""),
    ).create()

    # Save the new refresh token
    hass.config_entries.async_update_entry(
        entry, data={**entry.data, CONF_REFRESH_TOKEN: hon.api.auth.refresh_token}
    )

    async def async_update_data():
        try:
            appliances_data = await hon.api.load_appliances()
            if not isinstance(appliances_data, list):
                _LOGGER.warning("Unexpected appliances_data type: %s", type(appliances_data))
                return {}
            for new_appliance_data in appliances_data:
                if not isinstance(new_appliance_data, dict):
                    continue
                mac = new_appliance_data.get("macAddress")
                if not mac:
                    continue
                for appliance in hon.appliances:
                    if appliance.mac_address == mac:
                        appliance._data = new_appliance_data
                        break
        except Exception as exc:
            _LOGGER.warning("Error during Hon API poll: %s", exc)
        return {}

    coordinator: DataUpdateCoordinator[dict[str, Any]] = DataUpdateCoordinator(
        hass,
        _LOGGER,
        name=DOMAIN,
        update_method=async_update_data,
        update_interval=timedelta(seconds=30),  # Poll every 30 seconds to refresh appliance states
    )
    hon.subscribe_updates(coordinator.async_set_updated_data)

    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.unique_id] = {"hon": hon, "coordinator": coordinator}

    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

    return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    refresh_token = hass.data[DOMAIN][entry.unique_id]["hon"].api.auth.refresh_token
    hass.config_entries.async_update_entry(
        entry, data={**entry.data, CONF_REFRESH_TOKEN: refresh_token}
    )

    unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
    if unload_ok:
        hass.data[DOMAIN].pop(entry.unique_id)
        if not hass.data[DOMAIN]:
            hass.data.pop(DOMAIN)

    return unload_ok

Thanks, man, that solved the ongoing issue.

itradesize avatar Jul 15 '25 18:07 itradesize

dont know if last reply was for me, but nothing change, config is made but:

The issue you're seeing with the HonAuthenticationError: Can't login during setup isn't related to any errors in the init code—it's an authentication failure when the pyhon library tries to log in to the Hon API. This is a common problem and it's usually tied to account-specific issues rather than the integration code itself.

Possible reasons: Invalid credentials: Double-check your email and password in the integration's config flow. Try resetting your password through the app and re-entering it.

or

2FA: If your Hon account is connected to Google and has two-factor authentication enabled, the integration can't handle the 2FA prompt, leading to login failures. Switch to a direct Hon account (create one without Google if needed) or temporarily disable 2FA on your Google account to test.

or

Token or server-side glitches: Your stored refresh token might be expired or corrupted. Try deleting the integration entry in Home Assistant and re-adding it fresh. Replace the init file code with the above.

or

Outdated versions: Ensure your pyhon library and the Hon integration are up to date (update via HACS if using it), as older versions had auth bugs that were fixed.

Without debug log it is difficult to tell. Try adding this to your configuration.yaml and then report back with debug log:

logger:
  logs:
    custom_components.hon: debug
    pyhon: debug

SleepyDelegate avatar Jul 15 '25 19:07 SleepyDelegate

There Is any news? The integration doesn't work

Daximino avatar Jul 17 '25 14:07 Daximino

Hi all, in orde to fix the issue I replacede in custom_components/hon/init.py the below code:

# for platform in PLATFORMS:
#     hass.async_create_task(
#         hass.config_entries.async_forward_entry_setup(entry, platform)
#     )

with: await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) this change works for me Regards.

Thanks, worked for me too.

THIS !

9H1LO avatar Jul 18 '25 14:07 9H1LO

There Is any news? The integration doesn't work

Yeah, above is entire new init file code, just replace it and you will have working integration. Or you can use the partial fix that some people also use. It is less practical, as it only fixes one problem.

SleepyDelegate avatar Jul 18 '25 16:07 SleepyDelegate