Compare commits
	
		
			1 Commits
		
	
	
		
			v0.5.0-bet
			...
			v0.1.1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 767a921602 | 
							
								
								
									
										17
									
								
								.github/workflows/hacs_check.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								.github/workflows/hacs_check.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,17 +0,0 @@ | ||||
| name: HACS Action | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|   pull_request: | ||||
|   schedule: | ||||
|     - cron: "0 0 * * *" | ||||
|  | ||||
| jobs: | ||||
|   hacs: | ||||
|     name: HACS Action | ||||
|     runs-on: "ubuntu-latest" | ||||
|     steps: | ||||
|       - name: HACS Action | ||||
|         uses: "hacs/action@main" | ||||
|         with: | ||||
|           category: "integration" | ||||
							
								
								
									
										14
									
								
								.github/workflows/validate.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/validate.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,14 +1,16 @@ | ||||
| name: Validate with hassfest | ||||
| name: Validate | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|   pull_request: | ||||
|   schedule: | ||||
|     - cron:  '0 0 * * *' | ||||
|  | ||||
| jobs: | ||||
|   validate: | ||||
|     runs-on: "ubuntu-latest" | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|         - uses: "actions/checkout@v3" | ||||
|         - uses: "home-assistant/actions/hassfest@master" | ||||
|       - uses: actions/checkout@v2 | ||||
|       - uses: home-assistant/actions/hassfest@master | ||||
|       - name: HACS validation | ||||
|         uses: hacs/action@main | ||||
|         with: | ||||
|           category: integration | ||||
							
								
								
									
										88
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								README.md
									
									
									
									
									
								
							| @ -1,83 +1,27 @@ | ||||
| # Haier hOn | ||||
| [](https://github.com/hacs/integration) | ||||
| [](https://github.com/Andre0512/hon/releases/latest) | ||||
| [](https://analytics.home-assistant.io/)   | ||||
| Home Assistant integration for Haier hOn: support for Haier/Candy/Hoover home appliances like washing machines. | ||||
| ## Supported Appliances | ||||
| - Tumble Dryer | ||||
| - Washer Dryer | ||||
| - Washing Machine | ||||
| - Oven | ||||
| Home Assistant component supporting hOn cloud. | ||||
|  | ||||
| ## Installation | ||||
| **Method 1:** [](https://my.home-assistant.io/redirect/hacs_repository/?owner=Andre0512&repository=hon&category=integration) | ||||
| #### Installing via HACS | ||||
| 1. You need to have installed [HACS](https://hacs.xyz/) | ||||
| 2. Go to HACS->Integrations | ||||
| 3. Add this repo (`https://github.com/Andre0512/haier.git`) into your HACS custom repositories | ||||
| 4. Search for Haier hOn and Download it | ||||
| 5. Restart your HomeAssistant | ||||
| 6. Go to Settings->Devices & Services | ||||
| 7. Shift reload your browser | ||||
| 8. Click Add Integration | ||||
| 9. Search for Haier hOn  | ||||
| 10. Type your username used in the hOn App and hit submit | ||||
|  | ||||
| **Method 2:** [HACS](https://hacs.xyz/) > Integrations > Add Integration > **Haier hOn** > Install   | ||||
|  | ||||
| **Method 3:** Manually copy `hon` folder from [latest release](https://github.com/Andre0512/hon/releases/latest) to `config/custom_components` folder. | ||||
|  | ||||
| _Restart Home Assistant_ | ||||
|  | ||||
| ## Configuration | ||||
|  | ||||
| **Method 1**: [](https://my.home-assistant.io/redirect/config_flow_start/?domain=hon) | ||||
|  | ||||
| **Method 2**: Settings > Devices & Services > Add Integration > **Haier hOn**   | ||||
| _If the integration is not in the list, you need to clear the browser cache._ | ||||
|  | ||||
| ## Contribute | ||||
| Any kind of contribution is welcome! | ||||
| #### Add appliances or additional attributes | ||||
| 1. Install [pyhOn](https://github.com/Andre0512/pyhOn) | ||||
|    ```commandline | ||||
|     $ pip install pyhOn | ||||
|     ``` | ||||
| 2. Use the commandline tool to read out all appliance data from your account | ||||
|     ```commandline | ||||
|     $ pyhOn | ||||
|     User for hOn account: user.name@example.com | ||||
|     Password for hOn account: ******** | ||||
|     ========== WM - Washing Machine ========== | ||||
|     commands: | ||||
|       pauseProgram: pauseProgram command | ||||
|       resumeProgram: resumeProgram command | ||||
|       startProgram: startProgram command | ||||
|       stopProgram: stopProgram command | ||||
|     data: | ||||
|       actualWeight: 0 | ||||
|       airWashTempLevel: 0 | ||||
|       airWashTime: 0 | ||||
|       antiAllergyStatus: 0 | ||||
|       ... | ||||
|     ``` | ||||
| 3. Fork this repository and clone it to your local machine | ||||
| 4. Add the keys of the attributes you'd like to have as `EntityDescription` into this Repository   | ||||
|    _Example: Add pause button_ | ||||
|     ```python | ||||
|     BUTTONS: dict[str, tuple[ButtonEntityDescription, ...]] = { | ||||
|         "WM": (                        # WM is the applianceTypeName | ||||
|             ButtonEntityDescription( | ||||
|                 key="pauseProgram",    # key from pyhOn | ||||
|                 name="Pause Program",  # name in home assistant | ||||
|                 icon="mdi:pause",      # icon in home assistant | ||||
|                 ... | ||||
|             ), | ||||
|         ... | ||||
|     ``` | ||||
| 5. Create a [pull request](https://github.com/Andre0512/hon/pulls) | ||||
|  | ||||
| #### Tips and Tricks | ||||
| - If you want to have some states humanreadable, have a look at the `translation_key` parameter of the `EntityDescription`. | ||||
| - If you need to implement some more logic, create a pull request to the underlying library. There we collect special requirements in the `appliances` directory. | ||||
| - Use [pyhOn](https://github.com/Andre0512/pyhOn)s translate command to read out the official translations  | ||||
| ## Supported Appliances | ||||
| - Washing Machine | ||||
|  | ||||
| ## Tested Devices | ||||
| - Haier WD90-B14TEAM5 | ||||
| - Haier HD80-A3959 | ||||
| - Haier HWO60SM2F3XH | ||||
| - Hoover H-WASH 500 | ||||
| - Haier WD90 | ||||
|  | ||||
| ## About this Repo | ||||
| The existing integrations missed some features from the app I liked to have in HomeAssistant. | ||||
| I tried to create a pull request, but in the structures of these existing repos, I find it hard to fit in my needs, so I basically rewrote everything.  | ||||
| I moved the api related stuff into the package [pyhOn](https://github.com/Andre0512/pyhOn). | ||||
|  | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import logging | ||||
| 
 | ||||
| import voluptuous as vol | ||||
| from pyhon import Hon | ||||
| from pyhon import HonConnection | ||||
| 
 | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from homeassistant.const import CONF_EMAIL, CONF_PASSWORD | ||||
| @ -28,7 +28,8 @@ CONFIG_SCHEMA = vol.Schema( | ||||
| 
 | ||||
| async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): | ||||
|     session = aiohttp_client.async_get_clientsession(hass) | ||||
|     hon = await Hon(entry.data["email"], entry.data["password"], session=session).create() | ||||
|     hon = HonConnection(entry.data["email"], entry.data["password"], session) | ||||
|     await hon.setup() | ||||
|     hass.data.setdefault(DOMAIN, {}) | ||||
|     hass.data[DOMAIN][entry.unique_id] = hon | ||||
|     hass.data[DOMAIN]["coordinators"] = {} | ||||
							
								
								
									
										86
									
								
								custom_components/haier/binary_sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								custom_components/haier/binary_sensor.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,86 @@ | ||||
| import logging | ||||
| from dataclasses import dataclass | ||||
|  | ||||
| from pyhon import HonConnection | ||||
|  | ||||
| from homeassistant.components.binary_sensor import BinarySensorEntityDescription, BinarySensorDeviceClass, \ | ||||
|     BinarySensorEntity | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from homeassistant.core import callback | ||||
| from .const import DOMAIN | ||||
| from .hon import HonCoordinator, HonEntity | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| @dataclass | ||||
| class HonBinarySensorEntityDescriptionMixin: | ||||
|     on_value: str = "" | ||||
|  | ||||
|  | ||||
| @dataclass | ||||
| class HonBinarySensorEntityDescription(HonBinarySensorEntityDescriptionMixin, BinarySensorEntityDescription): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| BINARY_SENSORS: dict[str, tuple[HonBinarySensorEntityDescription, ...]] = { | ||||
|     "WM": ( | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="lastConnEvent.category", | ||||
|             name="Connection", | ||||
|             device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||||
|             on_value="CONNECTED", | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="doorLockStatus", | ||||
|             name="Door Locked", | ||||
|             device_class=BinarySensorDeviceClass.DOOR, | ||||
|             on_value="0", | ||||
|         ), | ||||
|     ) | ||||
| } | ||||
|  | ||||
|  | ||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] | ||||
|     coordinators = hass.data[DOMAIN]["coordinators"] | ||||
|     appliances = [] | ||||
|     for device in hon.devices: | ||||
|         if device.mac_address in coordinators: | ||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] | ||||
|         else: | ||||
|             coordinator = HonCoordinator(hass, device) | ||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator | ||||
|         await coordinator.async_config_entry_first_refresh() | ||||
|  | ||||
|         if descriptions := BINARY_SENSORS.get(device.appliance_type_name): | ||||
|             for description in descriptions: | ||||
|                 if not device.data.get(description.key): | ||||
|                     _LOGGER.info("Can't setup %s", description.key) | ||||
|                     continue | ||||
|                 appliances.extend([ | ||||
|                     HonBinarySensorEntity(hass, coordinator, entry, device, description)] | ||||
|                 ) | ||||
|  | ||||
|     async_add_entities(appliances) | ||||
|  | ||||
|  | ||||
| class HonBinarySensorEntity(HonEntity, BinarySensorEntity): | ||||
|     entity_description: HonBinarySensorEntityDescription | ||||
|  | ||||
|     def __init__(self, hass, coordinator, entry, device, description) -> None: | ||||
|         super().__init__(hass, entry, coordinator, device) | ||||
|  | ||||
|         self._coordinator = coordinator | ||||
|  | ||||
|         self.entity_description = description | ||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" | ||||
|  | ||||
|     @property | ||||
|     def is_on(self) -> bool: | ||||
|         return self._device.data.get(self.entity_description.key, "") == self.entity_description.on_value | ||||
|  | ||||
|     @callback | ||||
|     def _handle_coordinator_update(self): | ||||
|         self._attr_native_value = self._device.data.get(self.entity_description.key, "") | ||||
|         self.async_write_ha_state() | ||||
| @ -1,32 +1,33 @@ | ||||
| from pyhon import HonConnection | ||||
| from pyhon.device import HonDevice | ||||
| 
 | ||||
| from homeassistant.components.button import ButtonEntityDescription, ButtonEntity | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from pyhon import Hon | ||||
| from pyhon.appliance import HonAppliance | ||||
| 
 | ||||
| from .const import DOMAIN | ||||
| from .hon import HonCoordinator, HonEntity | ||||
| 
 | ||||
| BUTTONS: dict[str, tuple[ButtonEntityDescription, ...]] = { | ||||
|     "OV": ( | ||||
|     "WM": ( | ||||
|         ButtonEntityDescription( | ||||
|             key="startProgram", | ||||
|             name="Start Program", | ||||
|             icon="mdi:power-cycle", | ||||
|             key="pauseProgram", | ||||
|             name="Pause Program", | ||||
|             icon="mdi:pause", | ||||
|         ), | ||||
|         ButtonEntityDescription( | ||||
|             key="stopProgram", | ||||
|             name="Stop Program", | ||||
|             icon="mdi:power-off", | ||||
|             key="resumeProgram", | ||||
|             name="Resume Program", | ||||
|             icon="mdi:play-pause", | ||||
|         ), | ||||
|     ) | ||||
|     ), | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||
|     hon: Hon = hass.data[DOMAIN][entry.unique_id] | ||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] | ||||
|     coordinators = hass.data[DOMAIN]["coordinators"] | ||||
|     appliances = [] | ||||
|     for device in hon.appliances: | ||||
|     for device in hon.devices: | ||||
|         if device.mac_address in coordinators: | ||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] | ||||
|         else: | ||||
| @ -34,7 +35,7 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non | ||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator | ||||
|         await coordinator.async_config_entry_first_refresh() | ||||
| 
 | ||||
|         if descriptions := BUTTONS.get(device.appliance_type): | ||||
|         if descriptions := BUTTONS.get(device.appliance_type_name): | ||||
|             for description in descriptions: | ||||
|                 if not device.commands.get(description.key): | ||||
|                     continue | ||||
| @ -46,7 +47,7 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non | ||||
| 
 | ||||
| 
 | ||||
| class HonButtonEntity(HonEntity, ButtonEntity): | ||||
|     def __init__(self, hass, coordinator, entry, device: HonAppliance, description) -> None: | ||||
|     def __init__(self, hass, coordinator, entry, device: HonDevice, description) -> None: | ||||
|         super().__init__(hass, entry, coordinator, device) | ||||
| 
 | ||||
|         self._coordinator = coordinator | ||||
| @ -1,4 +1,4 @@ | ||||
| DOMAIN = "hon" | ||||
| DOMAIN = "haier" | ||||
| 
 | ||||
| PLATFORMS = [ | ||||
|     "sensor", | ||||
| @ -1,7 +1,7 @@ | ||||
| import logging | ||||
| from datetime import timedelta | ||||
| 
 | ||||
| from pyhon.appliance import HonAppliance | ||||
| from pyhon.device import HonDevice | ||||
| 
 | ||||
| from homeassistant.helpers.entity import DeviceInfo | ||||
| from homeassistant.helpers.update_coordinator import CoordinatorEntity | ||||
| @ -15,7 +15,7 @@ _LOGGER = logging.getLogger(__name__) | ||||
| class HonEntity(CoordinatorEntity): | ||||
|     _attr_has_entity_name = True | ||||
| 
 | ||||
|     def __init__(self, hass, entry, coordinator, device: HonAppliance) -> None: | ||||
|     def __init__(self, hass, entry, coordinator, device: HonDevice) -> None: | ||||
|         super().__init__(coordinator) | ||||
| 
 | ||||
|         self._hon = hass.data[DOMAIN][entry.unique_id] | ||||
| @ -28,15 +28,15 @@ class HonEntity(CoordinatorEntity): | ||||
|     def device_info(self): | ||||
|         return DeviceInfo( | ||||
|             identifiers={(DOMAIN, self._device.mac_address)}, | ||||
|             manufacturer=self._device.get("brand", ""), | ||||
|             manufacturer=self._device.brand, | ||||
|             name=self._device.nick_name if self._device.nick_name else self._device.model_name, | ||||
|             model=self._device.model_name, | ||||
|             sw_version=self._device.get("fwVersion", ""), | ||||
|             sw_version=self._device.fw_version, | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| class HonCoordinator(DataUpdateCoordinator): | ||||
|     def __init__(self, hass, device: HonAppliance): | ||||
|     def __init__(self, hass, device: HonDevice): | ||||
|         """Initialize my coordinator.""" | ||||
|         super().__init__(hass, _LOGGER, name=device.mac_address, update_interval=timedelta(seconds=30)) | ||||
|         self._device = device | ||||
							
								
								
									
										10
									
								
								custom_components/haier/manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								custom_components/haier/manifest.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| { | ||||
|   "domain": "haier", | ||||
|   "name": "Haier hOn", | ||||
|   "codeowners": ["@Andre0512"], | ||||
|   "config_flow": true, | ||||
|   "documentation": "https://github.com/Andre0512/haier/", | ||||
|   "iot_class": "cloud_polling", | ||||
|   "requirements": ["pyhOn==0.2.4"], | ||||
|   "version": "0.1.1" | ||||
| } | ||||
							
								
								
									
										94
									
								
								custom_components/haier/number.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								custom_components/haier/number.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | ||||
| from __future__ import annotations | ||||
|  | ||||
| from pyhon import HonConnection | ||||
| from pyhon.parameter import HonParameterRange | ||||
|  | ||||
| from homeassistant.components.number import ( | ||||
|     NumberEntity, | ||||
|     NumberEntityDescription, | ||||
| ) | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from homeassistant.const import UnitOfTime | ||||
| from homeassistant.core import callback | ||||
| from homeassistant.helpers.entity import EntityCategory | ||||
|  | ||||
| from .const import DOMAIN | ||||
| from .hon import HonEntity, HonCoordinator | ||||
|  | ||||
| NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = { | ||||
|     "WM": ( | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.delayTime", | ||||
|             name="Delay Time", | ||||
|             icon="mdi:timer", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES | ||||
|         ), | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.rinseIterations", | ||||
|             name="Rinse Iterations", | ||||
|             entity_category=EntityCategory.CONFIG | ||||
|         ), | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.mainWashTime", | ||||
|             name="Main Wash Time", | ||||
|             icon="mdi:timer", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES | ||||
|         ), | ||||
|     ), | ||||
| } | ||||
|  | ||||
|  | ||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] | ||||
|     coordinators = hass.data[DOMAIN]["coordinators"] | ||||
|     appliances = [] | ||||
|     for device in hon.devices: | ||||
|         if device.mac_address in coordinators: | ||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] | ||||
|         else: | ||||
|             coordinator = HonCoordinator(hass, device) | ||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator | ||||
|         await coordinator.async_config_entry_first_refresh() | ||||
|  | ||||
|         if descriptions := NUMBERS.get(device.appliance_type_name): | ||||
|             for description in descriptions: | ||||
|                 appliances.extend([ | ||||
|                     HonNumberEntity(hass, coordinator, entry, device, description)] | ||||
|                 ) | ||||
|  | ||||
|     async_add_entities(appliances) | ||||
|  | ||||
|  | ||||
| class HonNumberEntity(HonEntity, NumberEntity): | ||||
|     def __init__(self, hass, coordinator, entry, device, description) -> None: | ||||
|         super().__init__(hass, entry, coordinator, device) | ||||
|  | ||||
|         self._coordinator = coordinator | ||||
|         self._data = device.settings[description.key] | ||||
|         self.entity_description = description | ||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" | ||||
|  | ||||
|         if isinstance(self._data, HonParameterRange): | ||||
|             self._attr_native_max_value = self._data.max | ||||
|             self._attr_native_min_value = self._data.min | ||||
|             self._attr_native_step = self._data.step | ||||
|  | ||||
|     @property | ||||
|     def native_value(self) -> float | None: | ||||
|         return self._data.value | ||||
|  | ||||
|     async def async_set_native_value(self, value: float) -> None: | ||||
|         self._data.value = value | ||||
|         await self.coordinator.async_request_refresh() | ||||
|  | ||||
|     @callback | ||||
|     def _handle_coordinator_update(self): | ||||
|         self._data = self._device.settings[self.entity_description.key] | ||||
|         if isinstance(self._data, HonParameterRange): | ||||
|             self._attr_native_max_value = self._data.max | ||||
|             self._attr_native_min_value = self._data.min | ||||
|             self._attr_native_step = self._data.step | ||||
|         self._attr_native_value = self._data.value | ||||
|         self.async_write_ha_state() | ||||
| @ -1,22 +1,18 @@ | ||||
| from __future__ import annotations | ||||
| 
 | ||||
| import logging | ||||
| 
 | ||||
| from pyhon import Hon | ||||
| from pyhon.appliance import HonAppliance | ||||
| from pyhon import HonConnection | ||||
| from pyhon.device import HonDevice | ||||
| from pyhon.parameter import HonParameterFixed | ||||
| 
 | ||||
| from homeassistant.components.select import SelectEntity, SelectEntityDescription | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from homeassistant.const import UnitOfTemperature, UnitOfTime, REVOLUTIONS_PER_MINUTE | ||||
| from homeassistant.const import UnitOfTemperature, REVOLUTIONS_PER_MINUTE | ||||
| from homeassistant.core import callback | ||||
| from homeassistant.helpers.entity import EntityCategory | ||||
| 
 | ||||
| from .const import DOMAIN | ||||
| from .hon import HonEntity, HonCoordinator | ||||
| 
 | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
| 
 | ||||
| SELECTS = { | ||||
|     "WM": ( | ||||
|         SelectEntityDescription( | ||||
| @ -35,54 +31,18 @@ SELECTS = { | ||||
|         ), | ||||
|         SelectEntityDescription( | ||||
|             key="startProgram.program", | ||||
|             name="Program", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             translation_key="programs" | ||||
|         ), | ||||
|     ), | ||||
|     "TD": ( | ||||
|         SelectEntityDescription( | ||||
|             key="startProgram.program", | ||||
|             name="Program", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             translation_key="programs" | ||||
|         ), | ||||
|         SelectEntityDescription( | ||||
|             key="startProgram.dryTimeMM", | ||||
|             name="Time", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             icon="mdi:timer", | ||||
|             unit_of_measurement=UnitOfTime.MINUTES | ||||
|         ), | ||||
|     ), | ||||
|     "WD": ( | ||||
|         SelectEntityDescription( | ||||
|             key="startProgram.program", | ||||
|             name="Program", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             translation_key="programs" | ||||
|         ), | ||||
|     ), | ||||
|     "OV": ( | ||||
|         SelectEntityDescription( | ||||
|             key="startProgram.program", | ||||
|             name="Program", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|         ), | ||||
|         SelectEntityDescription( | ||||
|             key="startProgram.preheatStatus", | ||||
|             name="Preheat", | ||||
|             name="Programme", | ||||
|             entity_category=EntityCategory.CONFIG | ||||
|         ), | ||||
|     ), | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||
|     hon: Hon = hass.data[DOMAIN][entry.unique_id] | ||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] | ||||
|     coordinators = hass.data[DOMAIN]["coordinators"] | ||||
|     appliances = [] | ||||
|     for device in hon.appliances: | ||||
|     for device in hon.devices: | ||||
|         if device.mac_address in coordinators: | ||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] | ||||
|         else: | ||||
| @ -90,9 +50,9 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non | ||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator | ||||
|         await coordinator.async_config_entry_first_refresh() | ||||
| 
 | ||||
|         if descriptions := SELECTS.get(device.appliance_type): | ||||
|         if descriptions := SELECTS.get(device.appliance_type_name): | ||||
|             for description in descriptions: | ||||
|                 if not device.settings.get(description.key): | ||||
|                 if not device.data.get(description.key): | ||||
|                     continue | ||||
|                 appliances.extend([ | ||||
|                     HonSelectEntity(hass, coordinator, entry, device, description)] | ||||
| @ -101,36 +61,37 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non | ||||
| 
 | ||||
| 
 | ||||
| class HonSelectEntity(HonEntity, SelectEntity): | ||||
|     def __init__(self, hass, coordinator, entry, device: HonAppliance, description) -> None: | ||||
|     def __init__(self, hass, coordinator, entry, device: HonDevice, description) -> None: | ||||
|         super().__init__(hass, entry, coordinator, device) | ||||
| 
 | ||||
|         self._coordinator = coordinator | ||||
|         self._device = device | ||||
|         self._data = device.settings[description.key] | ||||
|         self.entity_description = description | ||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" | ||||
| 
 | ||||
|         if not isinstance(self._device.settings[description.key], HonParameterFixed): | ||||
|             self._attr_options: list[str] = device.settings[description.key].values | ||||
|         if not isinstance(self._data, HonParameterFixed): | ||||
|             self._attr_options: list[str] = self._data.values | ||||
|         else: | ||||
|             self._attr_options: list[str] = [device.settings[description.key].value] | ||||
|             self._attr_options = [self._data.value] | ||||
| 
 | ||||
|     @property | ||||
|     def current_option(self) -> str | None: | ||||
|         value = self._device.settings[self.entity_description.key].value | ||||
|         value = self._data.value | ||||
|         if value is None or value not in self._attr_options: | ||||
|             return None | ||||
|         return value | ||||
| 
 | ||||
|     async def async_select_option(self, option: str) -> None: | ||||
|         self._device.settings[self.entity_description.key].value = option | ||||
|         self._data.value = option | ||||
|         await self.coordinator.async_request_refresh() | ||||
| 
 | ||||
|     @callback | ||||
|     def _handle_coordinator_update(self): | ||||
|         setting = self._device.settings[self.entity_description.key] | ||||
|         if not isinstance(self._device.settings[self.entity_description.key], HonParameterFixed): | ||||
|             self._attr_options: list[str] = setting.values | ||||
|         self._data = self._device.settings[self.entity_description.key] | ||||
|         if not isinstance(self._data, HonParameterFixed): | ||||
|             self._attr_options: list[str] = self._data.values | ||||
|         else: | ||||
|             self._attr_options = [setting.value] | ||||
|         self._attr_native_value = setting.value | ||||
|             self._attr_options = [self._data.value] | ||||
|         self._attr_native_value = self._data.value | ||||
|         self.async_write_ha_state() | ||||
							
								
								
									
										135
									
								
								custom_components/haier/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								custom_components/haier/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | ||||
| import logging | ||||
|  | ||||
| from pyhon import HonConnection | ||||
|  | ||||
| from homeassistant.components.sensor import ( | ||||
|     SensorEntity, | ||||
|     SensorDeviceClass, | ||||
|     SensorStateClass, | ||||
|     SensorEntityDescription, | ||||
| ) | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from homeassistant.const import UnitOfEnergy, UnitOfVolume, UnitOfMass, UnitOfPower, UnitOfTime | ||||
| from homeassistant.core import callback | ||||
| from homeassistant.helpers.entity import EntityCategory | ||||
| from homeassistant.helpers.typing import StateType | ||||
|  | ||||
| from .const import DOMAIN | ||||
| from .hon import HonCoordinator, HonEntity | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { | ||||
|     "WM": ( | ||||
|         SensorEntityDescription( | ||||
|             key="totalElectricityUsed", | ||||
|             name="Total Power", | ||||
|             device_class=SensorDeviceClass.ENERGY, | ||||
|             state_class=SensorStateClass.TOTAL_INCREASING, | ||||
|             native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="totalWaterUsed", | ||||
|             name="Total Water", | ||||
|             device_class=SensorDeviceClass.WATER, | ||||
|             state_class=SensorStateClass.TOTAL_INCREASING, | ||||
|             native_unit_of_measurement=UnitOfVolume.LITERS | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="totalWashCycle", | ||||
|             name="Total Wash Cycle", | ||||
|             state_class=SensorStateClass.TOTAL_INCREASING, | ||||
|             icon="mdi:counter" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="currentElectricityUsed", | ||||
|             name="Current Electricity Used", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             device_class=SensorDeviceClass.POWER, | ||||
|             native_unit_of_measurement=UnitOfPower.KILO_WATT, | ||||
|             icon="mdi:lightning-bolt" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="currentWaterUsed", | ||||
|             name="Current Water Used", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             icon="mdi:water" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="startProgram.weight", | ||||
|             name="Suggested weight", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             native_unit_of_measurement=UnitOfMass.KILOGRAMS, | ||||
|             icon="mdi:weight-kilogram" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="machMode", | ||||
|             name="Machine Last Status", | ||||
|             icon="mdi:information", | ||||
|             translation_key="mode" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="errors", | ||||
|             name="Last Error", | ||||
|             icon="mdi:math-log", | ||||
|             translation_key="errors" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="remainingTimeMM", | ||||
|             name="Remaining Time", | ||||
|             icon="mdi:timer", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="spinSpeed", | ||||
|             name="Spin Speed", | ||||
|             icon="mdi:timer", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||
|         ), | ||||
|     ) | ||||
| } | ||||
|  | ||||
|  | ||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] | ||||
|     coordinators = hass.data[DOMAIN]["coordinators"] | ||||
|     appliances = [] | ||||
|     for device in hon.devices: | ||||
|         if device.mac_address in coordinators: | ||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] | ||||
|         else: | ||||
|             coordinator = HonCoordinator(hass, device) | ||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator | ||||
|         await coordinator.async_config_entry_first_refresh() | ||||
|  | ||||
|         if descriptions := SENSORS.get(device.appliance_type_name): | ||||
|             for description in descriptions: | ||||
|                 if not device.data.get(description.key): | ||||
|                     continue | ||||
|                 appliances.extend([ | ||||
|                     HonSensorEntity(hass, coordinator, entry, device, description)] | ||||
|                 ) | ||||
|  | ||||
|     async_add_entities(appliances) | ||||
|  | ||||
|  | ||||
| class HonSensorEntity(HonEntity, SensorEntity): | ||||
|     def __init__(self, hass, coordinator, entry, device, description) -> None: | ||||
|         super().__init__(hass, entry, coordinator, device) | ||||
|  | ||||
|         self._coordinator = coordinator | ||||
|  | ||||
|         self.entity_description = description | ||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" | ||||
|  | ||||
|     @property | ||||
|     def native_value(self) -> StateType: | ||||
|         return self._device.data.get(self.entity_description.key, "") | ||||
|  | ||||
|     @callback | ||||
|     def _handle_coordinator_update(self): | ||||
|         self._attr_native_value = self._device.data.get(self.entity_description.key, "") | ||||
|         self.async_write_ha_state() | ||||
| @ -1,19 +1,15 @@ | ||||
| import logging | ||||
| 
 | ||||
| from dataclasses import dataclass | ||||
| from typing import Any | ||||
| 
 | ||||
| from homeassistant.components.switch import SwitchEntityDescription, SwitchEntity | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from homeassistant.const import EntityCategory | ||||
| from pyhon import Hon | ||||
| from pyhon.appliance import HonAppliance | ||||
| from pyhon import HonConnection | ||||
| from pyhon.device import HonDevice | ||||
| 
 | ||||
| from .const import DOMAIN | ||||
| from .hon import HonCoordinator, HonEntity | ||||
| 
 | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
| 
 | ||||
| 
 | ||||
| @dataclass | ||||
| class HonSwitchEntityDescriptionMixin: | ||||
| @ -23,80 +19,39 @@ class HonSwitchEntityDescriptionMixin: | ||||
| 
 | ||||
| @dataclass | ||||
| class HonSwitchEntityDescription(HonSwitchEntityDescriptionMixin, | ||||
|                                  SwitchEntityDescription | ||||
|                                  ): | ||||
|     SwitchEntityDescription | ||||
| ): | ||||
|     pass | ||||
| 
 | ||||
| 
 | ||||
| SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { | ||||
|     "WM": ( | ||||
|         HonSwitchEntityDescription( | ||||
|             key="active", | ||||
|             name="Washing Machine", | ||||
|             icon="mdi:washing-machine", | ||||
|             key="startProgram", | ||||
|             name="Start Program", | ||||
|             icon="mdi:play", | ||||
|             turn_on_key="startProgram", | ||||
|             turn_off_key="stopProgram", | ||||
|         ), | ||||
|         HonSwitchEntityDescription( | ||||
|             key="pause", | ||||
|             name="Pause Washing Machine", | ||||
|             icon="mdi:pause", | ||||
|             turn_on_key="pauseProgram", | ||||
|             turn_off_key="resumeProgram", | ||||
|         ), | ||||
|         HonSwitchEntityDescription( | ||||
|             key="startProgram.delayStatus", | ||||
|             name="Delay Status", | ||||
|             icon="mdi:timer-check", | ||||
|             entity_category=EntityCategory.CONFIG | ||||
|         ), | ||||
|         HonSwitchEntityDescription( | ||||
|             key="startProgram.haier_SoakPrewashSelection", | ||||
|             name="Soak Prewash Selection", | ||||
|             icon="mdi:tshirt-crew", | ||||
|             entity_category=EntityCategory.CONFIG | ||||
|         ), | ||||
|     ), | ||||
|     "TD": ( | ||||
|         HonSwitchEntityDescription( | ||||
|             key="active", | ||||
|             name="Tumble Dryer", | ||||
|             icon="mdi:tumble-dryer", | ||||
|             turn_on_key="startProgram", | ||||
|             turn_off_key="stopProgram", | ||||
|         ), | ||||
|         HonSwitchEntityDescription( | ||||
|             key="pause", | ||||
|             name="Pause Tumble Dryer", | ||||
|             icon="mdi:pause", | ||||
|             turn_on_key="pauseProgram", | ||||
|             turn_off_key="resumeProgram", | ||||
|         ), | ||||
|     ), | ||||
|     "WD": ( | ||||
|         HonSwitchEntityDescription( | ||||
|             key="active", | ||||
|             name="Washing Machine", | ||||
|             icon="mdi:washing-machine", | ||||
|             turn_on_key="startProgram", | ||||
|             turn_off_key="stopProgram", | ||||
|         ), | ||||
|         HonSwitchEntityDescription( | ||||
|             key="pause", | ||||
|             name="Pause Washing Machine", | ||||
|             icon="mdi:pause", | ||||
|             turn_on_key="pauseProgram", | ||||
|             turn_off_key="resumeProgram", | ||||
|         ), | ||||
|     ), | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||
|     hon: Hon = hass.data[DOMAIN][entry.unique_id] | ||||
|     hon: HonConnection = hass.data[DOMAIN][entry.unique_id] | ||||
|     coordinators = hass.data[DOMAIN]["coordinators"] | ||||
|     appliances = [] | ||||
|     for device in hon.appliances: | ||||
|     for device in hon.devices: | ||||
|         if device.mac_address in coordinators: | ||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] | ||||
|         else: | ||||
| @ -104,14 +59,12 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non | ||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator | ||||
|         await coordinator.async_config_entry_first_refresh() | ||||
| 
 | ||||
|         if descriptions := SWITCHES.get(device.appliance_type): | ||||
|         if descriptions := SWITCHES.get(device.appliance_type_name): | ||||
|             for description in descriptions: | ||||
|                 if device.get(description.key) is not None or device.commands.get(description.key) is not None: | ||||
|                 if device.data.get(description.key) is not None or device.commands.get(description.key) is not None: | ||||
|                     appliances.extend([ | ||||
|                         HonSwitchEntity(hass, coordinator, entry, device, description)] | ||||
|                     ) | ||||
|                 else: | ||||
|                     _LOGGER.warning("[%s] Can't setup %s", device.appliance_type, description.key) | ||||
| 
 | ||||
|     async_add_entities(appliances) | ||||
| 
 | ||||
| @ -119,7 +72,7 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non | ||||
| class HonSwitchEntity(HonEntity, SwitchEntity): | ||||
|     entity_description: HonSwitchEntityDescription | ||||
| 
 | ||||
|     def __init__(self, hass, coordinator, entry, device: HonAppliance, description: HonSwitchEntityDescription) -> None: | ||||
|     def __init__(self, hass, coordinator, entry, device: HonDevice, description: HonSwitchEntityDescription) -> None: | ||||
|         super().__init__(hass, entry, coordinator, device) | ||||
|         self._coordinator = coordinator | ||||
|         self._device = device | ||||
| @ -128,7 +81,7 @@ class HonSwitchEntity(HonEntity, SwitchEntity): | ||||
| 
 | ||||
|     def available(self) -> bool: | ||||
|         if self.entity_category == EntityCategory.CONFIG: | ||||
|             return self._device.settings[self.entity_description.key].typology != "fixed" | ||||
|             return self._device.settings[self.entity_description.key].typology == "fixed" | ||||
|         return True | ||||
| 
 | ||||
|     @property | ||||
| @ -137,7 +90,7 @@ class HonSwitchEntity(HonEntity, SwitchEntity): | ||||
|         if self.entity_category == EntityCategory.CONFIG: | ||||
|             setting = self._device.settings[self.entity_description.key] | ||||
|             return setting.value == "1" or hasattr(setting, "min") and setting.value != setting.min | ||||
|         return self._device.get(self.entity_description.key, False) | ||||
|         return self._device.data.get(self.entity_description.key, "") | ||||
| 
 | ||||
|     async def async_turn_on(self, **kwargs: Any) -> None: | ||||
|         if self.entity_category == EntityCategory.CONFIG: | ||||
| @ -154,3 +107,5 @@ class HonSwitchEntity(HonEntity, SwitchEntity): | ||||
|             self.async_write_ha_state() | ||||
|         else: | ||||
|             await self._device.commands[self.entity_description.turn_off_key].send() | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										36
									
								
								custom_components/haier/translations/en.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								custom_components/haier/translations/en.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| { | ||||
|   "config": { | ||||
|     "step": { | ||||
|       "user": { | ||||
|         "title": "Haier hOn", | ||||
|         "description": "Please enters your hOn credentials", | ||||
|         "data": { | ||||
|           "email": "Email Address", | ||||
|           "password": "Password" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "entity": { | ||||
|     "sensor": { | ||||
|       "mode": { | ||||
|         "state": { | ||||
|           "0": "Disconnected", | ||||
|           "1": "Ready", | ||||
|           "2": "Running", | ||||
|           "3": "Paused", | ||||
|           "5": "Scheduled", | ||||
|           "6": "Error", | ||||
|           "7": "Finished" | ||||
|         } | ||||
|       }, | ||||
|       "errors": { | ||||
|         "state": { | ||||
|           "00": "No error", | ||||
|           "100000000000": "E2: Check if the door is closed", | ||||
|           "8000000000000": "E4: Check the water supply" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -1,167 +0,0 @@ | ||||
| import logging | ||||
| from dataclasses import dataclass | ||||
|  | ||||
| from pyhon import Hon | ||||
|  | ||||
| from homeassistant.components.binary_sensor import BinarySensorEntityDescription, BinarySensorDeviceClass, \ | ||||
|     BinarySensorEntity | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from homeassistant.core import callback | ||||
| from .const import DOMAIN | ||||
| from .hon import HonCoordinator, HonEntity | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| @dataclass | ||||
| class HonBinarySensorEntityDescriptionMixin: | ||||
|     on_value: str = "" | ||||
|  | ||||
|  | ||||
| @dataclass | ||||
| class HonBinarySensorEntityDescription(HonBinarySensorEntityDescriptionMixin, BinarySensorEntityDescription): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| BINARY_SENSORS: dict[str, tuple[HonBinarySensorEntityDescription, ...]] = { | ||||
|     "WM": ( | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="attributes.lastConnEvent.category", | ||||
|             name="Remote Control", | ||||
|             device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||||
|             on_value="CONNECTED", | ||||
|             icon="mdi:remote" | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="doorLockStatus", | ||||
|             name="Door Lock", | ||||
|             device_class=BinarySensorDeviceClass.LOCK, | ||||
|             on_value="0", | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="doorStatus", | ||||
|             name="Door", | ||||
|             device_class=BinarySensorDeviceClass.DOOR, | ||||
|             on_value="1", | ||||
|         ), | ||||
|     ), | ||||
|     "TD": ( | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="attributes.lastConnEvent.category", | ||||
|             name="Connection", | ||||
|             device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||||
|             on_value="CONNECTED", | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="doorStatus", | ||||
|             name="Door", | ||||
|             device_class=BinarySensorDeviceClass.DOOR, | ||||
|             on_value="1", | ||||
|         ), | ||||
|     ), | ||||
|     "WD": ( | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="attributes.lastConnEvent.category", | ||||
|             name="Remote Control", | ||||
|             device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||||
|             on_value="CONNECTED", | ||||
|             icon="mdi:remote" | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="startProgram.prewash", | ||||
|             name="Pre Wash", | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="extraRinse1", | ||||
|             name="Extra Rinse 1", | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="extraRinse2", | ||||
|             name="Extra Rinse 2", | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="extraRinse3", | ||||
|             name="Extra Rinse 3", | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="goodNight", | ||||
|             name="Good Night Mode", | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="acquaplus", | ||||
|             name="Acqua Plus", | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="anticrease", | ||||
|             name="Anti-Crease", | ||||
|         ), | ||||
|     ), | ||||
|     "OV": ( | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="attributes.lastConnEvent.category", | ||||
|             name="Online", | ||||
|             device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||||
|             on_value="CONNECTED", | ||||
|             icon="mdi:wifi" | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="attributes.parameters.remoteCtrValid", | ||||
|             name="On", | ||||
|             device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||||
|             on_value="1", | ||||
|             icon="mdi:remote" | ||||
|         ), | ||||
|         HonBinarySensorEntityDescription( | ||||
|             key="attributes.parameters.onOffStatus", | ||||
|             name="On", | ||||
|             device_class=BinarySensorDeviceClass.RUNNING, | ||||
|             on_value="1", | ||||
|             icon="mdi:power-cycle" | ||||
|         ), | ||||
|     ), | ||||
| } | ||||
|  | ||||
|  | ||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||
|     hon: Hon = hass.data[DOMAIN][entry.unique_id] | ||||
|     coordinators = hass.data[DOMAIN]["coordinators"] | ||||
|     appliances = [] | ||||
|     for device in hon.appliances: | ||||
|         if device.mac_address in coordinators: | ||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] | ||||
|         else: | ||||
|             coordinator = HonCoordinator(hass, device) | ||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator | ||||
|         await coordinator.async_config_entry_first_refresh() | ||||
|  | ||||
|         if descriptions := BINARY_SENSORS.get(device.appliance_type): | ||||
|             for description in descriptions: | ||||
|                 if not device.get(description.key): | ||||
|                     _LOGGER.warning("[%s] Can't setup %s", device.appliance_type, description.key) | ||||
|                     continue | ||||
|                 appliances.extend([ | ||||
|                     HonBinarySensorEntity(hass, coordinator, entry, device, description)] | ||||
|                 ) | ||||
|  | ||||
|     async_add_entities(appliances) | ||||
|  | ||||
|  | ||||
| class HonBinarySensorEntity(HonEntity, BinarySensorEntity): | ||||
|     entity_description: HonBinarySensorEntityDescription | ||||
|  | ||||
|     def __init__(self, hass, coordinator, entry, device, description) -> None: | ||||
|         super().__init__(hass, entry, coordinator, device) | ||||
|  | ||||
|         self._coordinator = coordinator | ||||
|  | ||||
|         self.entity_description = description | ||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" | ||||
|  | ||||
|     @property | ||||
|     def is_on(self) -> bool: | ||||
|         return self._device.get(self.entity_description.key, "") == self.entity_description.on_value | ||||
|  | ||||
|     @callback | ||||
|     def _handle_coordinator_update(self): | ||||
|         self._attr_native_value = self._device.get(self.entity_description.key, "") == self.entity_description.on_value | ||||
|         self.async_write_ha_state() | ||||
| @ -1,12 +0,0 @@ | ||||
| { | ||||
|   "domain": "hon", | ||||
|   "name": "Haier hOn", | ||||
|   "codeowners": ["@Andre0512"], | ||||
|   "config_flow": true, | ||||
|   "documentation": "https://github.com/Andre0512/hon/", | ||||
|   "iot_class": "cloud_polling", | ||||
|   "issue_tracker": "https://github.com/Andre0512/hon/issues", | ||||
|   "requirements": ["pyhOn==0.6.1"], | ||||
|   "version": "0.5.0-beta.2" | ||||
| } | ||||
|  | ||||
| @ -1,167 +0,0 @@ | ||||
| from __future__ import annotations | ||||
|  | ||||
| from pyhon import Hon | ||||
| from pyhon.parameter import HonParameterRange | ||||
|  | ||||
| from homeassistant.components.number import ( | ||||
|     NumberEntity, | ||||
|     NumberEntityDescription, | ||||
| ) | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from homeassistant.const import UnitOfTime, UnitOfTemperature | ||||
| from homeassistant.core import callback | ||||
| from homeassistant.helpers.entity import EntityCategory | ||||
|  | ||||
| from .const import DOMAIN | ||||
| from .hon import HonEntity, HonCoordinator | ||||
|  | ||||
| NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = { | ||||
|     "WM": ( | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.delayTime", | ||||
|             name="Delay Time", | ||||
|             icon="mdi:timer-plus", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES | ||||
|         ), | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.rinseIterations", | ||||
|             name="Rinse Iterations", | ||||
|             icon="mdi:rotate-right", | ||||
|             entity_category=EntityCategory.CONFIG | ||||
|         ), | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.mainWashTime", | ||||
|             name="Main Wash Time", | ||||
|             icon="mdi:clock-start", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES | ||||
|         ), | ||||
|     ), | ||||
|     "TD": ( | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.delayTime", | ||||
|             name="Delay time", | ||||
|             icon="mdi:timer-plus", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES | ||||
|         ), | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.dryLevel", | ||||
|             name="Dry level", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             icon="mdi:hair-dryer", | ||||
|             translation_key="tumbledryerdrylevel" | ||||
|         ), | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.tempLevel", | ||||
|             name="Temperature level", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             icon="mdi:thermometer", | ||||
|             translation_key="tumbledryertemplevel" | ||||
|         ), | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.antiCreaseTime", | ||||
|             name="Anti-Crease time", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             icon="mdi:timer", | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES | ||||
|         ), | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.sterilizationStatus", | ||||
|             name="Sterilization status", | ||||
|             icon="mdi:clock-start", | ||||
|             entity_category=EntityCategory.CONFIG | ||||
|         ), | ||||
|     ), | ||||
|     "WD": ( | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.delayTime", | ||||
|             name="Delay Time", | ||||
|             icon="mdi:timer-plus", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES | ||||
|         ), | ||||
|     ), | ||||
|     "OV": ( | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.delayTime", | ||||
|             name="Delay time", | ||||
|             icon="mdi:timer-plus", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES | ||||
|         ), | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.tempSel", | ||||
|             name="Target Temperature", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             icon="mdi:thermometer", | ||||
|             native_unit_of_measurement=UnitOfTemperature.CELSIUS | ||||
|         ), | ||||
|  | ||||
|         NumberEntityDescription( | ||||
|             key="startProgram.prTime", | ||||
|             name="Program Duration", | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             icon="mdi:timelapse", | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES | ||||
|         ), | ||||
|     ), | ||||
| } | ||||
|  | ||||
|  | ||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||
|     hon: Hon = hass.data[DOMAIN][entry.unique_id] | ||||
|     coordinators = hass.data[DOMAIN]["coordinators"] | ||||
|     appliances = [] | ||||
|     for device in hon.appliances: | ||||
|         if device.mac_address in coordinators: | ||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] | ||||
|         else: | ||||
|             coordinator = HonCoordinator(hass, device) | ||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator | ||||
|         await coordinator.async_config_entry_first_refresh() | ||||
|  | ||||
|         if descriptions := NUMBERS.get(device.appliance_type): | ||||
|             for description in descriptions: | ||||
|                 if not device.settings.get(description.key): | ||||
|                     continue | ||||
|                 appliances.extend([ | ||||
|                     HonNumberEntity(hass, coordinator, entry, device, description)] | ||||
|                 ) | ||||
|  | ||||
|     async_add_entities(appliances) | ||||
|  | ||||
|  | ||||
| class HonNumberEntity(HonEntity, NumberEntity): | ||||
|     def __init__(self, hass, coordinator, entry, device, description) -> None: | ||||
|         super().__init__(hass, entry, coordinator, device) | ||||
|  | ||||
|         self._coordinator = coordinator | ||||
|         self._device = device | ||||
|         self._data = device.settings[description.key] | ||||
|         self.entity_description = description | ||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" | ||||
|  | ||||
|         if isinstance(self._data, HonParameterRange): | ||||
|             self._attr_native_max_value = self._data.max | ||||
|             self._attr_native_min_value = self._data.min | ||||
|             self._attr_native_step = self._data.step | ||||
|  | ||||
|     @property | ||||
|     def native_value(self) -> float | None: | ||||
|         return self._device.get(self.entity_description.key) | ||||
|  | ||||
|     async def async_set_native_value(self, value: float) -> None: | ||||
|         self._device.settings[self.entity_description.key].value = value | ||||
|         await self.coordinator.async_request_refresh() | ||||
|  | ||||
|     @callback | ||||
|     def _handle_coordinator_update(self): | ||||
|         setting = self._device.settings[self.entity_description.key] | ||||
|         if isinstance(setting, HonParameterRange): | ||||
|             self._attr_native_max_value = setting.max | ||||
|             self._attr_native_min_value = setting.min | ||||
|             self._attr_native_step = setting.step | ||||
|         self._attr_native_value = setting.value | ||||
|         self.async_write_ha_state() | ||||
| @ -1,273 +0,0 @@ | ||||
| import logging | ||||
|  | ||||
| from pyhon import Hon | ||||
|  | ||||
| from homeassistant.components.sensor import ( | ||||
|     SensorEntity, | ||||
|     SensorDeviceClass, | ||||
|     SensorStateClass, | ||||
|     SensorEntityDescription, | ||||
| ) | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from homeassistant.const import ( | ||||
|     REVOLUTIONS_PER_MINUTE, | ||||
|     UnitOfEnergy, | ||||
|     UnitOfVolume, | ||||
|     UnitOfMass, | ||||
|     UnitOfPower, | ||||
|     UnitOfTime, | ||||
|     UnitOfTemperature | ||||
| ) | ||||
| from homeassistant.core import callback | ||||
| from homeassistant.helpers.entity import EntityCategory | ||||
| from homeassistant.helpers.typing import StateType | ||||
|  | ||||
| from .const import DOMAIN | ||||
| from .hon import HonCoordinator, HonEntity | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { | ||||
|     "WM": ( | ||||
|         SensorEntityDescription( | ||||
|             key="totalElectricityUsed", | ||||
|             name="Total Power", | ||||
|             device_class=SensorDeviceClass.ENERGY, | ||||
|             state_class=SensorStateClass.TOTAL_INCREASING, | ||||
|             native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="totalWaterUsed", | ||||
|             name="Total Water", | ||||
|             device_class=SensorDeviceClass.WATER, | ||||
|             state_class=SensorStateClass.TOTAL_INCREASING, | ||||
|             native_unit_of_measurement=UnitOfVolume.LITERS | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="totalWashCycle", | ||||
|             name="Total Wash Cycle", | ||||
|             state_class=SensorStateClass.TOTAL_INCREASING, | ||||
|             icon="mdi:counter" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="currentElectricityUsed", | ||||
|             name="Current Electricity Used", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             device_class=SensorDeviceClass.POWER, | ||||
|             native_unit_of_measurement=UnitOfPower.KILO_WATT, | ||||
|             icon="mdi:lightning-bolt" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="currentWaterUsed", | ||||
|             name="Current Water Used", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             icon="mdi:water" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="startProgram.weight", | ||||
|             name="Suggested weight", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             entity_category=EntityCategory.CONFIG, | ||||
|             native_unit_of_measurement=UnitOfMass.KILOGRAMS, | ||||
|             icon="mdi:weight-kilogram" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="machMode", | ||||
|             name="Machine Status", | ||||
|             icon="mdi:information", | ||||
|             translation_key="mode" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="errors", | ||||
|             name="Error", | ||||
|             icon="mdi:math-log", | ||||
|             translation_key="errors" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="remainingTimeMM", | ||||
|             name="Remaining Time", | ||||
|             icon="mdi:timer", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="spinSpeed", | ||||
|             name="Spin Speed", | ||||
|             icon="mdi:speedometer", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||
|         ), | ||||
|     ), | ||||
|     "TD": ( | ||||
|         SensorEntityDescription( | ||||
|             key="machMode", | ||||
|             name="Machine Status", | ||||
|             icon="mdi:information", | ||||
|             translation_key="mode" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="errors", | ||||
|             name="Error", | ||||
|             icon="mdi:math-log", | ||||
|             translation_key="errors" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="remainingTimeMM", | ||||
|             name="Remaining Time", | ||||
|             icon="mdi:timer", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="delayTime", | ||||
|             name="Start Time", | ||||
|             icon="mdi:clock-start", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="prCode", | ||||
|             name="Program", | ||||
|             icon="mdi:tumble-dryer", | ||||
|             translation_key="tumbledryerprogram" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="prPhase", | ||||
|             name="Program Phase", | ||||
|             icon="mdi:tumble-dryer", | ||||
|             translation_key="tumbledryerprogramphase" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="dryLevel", | ||||
|             name="Dry level", | ||||
|             icon="mdi:hair-dryer", | ||||
|             translation_key="tumbledryerdrylevel" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="tempLevel", | ||||
|             name="Temperature level", | ||||
|             icon="mdi:thermometer", | ||||
|             translation_key="tumbledryertemplevel" | ||||
|         ), | ||||
|     ), | ||||
|     "WD": ( | ||||
|         SensorEntityDescription( | ||||
|             key="machMode", | ||||
|             name="Machine Status", | ||||
|             icon="mdi:information", | ||||
|             translation_key="mode" | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="spinSpeed", | ||||
|             name="Spin Speed", | ||||
|             icon="mdi:fast-forward-outline", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             native_unit_of_measurement=REVOLUTIONS_PER_MINUTE, | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="remainingTimeMM", | ||||
|             name="Remaining Time", | ||||
|             icon="mdi:timer", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="prCode", | ||||
|             name="Current Program", | ||||
|             icon="mdi:tumble-dryer", | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="prPhase", | ||||
|             name="Program Phase", | ||||
|             icon="mdi:tumble-dryer", | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="dryLevel", | ||||
|             name="Dry level", | ||||
|             icon="mdi:hair-dryer", | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="dirtyLevel", | ||||
|             name="Dirt level", | ||||
|             icon="mdi:liquid-spot", | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="steamLevel", | ||||
|             name="Steam level", | ||||
|             icon="mdi:smoke", | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="temp", | ||||
|             name="Current Temperature", | ||||
|             icon="mdi:thermometer", | ||||
|             state_class=SensorStateClass.MEASUREMENT, | ||||
|             native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||||
|         ), | ||||
|     ), | ||||
|     "OV": ( | ||||
|         SensorEntityDescription( | ||||
|             key="remainingTimeMM", | ||||
|             name="Remaining Time", | ||||
|             icon="mdi:timer", | ||||
|             native_unit_of_measurement=UnitOfTime.MINUTES, | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="delayTime", | ||||
|             name="Start Time", | ||||
|             icon="mdi:clock-start", | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="temp", | ||||
|             name="Temperature", | ||||
|             icon="mdi:thermometer", | ||||
|         ), | ||||
|         SensorEntityDescription( | ||||
|             key="tempSel", | ||||
|             name="Temperature Selected", | ||||
|             icon="mdi:thermometer", | ||||
|         ), | ||||
|     ), | ||||
| } | ||||
|  | ||||
|  | ||||
| async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None: | ||||
|     hon: Hon = hass.data[DOMAIN][entry.unique_id] | ||||
|     coordinators = hass.data[DOMAIN]["coordinators"] | ||||
|     appliances = [] | ||||
|     for device in hon.appliances: | ||||
|         if device.mac_address in coordinators: | ||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.mac_address] | ||||
|         else: | ||||
|             coordinator = HonCoordinator(hass, device) | ||||
|             hass.data[DOMAIN]["coordinators"][device.mac_address] = coordinator | ||||
|         await coordinator.async_config_entry_first_refresh() | ||||
|  | ||||
|         if descriptions := SENSORS.get(device.appliance_type): | ||||
|             for description in descriptions: | ||||
|                 if not device.get(description.key): | ||||
|                     _LOGGER.warning("[%s] Can't setup %s", device.appliance_type, description.key) | ||||
|                     continue | ||||
|                 appliances.extend([ | ||||
|                     HonSensorEntity(hass, coordinator, entry, device, description)] | ||||
|                 ) | ||||
|  | ||||
|     async_add_entities(appliances) | ||||
|  | ||||
|  | ||||
| class HonSensorEntity(HonEntity, SensorEntity): | ||||
|     def __init__(self, hass, coordinator, entry, device, description) -> None: | ||||
|         super().__init__(hass, entry, coordinator, device) | ||||
|  | ||||
|         self._coordinator = coordinator | ||||
|  | ||||
|         self.entity_description = description | ||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" | ||||
|  | ||||
|     @property | ||||
|     def native_value(self) -> StateType: | ||||
|         return self._device.get(self.entity_description.key, "") | ||||
|  | ||||
|     @callback | ||||
|     def _handle_coordinator_update(self): | ||||
|         self._attr_native_value = self._device.get(self.entity_description.key, "") | ||||
|         self.async_write_ha_state() | ||||
| @ -1,410 +0,0 @@ | ||||
| { | ||||
|   "config": { | ||||
|     "step": { | ||||
|       "user": { | ||||
|         "description": "Моля, въведете вашите данни за достъп до hOn", | ||||
|         "data": { | ||||
|           "email": "Email Адрес", | ||||
|           "password": "Парола" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "entity": { | ||||
|     "sensor": { | ||||
|       "mode": { | ||||
|         "state": { | ||||
|           "0": "Изключен", | ||||
|           "1": "Готов", | ||||
|           "2": "Работи", | ||||
|           "3": "На пауза", | ||||
|           "5": "Scheduled", | ||||
|           "6": "Грешка", | ||||
|           "7": "Завършен" | ||||
|         } | ||||
|       }, | ||||
|       "errors": { | ||||
|         "state": { | ||||
|           "00": "Няма грешки", | ||||
|           "100000000000": "E2: Провери дали вратата е затворена", | ||||
|           "8000000000000": "E4: Провери подаването на вода" | ||||
|         } | ||||
|       }, | ||||
|       "tumbledryerprogram": { | ||||
|         "state": { | ||||
|           "0": "Стандартна", | ||||
|           "62": "Памук", | ||||
|           "63": "Синтетика", | ||||
|           "64": "Смесен тип", | ||||
|           "66": "Чаршафи", | ||||
|           "71": "Пердета", | ||||
|           "72": "Спорт", | ||||
|           "74": "i-time", | ||||
|           "75": "Олекотени завивки", | ||||
|           "76": "Вълна", | ||||
|           "78": "i-Refresh", | ||||
|           "83": "Хавлиена кърпа", | ||||
|           "85": "Бързо Сушене", | ||||
|           "92": "Деликатно пране", | ||||
|           "103": "Отдалечен" | ||||
|         } | ||||
|       }, | ||||
|       "tumbledryerprogramphase": { | ||||
|         "state": { | ||||
|           "0": "Изчаване", | ||||
|           "2": "Сушене", | ||||
|           "3": "Охлажане", | ||||
|           "11": "11" | ||||
|         } | ||||
|       }, | ||||
|       "tumbledryertemplevel": { | ||||
|         "state": { | ||||
|           "1": "Хладен въздух", | ||||
|           "2": "Ниска температура L-1", | ||||
|           "3": "Средна температура L-2", | ||||
|           "4": "Висока температура L-3" | ||||
|         } | ||||
|       }, | ||||
|       "tumbledryerdrylevel": { | ||||
|         "state": { | ||||
|           "3": "Готови за съхранение", | ||||
|           "12": "Готови за гладене H-1", | ||||
|           "13": "Готови за съхранение H-2", | ||||
|           "14": "Екстра сухо H-3" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "select": { | ||||
|       "programs": { | ||||
|         "state": { | ||||
|           "20_degrees_coloured_cottons": "20° Colored and Cottons", | ||||
|           "20_degrees_new_energy_label": "20°C", | ||||
|           "active_steam": "Steam", | ||||
|           "active_wash": "Active Wash", | ||||
|           "active_wash_steam": "Active Wash + Steam", | ||||
|           "allergy_care": "Allergy Care", | ||||
|           "allergy_care_pro": "Allergy Care Pro", | ||||
|           "all_in_one_49": "All in One 49'", | ||||
|           "all_in_one_59": "All in One 59'", | ||||
|           "all_in_one_59_steam": "Active Wash + Steam", | ||||
|           "autocare": "Autocare", | ||||
|           "autoclean": "Drum Cleaning", | ||||
|           "baby_60": "All Baby 60°C", | ||||
|           "care_14": "Rapid Care 14'", | ||||
|           "care_30": "Rapid Care 30'", | ||||
|           "care_44": "Rapid Care 44'", | ||||
|           "checkup": "Check-Up", | ||||
|           "colour_59": "Colored 59'", | ||||
|           "colour_59_steam": "Colored 59' + Steam", | ||||
|           "cottons": "Cotton", | ||||
|           "cottons_prewash": "Cottons + Prewash", | ||||
|           "cottons_steam": "Cotton + Steam", | ||||
|           "cotton_care_59": "Cotton Care 59'", | ||||
|           "delicate_59": "Delicate 59'", | ||||
|           "delicate_silk": "Delicate and Silk", | ||||
|           "delicate_silk_steam": "Delicate and Silk + Steam", | ||||
|           "delicati_59": "Delicate 59'", | ||||
|           "delicati_59_steam": "Delicate 59' + Steam", | ||||
|           "drain_spin": "Drain + Spin", | ||||
|           "easy_iron": "Easy Iron", | ||||
|           "eco_40_60_new_energy_label": "Eco 40-60", | ||||
|           "extra_care": "Extra Care", | ||||
|           "fitness": "Fitness Care", | ||||
|           "fitness_care": "Fitness Care", | ||||
|           "fresh_care": "Fresh Care", | ||||
|           "fresh_care_steam": "Fresh Care + Steam", | ||||
|           "handwash_wool": "Hand Wash + Wool", | ||||
|           "high_dry": "High Heat Dry", | ||||
|           "hqd_20_degrees": "Cotton 20℃", | ||||
|           "hqd_allergy": "Allergy Care", | ||||
|           "hqd_autoclean": "Автоматично почистване", | ||||
|           "hqd_babycare": "Бебе", | ||||
|           "hqd_baby_care": "Бебе", | ||||
|           "hqd_bath_towel": "Хавлиени кърпи", | ||||
|           "hqd_bed_sheets": "Чаршафи", | ||||
|           "hqd_checkup": "Check-Up", | ||||
|           "hqd_bulky": "Обемисти", | ||||
|           "hqd_casual": "Ежедневни", | ||||
|           "hqd_cold_wind_30": "Студен бриз 30 мин", | ||||
|           "hqd_cold_wind_timing": "Студен бриз за време", | ||||
|           "hqd_cotton": "Памук", | ||||
|           "hqd_cottons": "Памук", | ||||
|           "hqd_curtain": "Пердета", | ||||
|           "hqd_delicate": "Деликатни", | ||||
|           "hqd_delicate_cradle": "Деликатни", | ||||
|           "hqd_diaper": "Бебешки пелени", | ||||
|           "hqd_dry": "Cotton Dry", | ||||
|           "hqd_dry_synthetics": "Low Heat Dry", | ||||
|           "hqd_duvet": "Олекотени завивки", | ||||
|           "hqd_eco_40_60_degrees": "Eco 40-60", | ||||
|           "hqd_feather": "Пълнеж от пера(пух)", | ||||
|           "hqd_handwash_wool": "Wool", | ||||
|           "hqd_hot_wind_timing": "Горещ въздух за време", | ||||
|           "hqd_hygienic": "Здравословна", | ||||
|           "hqd_i_refresh": "i-Refresh", | ||||
|           "hqd_i_refresh_pro": "i-Refresh Pro", | ||||
|           "hqd_jacket": "Якета", | ||||
|           "hqd_jeans": "Дънки", | ||||
|           "hqd_luxury": "Луксозно", | ||||
|           "hqd_mix": "Смесен тип", | ||||
|           "hqd_night_dry": "Сушене през ноща", | ||||
|           "hqd_outdoor": "Дрехи за открито", | ||||
|           "hqd_precious_cure": "Precious cure", | ||||
|           "hqd_quick_15": "Бързо 15 мин", | ||||
|           "hqd_quick_20": "Бързо 20 мин", | ||||
|           "hqd_quick_30": "Бързо 30 мин", | ||||
|           "hqd_quick_dry": "Бързо", | ||||
|           "hqd_quick_wash_57": "Quick Wash 57'", | ||||
|           "hqd_quilt": "Юргани", | ||||
|           "hqd_rapid_wash_and_dry": "Wash and dry", | ||||
|           "hqd_refresh": "Освежаване", | ||||
|           "hqd_rinse": "Rinses", | ||||
|           "hqd_school_uniform": "Ученически униформи", | ||||
|           "hqd_shirt": "Ризи", | ||||
|           "hqd_shirts": "Ризи", | ||||
|           "hqd_shoes": "Обувки", | ||||
|           "hqd_silk": "Коприна", | ||||
|           "hqd_smart": "Smart A.I.", | ||||
|           "hqd_spin": "Spin", | ||||
|           "hqd_sport": "Спорт", | ||||
|           "hqd_sports": "Спорт", | ||||
|           "hqd_synthetics": "Синтетика", | ||||
|           "hqd_super_fast": "Супер бързо 39 мин", | ||||
|           "hqd_synthetic_and_coloured": "Synthetics", | ||||
|           "hqd_timer": "Таймер", | ||||
|           "hqd_towel": "Хавлиени кърпи", | ||||
|           "hqd_underwear": "Бельо", | ||||
|           "hqd_warm_up": "Затопляне", | ||||
|           "hqd_wool": "Вълна", | ||||
|           "hqd_working_suit": "Работно облекло", | ||||
|           "hygiene_59": "Hygiene Plus 59'", | ||||
|           "hygiene_60": "Hygiene 60°C", | ||||
|           "hygiene_plus_59": "Hygiene Plus 59'", | ||||
|           "hygiene_plus_59_min": "Hygiene Plus 59'", | ||||
|           "hygiene_pro_4_min": "Hygiene Pro 49'", | ||||
|           "hygiene_pro_49_min": "Hygiene Pro 49'", | ||||
|           "hygiene_pro_steam": "Hygiene Pro + Steam", | ||||
|           "intensive_40": "Intensive 40°C", | ||||
|           "intensive_40_steam": "Intensive 40°C + Steam", | ||||
|           "iot_checkup": "Check-Up", | ||||
|           "iot_dry_air_refresh": "Air Refresh", | ||||
|           "iot_dry_anti_mites": "Anti-mite", | ||||
|           "iot_dry_baby": "Бебе", | ||||
|           "iot_dry_backpacks": "Раници", | ||||
|           "iot_dry_bathrobe": "Халати за баня", | ||||
|           "iot_dry_bed_linen": "Спално бельо", | ||||
|           "iot_dry_cotton": "Памук", | ||||
|           "iot_dry_cotton_dry": "Памук", | ||||
|           "iot_dry_cuddly_toys": "Плюшени играчки", | ||||
|           "iot_dry_curtains": "Пердета", | ||||
|           "iot_dry_dehumidifier": "Humidity Remover", | ||||
|           "iot_dry_delicates": "Деликатни", | ||||
|           "iot_dry_delicates_antiallergy": "Delicates  Anti-allergy", | ||||
|           "iot_dry_delicate_tablecloths": "Delicate Tablecloths", | ||||
|           "iot_dry_denim_jeans": "Дънки", | ||||
|           "iot_dry_down_jacket": "Пухени якета", | ||||
|           "iot_dry_duvet": "Олекотени завивки", | ||||
|           "iot_dry_easy_iron_cotton": "Easy Iron - Cotton", | ||||
|           "iot_dry_easy_iron_synthetics": "Easy Iron - Synthetics", | ||||
|           "iot_dry_gym_fit": "Фитнес", | ||||
|           "iot_dry_lingerie": "Деликано бельо", | ||||
|           "iot_dry_mixed": "Смесен тип", | ||||
|           "iot_dry_mixed_dry": "Смесен тип", | ||||
|           "iot_dry_rapid_30": "Бързо 30 мин", | ||||
|           "iot_dry_rapid_59": "Бързо 59 мин", | ||||
|           "iot_dry_rapid_60_min_delicates": "Rapid 60' - Delicates", | ||||
|           "iot_dry_shirts": "Ризи", | ||||
|           "iot_dry_swimsuits_and_bikinis": "Бански", | ||||
|           "iot_dry_synthetics": "Синтетика", | ||||
|           "iot_dry_synthetic_dry": "Synthetic Dry", | ||||
|           "iot_dry_tablecloths": "Покривки", | ||||
|           "iot_dry_technical_fabrics": "Технически тъкани", | ||||
|           "iot_dry_warm_embrace": "Warm Embrace", | ||||
|           "iot_dry_wool": "Вълна", | ||||
|           "iot_dry_wool_dry": "Вълна", | ||||
|           "iot_wash_and_dry": "Wash and dry", | ||||
|           "iot_wash_anti_mites": "Anti-mites", | ||||
|           "iot_wash_anti_odor": "Anti-odour", | ||||
|           "iot_wash_ariel_clean_cycle": "Ariel Ultimate Clean", | ||||
|           "iot_wash_ariel_cold_cycle": "Ariel Cold Clean", | ||||
|           "iot_wash_ariel_fresh_cycle": "Ariel Fresh Clean", | ||||
|           "iot_wash_baby_sanitizer": "Sanitizer", | ||||
|           "iot_wash_baby_sanitizer_steam": "Sanitiser + Steam", | ||||
|           "iot_wash_backpacks": "Backpacks", | ||||
|           "iot_wash_backpacks_zelig": "Backpacks", | ||||
|           "iot_wash_bathrobe": "Bathrobes and Towels", | ||||
|           "iot_wash_bathrobe_steam": "Bathrobe and Towels + Steam", | ||||
|           "iot_wash_bed_linen": "Bed Linen", | ||||
|           "iot_wash_bed_linen_steam": "Bed Linen + Steam", | ||||
|           "iot_wash_bed_linen_zelig": "Bed Linens", | ||||
|           "iot_wash_big_single_load": "Big single load", | ||||
|           "iot_wash_bleaching": "Bleaching", | ||||
|           "iot_wash_blood_stains": "Bloodstains", | ||||
|           "iot_wash_cashmere": "Cashmere", | ||||
|           "iot_wash_chocolate_stains": "Chocolate stains", | ||||
|           "iot_wash_cold_wash": "Cold Wash", | ||||
|           "iot_wash_colored": "Colored", | ||||
|           "iot_wash_colored_anti_stain": "Colored Anti-stain", | ||||
|           "iot_wash_colored_delicate": "Colored Delicate", | ||||
|           "iot_wash_coloured": "Colored", | ||||
|           "iot_wash_coloured_bed_linen": "Colored Bed Linen", | ||||
|           "iot_wash_coloured_bed_linen_steam": "Coloured Bed Linen + Steam", | ||||
|           "iot_wash_coloured_curtains": "Colored Curtains", | ||||
|           "iot_wash_coloured_shirts": "Colored Shirts", | ||||
|           "iot_wash_coloured_shirts_steam": "Colored Shirts + Steam", | ||||
|           "iot_wash_coloured_steam": "Colored + Steam", | ||||
|           "iot_wash_coloured_tableclothes": "Colored Tableclothes", | ||||
|           "iot_wash_coloured_tableclothes_steam": "Coloured Tablecloths + Steam", | ||||
|           "iot_wash_cotton": "Cotton", | ||||
|           "iot_wash_cotton_steam": "Cotton + Steam", | ||||
|           "iot_wash_cuddly_toys": "Cuddly Toys", | ||||
|           "iot_wash_curtains": "Curtains", | ||||
|           "iot_wash_curtains_steam": "Curtains + Steam", | ||||
|           "iot_wash_curtains_zelig": "Curtains", | ||||
|           "iot_wash_dark": "Darks", | ||||
|           "iot_wash_darks_and_coloured_44": "Darks and Colored 44'", | ||||
|           "iot_wash_darks_and_coloured_59": "Darks and Colored 59'", | ||||
|           "iot_wash_darks_and_coloured_xl": "Darks and Colored XL", | ||||
|           "iot_wash_dark_steam": "Darks + Steam", | ||||
|           "iot_wash_dash_clean_cycle": "Dash Ultimate Clean", | ||||
|           "iot_wash_dash_cold_cycle": "Dash Cold Clean", | ||||
|           "iot_wash_dash_fresh_cycle": "Dash Fresh Clean", | ||||
|           "iot_wash_delicate": "Delicates", | ||||
|           "iot_wash_delicate_antiallergy": "Delicate Anti-Allergy", | ||||
|           "iot_wash_delicate_antiallergy_steam": "Delicate Anti-Allergy + Steam", | ||||
|           "iot_wash_delicate_antiallergy_zelig": "Delicate Anti-Allergy", | ||||
|           "iot_wash_delicate_colors": "Delicate Colors", | ||||
|           "iot_wash_delicate_colors_steam": "Delicate Colors + Steam", | ||||
|           "iot_wash_delicate_dark": "Delicate Darks", | ||||
|           "iot_wash_delicate_steam": "Delicates + Steam", | ||||
|           "iot_wash_delicate_tablecloths": "Delicate Tablecloths", | ||||
|           "iot_wash_delicate_tablecloths_steam": "Delicate Tablecloths + Steam", | ||||
|           "iot_wash_delicate_whites": "Delicate Whites", | ||||
|           "iot_wash_denim_jeans": "Denim - Jeans", | ||||
|           "iot_wash_diving_suits": "Diving Suits", | ||||
|           "iot_wash_diving_suits_zelig": "Diving Suits", | ||||
|           "iot_wash_down_jackets": "Down Jackets", | ||||
|           "iot_wash_down_jackets_zelig": "Down Jackets", | ||||
|           "iot_wash_duvet": "Duvet", | ||||
|           "iot_wash_fruit_stains": "Fruit stains", | ||||
|           "iot_wash_gym_fit": "Gym Fit - Fitness", | ||||
|           "iot_wash_handwash": "Handwash", | ||||
|           "iot_wash_handwash_colored": "Handwash Colored", | ||||
|           "iot_wash_handwash_dark": "Handwash Darks", | ||||
|           "iot_wash_lingerie": "Lingerie", | ||||
|           "iot_wash_masks_refresh": "Masks Refresh", | ||||
|           "iot_wash_masks_sanification": "Masks Sanitization", | ||||
|           "iot_wash_masks_sanification_steam": "Mask Sanitisation + Steam", | ||||
|           "iot_wash_mats": "Mats", | ||||
|           "iot_wash_men_s_trousers": "Trousers", | ||||
|           "iot_wash_mixed": "Mixed", | ||||
|           "iot_wash_mixed_steam": "Mixed + Steam", | ||||
|           "iot_wash_mix_and_coloured_44": "Mix and Colored 44'", | ||||
|           "iot_wash_mix_and_coloured_59": "Mix and Colored 59'", | ||||
|           "iot_wash_mix_and_coloured_xl": "Mix and colored XL", | ||||
|           "iot_wash_new_clothes": "New Clothes", | ||||
|           "iot_wash_perfect_white": "Perfect White", | ||||
|           "iot_wash_perfect_white_steam": "Perfect White + Steam", | ||||
|           "iot_wash_pets": "Pet Accessories", | ||||
|           "iot_wash_pets_hair_removal": "Pets Hair Removal", | ||||
|           "iot_wash_pets_odours_stains_removal": "Pets Odours and Stains Removal", | ||||
|           "iot_wash_pets_steam": "Pet Accessories + Steam", | ||||
|           "iot_wash_playsuits": "Playsuits", | ||||
|           "iot_wash_playsuits_steam": "Playsuits + Steam", | ||||
|           "iot_wash_quick_drum_cleaner": "Quick drum cleaner", | ||||
|           "iot_wash_rapid_14": "Rapid 14’", | ||||
|           "iot_wash_rapid_30": "Rapid 30’", | ||||
|           "iot_wash_rapid_44": "Rapid 44'", | ||||
|           "iot_wash_rapid_59": "Rapid 59'", | ||||
|           "iot_wash_rapid_59_steam": "Rapid 59' + Steam", | ||||
|           "iot_wash_refresh_14_min": "Refresh 14'", | ||||
|           "iot_wash_resistant_colored": "Resistant Colored", | ||||
|           "iot_wash_resistant_dark": "Resistant Darks", | ||||
|           "iot_wash_resistant_whites": "Resistant Whites", | ||||
|           "iot_wash_rinse": "Rinses", | ||||
|           "iot_wash_shirts": "Shirts", | ||||
|           "iot_wash_shirts_steam": "Shirts + Steam", | ||||
|           "iot_wash_silk": "Silk", | ||||
|           "iot_wash_ski_suit": "Ski Suit", | ||||
|           "iot_wash_ski_suit_zelig": "Ski Suit", | ||||
|           "iot_wash_spin": "Spin", | ||||
|           "iot_wash_sport": "Sport", | ||||
|           "iot_wash_sport_anti_odor": "Anti-odour Sportswear", | ||||
|           "iot_wash_sport_anti_odor_zelig": "Anti-odour Sportswear", | ||||
|           "iot_wash_stains_remover": "Stain Remover", | ||||
|           "iot_wash_swimsuits_and_bikinis": "Swimsuits and Bikinis", | ||||
|           "iot_wash_synthetic": "Synthetics", | ||||
|           "iot_wash_synthetic_steam": "Synthetics + Steam", | ||||
|           "iot_wash_tablecloths": "Tablecloths", | ||||
|           "iot_wash_tablecloths_steam": "Tablecloths + Steam", | ||||
|           "iot_wash_technical_fabrics": "Technical Fabrics", | ||||
|           "iot_wash_technical_fabrics_zelig": "Technical Fabrics", | ||||
|           "iot_wash_technical_jackets": "Technical Jackets", | ||||
|           "iot_wash_technical_jackets_zelig": "Technical Jackets", | ||||
|           "iot_wash_trainers": "Trainers", | ||||
|           "iot_wash_whites": "Whites", | ||||
|           "iot_wash_whites_44": "Whites 44'", | ||||
|           "iot_wash_whites_59": "Whites 59'", | ||||
|           "iot_wash_whites_xl": "Whites XL", | ||||
|           "iot_wash_wine_stains": "Wine Stains", | ||||
|           "iot_wash_wool": "Wool", | ||||
|           "jeans": "Jeans", | ||||
|           "jeans_60": "Jeans", | ||||
|           "low_dry": "Low Heat Dry", | ||||
|           "mixed": "Mixed", | ||||
|           "mixed_and_colored_59": "Mixed and Colored 59'", | ||||
|           "mixed_steam": "Mixed + Steam", | ||||
|           "mix_and_colour_59": "Mixed and Colored 59'", | ||||
|           "mix_and_colour_59_steam": "Mixed and Coloured 59' + Steam", | ||||
|           "night_and_day": "Night and Day", | ||||
|           "night_wash": "Night Wash", | ||||
|           "perfect_59": "Perfect 59'", | ||||
|           "perfect_cotton_59": "Perfect Cotton 59'", | ||||
|           "perfect_cotton_59_steam": "Perfect Cotton 59' + Steam", | ||||
|           "perfect_whites_59": "Perfect White 59'", | ||||
|           "rapid_14_min": "Rapid 14'", | ||||
|           "rapid_30_min": "Rapid 30'", | ||||
|           "rapid_44_min": "Rapid 44'", | ||||
|           "rapid_a_class_60": "Rapid 59' A Class", | ||||
|           "rapid_a_class_60_steam": "Rapid 59' A Class + Steam", | ||||
|           "rapid_wash_and_dry_59_min": "Wash and Dry 59'", | ||||
|           "resistant_cotton": "Resistant Cotton", | ||||
|           "resistant_cotton_steam": "Resistant Cotton + Steam", | ||||
|           "rinse": "Rinse", | ||||
|           "shirts_steam": "Shirts + Steam", | ||||
|           "silent_night": "Silent Night", | ||||
|           "single_item": "Single Item", | ||||
|           "single_item_steam": "Single Item + Steam", | ||||
|           "smart_wash": "Smart Wash", | ||||
|           "soft_care": "Soft Care", | ||||
|           "soft_care_steam": "Soft Care + Steam", | ||||
|           "soft_care_steam_title": "Soft Care + Steam", | ||||
|           "special_39": "Special 39'", | ||||
|           "special_39_full_load": "Special 39'", | ||||
|           "special_39_full_load_steam": "Special 39' + Steam", | ||||
|           "special_49": "Special 49'", | ||||
|           "sport_39": "Sport 39'", | ||||
|           "sport_plus_29": "Sport Plus 29'", | ||||
|           "sport_plus_39": "Sport Plus 39'", | ||||
|           "steam_39": "Steam 39'", | ||||
|           "steam_care_pro": "Steam Care Pro", | ||||
|           "steam_care_pro_cotton": "Steam Care Pro - Cottons", | ||||
|           "steam_care_pro_delicates": "Steam Care Pro - Delicates", | ||||
|           "steam_care_pro_synthetic": "Steam Care Pro - Synthetics", | ||||
|           "steam_hygiene_plus": "Hygiene Plus + Steam", | ||||
|           "synthetics": "Synthetics", | ||||
|           "synthetic_and_coloured": "Synthetic and Colored", | ||||
|           "synthetic_and_coloured_steam": "Synthetic and Coloured + Steam", | ||||
|           "tailored_resistant_cotton": "Tailored Resistant Cotton", | ||||
|           "tailored_synthetic_and_coloured": "Tailored Synthetic Colored", | ||||
|           "total_care": "Total Care", | ||||
|           "tumbling": "Tumbling", | ||||
|           "wool": "Wool", | ||||
|           "wool_and_delicates_49": "Wool and Delicates 49'", | ||||
|           "wool_dry": "Wool Dry", | ||||
|           "wool_soft_care": "Wool and Soft Car" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -1,410 +0,0 @@ | ||||
| { | ||||
|   "config": { | ||||
|     "step": { | ||||
|       "user": { | ||||
|         "description": "Please enters your hOn credentials", | ||||
|         "data": { | ||||
|           "email": "Email Address", | ||||
|           "password": "Password" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "entity": { | ||||
|     "sensor": { | ||||
|       "mode": { | ||||
|         "state": { | ||||
|           "0": "Disconnected", | ||||
|           "1": "Ready", | ||||
|           "2": "Running", | ||||
|           "3": "Paused", | ||||
|           "5": "Scheduled", | ||||
|           "6": "Error", | ||||
|           "7": "Finished" | ||||
|         } | ||||
|       }, | ||||
|       "errors": { | ||||
|         "state": { | ||||
|           "00": "No error", | ||||
|           "100000000000": "E2: Check if the door is closed", | ||||
|           "8000000000000": "E4: Check the water supply" | ||||
|         } | ||||
|       }, | ||||
|       "tumbledryerprogram": { | ||||
|         "state": { | ||||
|           "0": "Default", | ||||
|           "62": "Cotton", | ||||
|           "63": "Synthetics", | ||||
|           "64": "Mix", | ||||
|           "66": "Bed Sheets", | ||||
|           "71": "Curtains", | ||||
|           "72": "Sports", | ||||
|           "74": "i-time", | ||||
|           "75": "Duvet", | ||||
|           "76": "Wool", | ||||
|           "78": "i-Refresh", | ||||
|           "83": "Towel", | ||||
|           "85": "Quick Dry", | ||||
|           "92": "Delicate", | ||||
|           "103": "Remote" | ||||
|         } | ||||
|       }, | ||||
|       "tumbledryerprogramphase": { | ||||
|         "state": { | ||||
|           "0": "Waiting", | ||||
|           "2": "Drying", | ||||
|           "3": "Cooldown", | ||||
|           "11": "11" | ||||
|         } | ||||
|       }, | ||||
|       "tumbledryertemplevel": { | ||||
|         "state": { | ||||
|           "1": "Cool", | ||||
|           "2": "Low temperature L-1", | ||||
|           "3": "Middle temperature L-2", | ||||
|           "4": "High temperature L-3" | ||||
|         } | ||||
|       }, | ||||
|       "tumbledryerdrylevel": { | ||||
|         "state": { | ||||
|           "3": "Cupboard dry", | ||||
|           "12": "Ready to Iron H-1", | ||||
|           "13": "Ready to Store H-2", | ||||
|           "14": "Extra Dry H-3" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "select": { | ||||
|       "programs": { | ||||
|         "state": { | ||||
|           "20_degrees_coloured_cottons": "20° Colored and Cottons", | ||||
|           "20_degrees_new_energy_label": "20°C", | ||||
|           "active_steam": "Steam", | ||||
|           "active_wash": "Active Wash", | ||||
|           "active_wash_steam": "Active Wash + Steam", | ||||
|           "allergy_care": "Allergy Care", | ||||
|           "allergy_care_pro": "Allergy Care Pro", | ||||
|           "all_in_one_49": "All in One 49'", | ||||
|           "all_in_one_59": "All in One 59'", | ||||
|           "all_in_one_59_steam": "Active Wash + Steam", | ||||
|           "autocare": "Autocare", | ||||
|           "autoclean": "Drum Cleaning", | ||||
|           "baby_60": "All Baby 60°C", | ||||
|           "care_14": "Rapid Care 14'", | ||||
|           "care_30": "Rapid Care 30'", | ||||
|           "care_44": "Rapid Care 44'", | ||||
|           "checkup": "Check-Up", | ||||
|           "colour_59": "Colored 59'", | ||||
|           "colour_59_steam": "Colored 59' + Steam", | ||||
|           "cottons": "Cotton", | ||||
|           "cottons_prewash": "Cottons + Prewash", | ||||
|           "cottons_steam": "Cotton + Steam", | ||||
|           "cotton_care_59": "Cotton Care 59'", | ||||
|           "delicate_59": "Delicate 59'", | ||||
|           "delicate_silk": "Delicate and Silk", | ||||
|           "delicate_silk_steam": "Delicate and Silk + Steam", | ||||
|           "delicati_59": "Delicate 59'", | ||||
|           "delicati_59_steam": "Delicate 59' + Steam", | ||||
|           "drain_spin": "Drain + Spin", | ||||
|           "easy_iron": "Easy Iron", | ||||
|           "eco_40_60_new_energy_label": "Eco 40-60", | ||||
|           "extra_care": "Extra Care", | ||||
|           "fitness": "Fitness Care", | ||||
|           "fitness_care": "Fitness Care", | ||||
|           "fresh_care": "Fresh Care", | ||||
|           "fresh_care_steam": "Fresh Care + Steam", | ||||
|           "handwash_wool": "Hand Wash + Wool", | ||||
|           "high_dry": "High Heat Dry", | ||||
|           "hqd_20_degrees": "Cotton 20℃", | ||||
|           "hqd_allergy": "Allergy Care", | ||||
|           "hqd_autoclean": "Drum Cleaning", | ||||
|           "hqd_babycare": "Baby Care", | ||||
|           "hqd_baby_care": "Baby care", | ||||
|           "hqd_bath_towel": "Bath towel", | ||||
|           "hqd_bed_sheets": "Bed sheets", | ||||
|           "hqd_bulky": "Bulky", | ||||
|           "hqd_casual": "Casual", | ||||
|           "hqd_checkup": "Check-Up", | ||||
|           "hqd_cold_wind_30": "Cold wind 30'", | ||||
|           "hqd_cold_wind_timing": "Cold wind timing", | ||||
|           "hqd_cotton": "Cotton", | ||||
|           "hqd_cottons": "Cotton", | ||||
|           "hqd_curtain": "Curtain", | ||||
|           "hqd_delicate": "Delicate", | ||||
|           "hqd_delicate_cradle": "Delicate", | ||||
|           "hqd_diaper": "Diaper", | ||||
|           "hqd_dry": "Cotton Dry", | ||||
|           "hqd_dry_synthetics": "Low Heat Dry", | ||||
|           "hqd_duvet": "Duvet", | ||||
|           "hqd_eco_40_60_degrees": "Eco 40-60", | ||||
|           "hqd_feather": "Feather", | ||||
|           "hqd_handwash_wool": "Wool", | ||||
|           "hqd_hot_wind_timing": "Hot wind timing", | ||||
|           "hqd_hygienic": "Hygienic", | ||||
|           "hqd_i_refresh": "i-Refresh", | ||||
|           "hqd_i_refresh_pro": "i-Refresh Pro", | ||||
|           "hqd_jacket": "Jacket", | ||||
|           "hqd_jeans": "Jeans", | ||||
|           "hqd_luxury": "Luxury", | ||||
|           "hqd_mix": "Mix", | ||||
|           "hqd_night_dry": "Night dry", | ||||
|           "hqd_outdoor": "Outdoor", | ||||
|           "hqd_precious_cure": "Precious cure", | ||||
|           "hqd_quick_15": "Quick 15'", | ||||
|           "hqd_quick_20": "Quick 20'", | ||||
|           "hqd_quick_30": "Quick 30'", | ||||
|           "hqd_quick_dry": "Quick dry", | ||||
|           "hqd_quick_wash_57": "Quick Wash 57'", | ||||
|           "hqd_quilt": "Quilt", | ||||
|           "hqd_rapid_wash_and_dry": "Wash and dry", | ||||
|           "hqd_refresh": "Refresh", | ||||
|           "hqd_rinse": "Rinses", | ||||
|           "hqd_school_uniform": "School uniform", | ||||
|           "hqd_shirt": "Shirt", | ||||
|           "hqd_shirts": "Shirts", | ||||
|           "hqd_shoes": "Shoes", | ||||
|           "hqd_silk": "Silk", | ||||
|           "hqd_smart": "Smart A.I.", | ||||
|           "hqd_spin": "Spin", | ||||
|           "hqd_sport": "Sport", | ||||
|           "hqd_sports": "Sports", | ||||
|           "hqd_super_fast": "Super Fast 39'", | ||||
|           "hqd_synthetic_and_coloured": "Synthetics", | ||||
|           "hqd_synthetics": "Synthetics", | ||||
|           "hqd_timer": "Timer", | ||||
|           "hqd_towel": "Towel", | ||||
|           "hqd_underwear": "Underwear", | ||||
|           "hqd_warm_up": "Warm up", | ||||
|           "hqd_wool": "Wool", | ||||
|           "hqd_working_suit": "Working suit", | ||||
|           "hygiene_59": "Hygiene Plus 59'", | ||||
|           "hygiene_60": "Hygiene 60°C", | ||||
|           "hygiene_plus_59": "Hygiene Plus 59'", | ||||
|           "hygiene_plus_59_min": "Hygiene Plus 59'", | ||||
|           "hygiene_pro_4_min": "Hygiene Pro 49'", | ||||
|           "hygiene_pro_49_min": "Hygiene Pro 49'", | ||||
|           "hygiene_pro_steam": "Hygiene Pro + Steam", | ||||
|           "intensive_40": "Intensive 40°C", | ||||
|           "intensive_40_steam": "Intensive 40°C + Steam", | ||||
|           "iot_checkup": "Check-Up", | ||||
|           "iot_dry_air_refresh": "Air Refresh", | ||||
|           "iot_dry_anti_mites": "Anti-mite", | ||||
|           "iot_dry_baby": "Baby", | ||||
|           "iot_dry_backpacks": "Backpacks", | ||||
|           "iot_dry_bathrobe": "Bathrobes", | ||||
|           "iot_dry_bed_linen": "Bed Linen", | ||||
|           "iot_dry_cotton_dry": "Cotton Dry", | ||||
|           "iot_dry_cotton": "Cotton", | ||||
|           "iot_dry_cuddly_toys": "Cuddly Toys", | ||||
|           "iot_dry_curtains": "Curtains", | ||||
|           "iot_dry_dehumidifier": "Humidity Remover", | ||||
|           "iot_dry_delicates": "Delicates", | ||||
|           "iot_dry_delicates_antiallergy": "Delicates  Anti-allergy", | ||||
|           "iot_dry_delicate_tablecloths": "Delicate Tablecloths", | ||||
|           "iot_dry_denim_jeans": "Denim - Jeans", | ||||
|           "iot_dry_down_jacket": "Down jacket", | ||||
|           "iot_dry_duvet": "Duvet", | ||||
|           "iot_dry_easy_iron_cotton": "Easy Iron - Cotton", | ||||
|           "iot_dry_easy_iron_synthetics": "Easy Iron - Synthetics", | ||||
|           "iot_dry_gym_fit": "Gym fit - Fitness", | ||||
|           "iot_dry_lingerie": "Lingerie", | ||||
|           "iot_dry_mixed": "Mixed", | ||||
|           "iot_dry_mixed_dry": "Mixed Dry", | ||||
|           "iot_dry_rapid_30": "Rapid 30'", | ||||
|           "iot_dry_rapid_59": "Rapid 59'", | ||||
|           "iot_dry_rapid_60_min_delicates": "Rapid 60' - Delicates", | ||||
|           "iot_dry_shirts": "Shirts", | ||||
|           "iot_dry_swimsuits_and_bikinis": "Swimsuits and Bikinis", | ||||
|           "iot_dry_synthetics": "Synthetic Dry", | ||||
|           "iot_dry_synthetic_dry": "Synthetic Dry", | ||||
|           "iot_dry_tablecloths": "Tablecloths", | ||||
|           "iot_dry_technical_fabrics": "Technical Fabrics", | ||||
|           "iot_dry_warm_embrace": "Warm Embrace", | ||||
|           "iot_dry_wool": "Wool", | ||||
|           "iot_dry_wool_dry": "Wool Dry", | ||||
|           "iot_wash_and_dry": "Wash and dry", | ||||
|           "iot_wash_anti_mites": "Anti-mites", | ||||
|           "iot_wash_anti_odor": "Anti-odour", | ||||
|           "iot_wash_ariel_clean_cycle": "Ariel Ultimate Clean", | ||||
|           "iot_wash_ariel_cold_cycle": "Ariel Cold Clean", | ||||
|           "iot_wash_ariel_fresh_cycle": "Ariel Fresh Clean", | ||||
|           "iot_wash_baby_sanitizer": "Sanitizer", | ||||
|           "iot_wash_baby_sanitizer_steam": "Sanitiser + Steam", | ||||
|           "iot_wash_backpacks": "Backpacks", | ||||
|           "iot_wash_backpacks_zelig": "Backpacks", | ||||
|           "iot_wash_bathrobe": "Bathrobes and Towels", | ||||
|           "iot_wash_bathrobe_steam": "Bathrobe and Towels + Steam", | ||||
|           "iot_wash_bed_linen": "Bed Linen", | ||||
|           "iot_wash_bed_linen_steam": "Bed Linen + Steam", | ||||
|           "iot_wash_bed_linen_zelig": "Bed Linens", | ||||
|           "iot_wash_big_single_load": "Big single load", | ||||
|           "iot_wash_bleaching": "Bleaching", | ||||
|           "iot_wash_blood_stains": "Bloodstains", | ||||
|           "iot_wash_cashmere": "Cashmere", | ||||
|           "iot_wash_chocolate_stains": "Chocolate stains", | ||||
|           "iot_wash_cold_wash": "Cold Wash", | ||||
|           "iot_wash_colored": "Colored", | ||||
|           "iot_wash_colored_anti_stain": "Colored Anti-stain", | ||||
|           "iot_wash_colored_delicate": "Colored Delicate", | ||||
|           "iot_wash_coloured": "Colored", | ||||
|           "iot_wash_coloured_bed_linen": "Colored Bed Linen", | ||||
|           "iot_wash_coloured_bed_linen_steam": "Coloured Bed Linen + Steam", | ||||
|           "iot_wash_coloured_curtains": "Colored Curtains", | ||||
|           "iot_wash_coloured_shirts": "Colored Shirts", | ||||
|           "iot_wash_coloured_shirts_steam": "Colored Shirts + Steam", | ||||
|           "iot_wash_coloured_steam": "Colored + Steam", | ||||
|           "iot_wash_coloured_tableclothes": "Colored Tableclothes", | ||||
|           "iot_wash_coloured_tableclothes_steam": "Coloured Tablecloths + Steam", | ||||
|           "iot_wash_cotton": "Cotton", | ||||
|           "iot_wash_cotton_steam": "Cotton + Steam", | ||||
|           "iot_wash_cuddly_toys": "Cuddly Toys", | ||||
|           "iot_wash_curtains": "Curtains", | ||||
|           "iot_wash_curtains_steam": "Curtains + Steam", | ||||
|           "iot_wash_curtains_zelig": "Curtains", | ||||
|           "iot_wash_dark": "Darks", | ||||
|           "iot_wash_darks_and_coloured_44": "Darks and Colored 44'", | ||||
|           "iot_wash_darks_and_coloured_59": "Darks and Colored 59'", | ||||
|           "iot_wash_darks_and_coloured_xl": "Darks and Colored XL", | ||||
|           "iot_wash_dark_steam": "Darks + Steam", | ||||
|           "iot_wash_dash_clean_cycle": "Dash Ultimate Clean", | ||||
|           "iot_wash_dash_cold_cycle": "Dash Cold Clean", | ||||
|           "iot_wash_dash_fresh_cycle": "Dash Fresh Clean", | ||||
|           "iot_wash_delicate": "Delicates", | ||||
|           "iot_wash_delicate_antiallergy": "Delicate Anti-Allergy", | ||||
|           "iot_wash_delicate_antiallergy_steam": "Delicate Anti-Allergy + Steam", | ||||
|           "iot_wash_delicate_antiallergy_zelig": "Delicate Anti-Allergy", | ||||
|           "iot_wash_delicate_colors": "Delicate Colors", | ||||
|           "iot_wash_delicate_colors_steam": "Delicate Colors + Steam", | ||||
|           "iot_wash_delicate_dark": "Delicate Darks", | ||||
|           "iot_wash_delicate_steam": "Delicates + Steam", | ||||
|           "iot_wash_delicate_tablecloths": "Delicate Tablecloths", | ||||
|           "iot_wash_delicate_tablecloths_steam": "Delicate Tablecloths + Steam", | ||||
|           "iot_wash_delicate_whites": "Delicate Whites", | ||||
|           "iot_wash_denim_jeans": "Denim - Jeans", | ||||
|           "iot_wash_diving_suits": "Diving Suits", | ||||
|           "iot_wash_diving_suits_zelig": "Diving Suits", | ||||
|           "iot_wash_down_jackets": "Down Jackets", | ||||
|           "iot_wash_down_jackets_zelig": "Down Jackets", | ||||
|           "iot_wash_duvet": "Duvet", | ||||
|           "iot_wash_fruit_stains": "Fruit stains", | ||||
|           "iot_wash_gym_fit": "Gym Fit - Fitness", | ||||
|           "iot_wash_handwash": "Handwash", | ||||
|           "iot_wash_handwash_colored": "Handwash Colored", | ||||
|           "iot_wash_handwash_dark": "Handwash Darks", | ||||
|           "iot_wash_lingerie": "Lingerie", | ||||
|           "iot_wash_masks_refresh": "Masks Refresh", | ||||
|           "iot_wash_masks_sanification": "Masks Sanitization", | ||||
|           "iot_wash_masks_sanification_steam": "Mask Sanitisation + Steam", | ||||
|           "iot_wash_mats": "Mats", | ||||
|           "iot_wash_men_s_trousers": "Trousers", | ||||
|           "iot_wash_mixed": "Mixed", | ||||
|           "iot_wash_mixed_steam": "Mixed + Steam", | ||||
|           "iot_wash_mix_and_coloured_44": "Mix and Colored 44'", | ||||
|           "iot_wash_mix_and_coloured_59": "Mix and Colored 59'", | ||||
|           "iot_wash_mix_and_coloured_xl": "Mix and colored XL", | ||||
|           "iot_wash_new_clothes": "New Clothes", | ||||
|           "iot_wash_perfect_white": "Perfect White", | ||||
|           "iot_wash_perfect_white_steam": "Perfect White + Steam", | ||||
|           "iot_wash_pets": "Pet Accessories", | ||||
|           "iot_wash_pets_hair_removal": "Pets Hair Removal", | ||||
|           "iot_wash_pets_odours_stains_removal": "Pets Odours and Stains Removal", | ||||
|           "iot_wash_pets_steam": "Pet Accessories + Steam", | ||||
|           "iot_wash_playsuits": "Playsuits", | ||||
|           "iot_wash_playsuits_steam": "Playsuits + Steam", | ||||
|           "iot_wash_quick_drum_cleaner": "Quick drum cleaner", | ||||
|           "iot_wash_rapid_14": "Rapid 14’", | ||||
|           "iot_wash_rapid_30": "Rapid 30’", | ||||
|           "iot_wash_rapid_44": "Rapid 44'", | ||||
|           "iot_wash_rapid_59": "Rapid 59'", | ||||
|           "iot_wash_rapid_59_steam": "Rapid 59' + Steam", | ||||
|           "iot_wash_refresh_14_min": "Refresh 14'", | ||||
|           "iot_wash_resistant_colored": "Resistant Colored", | ||||
|           "iot_wash_resistant_dark": "Resistant Darks", | ||||
|           "iot_wash_resistant_whites": "Resistant Whites", | ||||
|           "iot_wash_rinse": "Rinses", | ||||
|           "iot_wash_shirts": "Shirts", | ||||
|           "iot_wash_shirts_steam": "Shirts + Steam", | ||||
|           "iot_wash_silk": "Silk", | ||||
|           "iot_wash_ski_suit": "Ski Suit", | ||||
|           "iot_wash_ski_suit_zelig": "Ski Suit", | ||||
|           "iot_wash_spin": "Spin", | ||||
|           "iot_wash_sport": "Sport", | ||||
|           "iot_wash_sport_anti_odor": "Anti-odour Sportswear", | ||||
|           "iot_wash_sport_anti_odor_zelig": "Anti-odour Sportswear", | ||||
|           "iot_wash_stains_remover": "Stain Remover", | ||||
|           "iot_wash_swimsuits_and_bikinis": "Swimsuits and Bikinis", | ||||
|           "iot_wash_synthetic": "Synthetics", | ||||
|           "iot_wash_synthetic_steam": "Synthetics + Steam", | ||||
|           "iot_wash_tablecloths": "Tablecloths", | ||||
|           "iot_wash_tablecloths_steam": "Tablecloths + Steam", | ||||
|           "iot_wash_technical_fabrics": "Technical Fabrics", | ||||
|           "iot_wash_technical_fabrics_zelig": "Technical Fabrics", | ||||
|           "iot_wash_technical_jackets": "Technical Jackets", | ||||
|           "iot_wash_technical_jackets_zelig": "Technical Jackets", | ||||
|           "iot_wash_trainers": "Trainers", | ||||
|           "iot_wash_whites": "Whites", | ||||
|           "iot_wash_whites_44": "Whites 44'", | ||||
|           "iot_wash_whites_59": "Whites 59'", | ||||
|           "iot_wash_whites_xl": "Whites XL", | ||||
|           "iot_wash_wine_stains": "Wine Stains", | ||||
|           "iot_wash_wool": "Wool", | ||||
|           "jeans": "Jeans", | ||||
|           "jeans_60": "Jeans", | ||||
|           "low_dry": "Low Heat Dry", | ||||
|           "mixed": "Mixed", | ||||
|           "mixed_and_colored_59": "Mixed and Colored 59'", | ||||
|           "mixed_steam": "Mixed + Steam", | ||||
|           "mix_and_colour_59": "Mixed and Colored 59'", | ||||
|           "mix_and_colour_59_steam": "Mixed and Coloured 59' + Steam", | ||||
|           "night_and_day": "Night and Day", | ||||
|           "night_wash": "Night Wash", | ||||
|           "perfect_59": "Perfect 59'", | ||||
|           "perfect_cotton_59": "Perfect Cotton 59'", | ||||
|           "perfect_cotton_59_steam": "Perfect Cotton 59' + Steam", | ||||
|           "perfect_whites_59": "Perfect White 59'", | ||||
|           "rapid_14_min": "Rapid 14'", | ||||
|           "rapid_30_min": "Rapid 30'", | ||||
|           "rapid_44_min": "Rapid 44'", | ||||
|           "rapid_a_class_60": "Rapid 59' A Class", | ||||
|           "rapid_a_class_60_steam": "Rapid 59' A Class + Steam", | ||||
|           "rapid_wash_and_dry_59_min": "Wash and Dry 59'", | ||||
|           "resistant_cotton": "Resistant Cotton", | ||||
|           "resistant_cotton_steam": "Resistant Cotton + Steam", | ||||
|           "rinse": "Rinse", | ||||
|           "shirts_steam": "Shirts + Steam", | ||||
|           "silent_night": "Silent Night", | ||||
|           "single_item": "Single Item", | ||||
|           "single_item_steam": "Single Item + Steam", | ||||
|           "smart_wash": "Smart Wash", | ||||
|           "soft_care": "Soft Care", | ||||
|           "soft_care_steam": "Soft Care + Steam", | ||||
|           "soft_care_steam_title": "Soft Care + Steam", | ||||
|           "special_39": "Special 39'", | ||||
|           "special_39_full_load": "Special 39'", | ||||
|           "special_39_full_load_steam": "Special 39' + Steam", | ||||
|           "special_49": "Special 49'", | ||||
|           "sport_39": "Sport 39'", | ||||
|           "sport_plus_29": "Sport Plus 29'", | ||||
|           "sport_plus_39": "Sport Plus 39'", | ||||
|           "steam_39": "Steam 39'", | ||||
|           "steam_care_pro": "Steam Care Pro", | ||||
|           "steam_care_pro_cotton": "Steam Care Pro - Cottons", | ||||
|           "steam_care_pro_delicates": "Steam Care Pro - Delicates", | ||||
|           "steam_care_pro_synthetic": "Steam Care Pro - Synthetics", | ||||
|           "steam_hygiene_plus": "Hygiene Plus + Steam", | ||||
|           "synthetics": "Synthetics", | ||||
|           "synthetic_and_coloured": "Synthetic and Colored", | ||||
|           "synthetic_and_coloured_steam": "Synthetic and Coloured + Steam", | ||||
|           "tailored_resistant_cotton": "Tailored Resistant Cotton", | ||||
|           "tailored_synthetic_and_coloured": "Tailored Synthetic Colored", | ||||
|           "total_care": "Total Care", | ||||
|           "tumbling": "Tumbling", | ||||
|           "wool": "Wool", | ||||
|           "wool_and_delicates_49": "Wool and Delicates 49'", | ||||
|           "wool_dry": "Wool Dry", | ||||
|           "wool_soft_care": "Wool and Soft Car" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -1,4 +1,5 @@ | ||||
| { | ||||
|     "name": "Haier hOn", | ||||
|     "render_readme": true, | ||||
|     "homeassistant": "2023.2.0" | ||||
| } | ||||
							
								
								
									
										35
									
								
								info.md
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								info.md
									
									
									
									
									
								
							| @ -1,35 +0,0 @@ | ||||
| # Haier hOn | ||||
| [](https://github.com/Andre0512/hon/releases/latest) | ||||
| [](https://analytics.home-assistant.io/)   | ||||
| Support for home appliances of Haier's mobile app hOn.  | ||||
|  | ||||
| ## Supported Appliances | ||||
| - Tumble Dryer | ||||
| - Washer Dryer | ||||
| - Washing Machine | ||||
| - Oven | ||||
|  | ||||
| ## Tested Appliances | ||||
| - Haier WD90-B14TEAM5 | ||||
| - Haier HD80-A3959 | ||||
| - Haier HWO60SM2F3XH | ||||
| - Hoover H-WASH 500 | ||||
|  | ||||
|  | ||||
| ## Configuration | ||||
|  | ||||
| **Method 1**: [](https://my.home-assistant.io/redirect/config_flow_start/?domain=hon) | ||||
|  | ||||
| **Method 2**: Settings > Devices & Services > Add Integration > **Haier hOn**   | ||||
| _If the integration is not in the list, you need to clear the browser cache._ | ||||
|  | ||||
|  | ||||
| ## Contribute | ||||
| Want to help us to support more appliances?  | ||||
| Or add more sensors? | ||||
| Or help with translating?  | ||||
| Or beautify some icons or captions?  | ||||
| Check out the [project on GitHub](https://github.com/Andre0512/hon), every contribution is welcome! | ||||
|  | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	