Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/schblondie/hon
Browse files Browse the repository at this point in the history
  • Loading branch information
schblondie committed Jun 6, 2024
2 parents 502e6e4 + 6906e75 commit bf3aed9
Show file tree
Hide file tree
Showing 49 changed files with 17,483 additions and 329 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/python_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@ jobs:
fail-fast: false
matrix:
include:
- home-assistant: "2024.1.0"
- home-assistant: "2024.2.0"
python-version: "3.11"
- home-assistant: "2024.2.0"
python-version: "3.12"
- home-assistant: "2024.3.0"
python-version: "3.11"
- home-assistant: "2024.3.0"
python-version: "3.12"

steps:
- uses: actions/checkout@v3
Expand Down
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ Home Assistant integration for [Haier's mobile app hOn](https://hon-smarthome.co
---


[![Supported Languages](https://img.shields.io/badge/Languages-19-royalblue)](https://github.com/Andre0512/hon#supported-languages)
[![Supported Languages](https://img.shields.io/badge/Languages-28-royalblue)](https://github.com/Andre0512/hon#supported-languages)
[![Supported Appliances](https://img.shields.io/badge/Appliances-11-forestgreen)](https://github.com/Andre0512/hon#supported-appliances)
[![Supported Models](https://img.shields.io/badge/Models-130-yellowgreen)](https://github.com/Andre0512/hon#supported-appliances)
[![Supported Models](https://img.shields.io/badge/Models-134-yellowgreen)](https://github.com/Andre0512/hon#supported-appliances)
[![Supported Entities](https://img.shields.io/badge/Entities-320-crimson)](https://github.com/Andre0512/hon#supported-appliances)

## Takedown Story
Expand Down Expand Up @@ -156,10 +156,11 @@ Support has been confirmed for these **4 models**, but many more will work. Plea
![Dish Washer](assets/example_dw.png)

### Supported Dish Washer models
Support has been confirmed for these **6 models**, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8).
Support has been confirmed for these **7 models**, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8).

#### Haier
- XIB 3B2SFS-80
- XIB 5C1S3FS
- XIB 6B2D3FB

#### Hoover
Expand Down Expand Up @@ -614,7 +615,7 @@ Support has been confirmed for these **15 models**, but many more will work. Ple
![Washing Machine](assets/example_wm.png)

### Supported Washing Machine models
Support has been confirmed for these **41 models**, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8).
Support has been confirmed for these **44 models**, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8).

#### Haier
- HW80-B1439N
Expand All @@ -625,11 +626,13 @@ Support has been confirmed for these **41 models**, but many more will work. Ple
- HW90-B14959U1
- HW90-B14959S8U1
- HW90-B14TEAM5
- HW90-BD14979U1
- HW90G-BD14979UD
- HW100-B14959U1
- HW110-14979

#### Hoover
- H3WOSQ495TA4-84
- H5WPB4 27BC8/1-S
- H5WPB447AMBC/1-S
- H7W 412MBCR-80
Expand All @@ -649,6 +652,7 @@ Support has been confirmed for these **41 models**, but many more will work. Ple
- HWB 414AMC/1-80
- HWE 49AMBS/1-S
- HWP 48AMBCR/1-S
- HWP 49AMBCR/1-S
- HWP 610AMBC/1-S
- HWPD 69AMBC/1-S
- HWPDQ49AMBC/1-S
Expand Down Expand Up @@ -748,25 +752,34 @@ _If the integration is not in the list, you need to clear the browser cache._

## Supported Languages
Translation of internal names like programs are available for all languages which are official supported by the hOn app:
* 🇸🇦 Arabic
* 🇧🇬 Bulgarian
* 🇨🇳 Chinese
* 🇭🇷 Croatian
* 🇨🇿 Czech
* 🇩🇰 Danish
* 🇳🇱 Dutch
* 🇬🇧 English
* 🇫🇮 Finnish
* 🇫🇷 French
* 🇩🇪 German
* 🇬🇷 Greek
* 🇮🇱 Hebrew
* 🇭🇺 Hungarian
* 🇮🇹 Italian
* 🇳🇴 Norwegian
* 🇵🇱 Polish
* 🇵🇹 Portuguese
* 🇷🇴 Romanian
* 🇷🇺 Russian
* 🇷🇸 Serbian
* 🇸🇰 Slovak
* 🇸🇮 Slovenian
* 🇿🇦 Southern Ndebele
* 🇪🇸 Spanish
* 🇸🇪 Swedish
* 🇹🇷 Turkish
* 🇺🇦 Ukrainian

## Compatibility
Haier offers different apps for different markets. Some appliances are compatible with more than one app. This integration only supports appliances that can be controlled via hOn. Please download the hOn app and check compatibility before you open an issue.
Expand Down
34 changes: 20 additions & 14 deletions custom_components/hon/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
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
Expand All @@ -29,23 +31,27 @@ 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")
kwargs = {
"email": entry.data[CONF_EMAIL],
"password": entry.data[CONF_PASSWORD],
"mobile_id": MOBILE_ID,
"session": session,
"test_data_path": Path(config_dir),
}
if refresh_token := entry.data.get(CONF_REFRESH_TOKEN):
kwargs["refresh_token"] = refresh_token
hon = await Hon(**kwargs).create()
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.unique_id] = hon
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}
)
hass.data[DOMAIN]["coordinators"] = {}

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}

for platform in PLATFORMS:
hass.async_create_task(
Expand All @@ -55,7 +61,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool


async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
refresh_token = hass.data[DOMAIN][entry.unique_id].api.auth.refresh_token
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}
Expand Down
32 changes: 29 additions & 3 deletions custom_components/hon/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
from homeassistant.helpers.typing import HomeAssistantType

from .const import DOMAIN
from .hon import HonEntity, unique_entities
from .entity import HonEntity
from .util import unique_entities

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -284,6 +285,32 @@ class HonBinarySensorEntityDescription(BinarySensorEntityDescription):
translation_key="on",
),
),
"FRE": (
HonBinarySensorEntityDescription(
key="quickModeZ1",
name="Super Cool",
icon="mdi:snowflake",
device_class=BinarySensorDeviceClass.RUNNING,
on_value=1,
translation_key="super_cool",
),
HonBinarySensorEntityDescription(
key="quickModeZ2",
name="Super Freeze",
icon="mdi:snowflake-variant",
device_class=BinarySensorDeviceClass.RUNNING,
on_value=1,
translation_key="super_freeze",
),
HonBinarySensorEntityDescription(
key="doorStatusZ2",
name="Door Status",
icon="mdi:fridge",
device_class=BinarySensorDeviceClass.DOOR,
on_value=1,
translation_key="door_open",
),
),
}

BINARY_SENSORS["WD"] = unique_entities(BINARY_SENSORS["WM"], BINARY_SENSORS["TD"])
Expand All @@ -293,12 +320,11 @@ async def async_setup_entry(
hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
entities = []
for device in hass.data[DOMAIN][entry.unique_id].appliances:
for device in hass.data[DOMAIN][entry.unique_id]["hon"].appliances:
for description in BINARY_SENSORS.get(device.appliance_type, []):
if device.get(description.key) is None:
continue
entity = HonBinarySensorEntity(hass, entry, device, description)
await entity.coordinator.async_config_entry_first_refresh()
entities.append(entity)
async_add_entities(entities)

Expand Down
36 changes: 21 additions & 15 deletions custom_components/hon/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pyhon.appliance import HonAppliance

from .const import DOMAIN
from .hon import HonEntity
from .entity import HonEntity
from .typedefs import HonButtonType

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -38,23 +38,35 @@
translation_key="stop_program",
),
),
"FRE": (
ButtonEntityDescription(
key="startProgram",
name="Program Start",
icon="mdi:play",
translation_key="start_program",
),
ButtonEntityDescription(
key="stopProgram",
name="Program Stop",
icon="mdi:stop",
translation_key="stop_program",
),
),
}


async def async_setup_entry(
hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
entities: list[HonButtonType] = []
for device in hass.data[DOMAIN][entry.unique_id].appliances:
for device in hass.data[DOMAIN][entry.unique_id]["hon"].appliances:
for description in BUTTONS.get(device.appliance_type, []):
if not device.commands.get(description.key):
continue
entity = HonButtonEntity(hass, entry, device, description)
await entity.coordinator.async_config_entry_first_refresh()
entities.append(entity)
entities.append(HonDeviceInfo(hass, entry, device))
entities.append(HonDataArchive(hass, entry, device))
await entities[-1].coordinator.async_config_entry_first_refresh()
async_add_entities(entities)


Expand All @@ -70,7 +82,7 @@ def available(self) -> bool:
return (
super().available
and int(self._device.get("remoteCtrValid", "1")) == 1
and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED"
and self._device.connection
)


Expand All @@ -84,19 +96,14 @@ def __init__(
self._attr_icon = "mdi:information"
self._attr_name = "Show Device Info"
self._attr_entity_category = EntityCategory.DIAGNOSTIC
if "beta" not in self.coordinator.info.hon_version:
self._attr_entity_registry_enabled_default = False
self._attr_entity_registry_enabled_default = False

async def async_press(self) -> None:
versions = "versions:\n"
versions += f" hon: {self.coordinator.info.hon_version}\n"
versions += f" pyhOn: {self.coordinator.info.pyhon_version}\n"
info = f"{self._device.diagnose}{versions}"
title = f"{self._device.nick_name} Device Info"
persistent_notification.create(
self._hass, f"````\n```\n{info}\n```\n````", title
self._hass, f"````\n```\n{self._device.diagnose}\n```\n````", title
)
_LOGGER.info(info.replace(" ", "\u200B "))
_LOGGER.info(self._device.diagnose.replace(" ", "\u200B "))


class HonDataArchive(HonEntity, ButtonEntity):
Expand All @@ -109,8 +116,7 @@ def __init__(
self._attr_icon = "mdi:archive-arrow-down"
self._attr_name = "Create Data Archive"
self._attr_entity_category = EntityCategory.DIAGNOSTIC
if "beta" not in self.coordinator.info.hon_version:
self._attr_entity_registry_enabled_default = False
self._attr_entity_registry_enabled_default = False

async def async_press(self) -> None:
if (config_dir := self._hass.config.config_dir) is None:
Expand Down
Loading

0 comments on commit bf3aed9

Please sign in to comment.