Compare commits
	
		
			1 Commits
		
	
	
		
			v0.6.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" |  | ||||||
							
								
								
									
										38
									
								
								.github/workflows/python_check.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								.github/workflows/python_check.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,38 +0,0 @@ | |||||||
| name: Python check |  | ||||||
|  |  | ||||||
| on: |  | ||||||
|   push: |  | ||||||
|     branches: [ "main" ] |  | ||||||
|   pull_request: |  | ||||||
|     branches: [ "main" ] |  | ||||||
|  |  | ||||||
| jobs: |  | ||||||
|   build: |  | ||||||
|  |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     strategy: |  | ||||||
|       fail-fast: false |  | ||||||
|       matrix: |  | ||||||
|         python-version: ["3.10", "3.11"] |  | ||||||
|  |  | ||||||
|     steps: |  | ||||||
|     - uses: actions/checkout@v3 |  | ||||||
|     - name: Set up Python ${{ matrix.python-version }} |  | ||||||
|       uses: actions/setup-python@v3 |  | ||||||
|       with: |  | ||||||
|         python-version: ${{ matrix.python-version }} |  | ||||||
|     - name: Install dependencies |  | ||||||
|       run: | |  | ||||||
|         python -m pip install --upgrade pip |  | ||||||
|         python -m pip install flake8 pylint black |  | ||||||
|     - name: Lint with flake8 |  | ||||||
|       run: | |  | ||||||
|         # stop the build if there are Python syntax errors or undefined names |  | ||||||
|         flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics |  | ||||||
|         flake8 . --count --exit-zero --max-complexity=10 --max-line-length=88 --statistics |  | ||||||
|     # - name: Analysing the code with pylint |  | ||||||
|     #   run: | |  | ||||||
|     #     pylint --max-line-length 88 $(git ls-files '*.py') |  | ||||||
|     - name: Check black style |  | ||||||
|       run: | |  | ||||||
|         black . --check |  | ||||||
							
								
								
									
										25
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,25 +0,0 @@ | |||||||
| name: Release |  | ||||||
|  |  | ||||||
| on: |  | ||||||
|   release: |  | ||||||
|     types: [published] |  | ||||||
|  |  | ||||||
| jobs: |  | ||||||
|   release-zip: |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     steps: |  | ||||||
|       - uses: actions/checkout@v2 |  | ||||||
|  |  | ||||||
|       - name: ZIP Component Dir |  | ||||||
|         run: | |  | ||||||
|           cd ${{ github.workspace }}/custom_components/hon |  | ||||||
|           zip -r haier_hon.zip ./ |  | ||||||
|  |  | ||||||
|       - name: Upload zip to release |  | ||||||
|         uses: svenstaro/upload-release-action@v2 |  | ||||||
|         with: |  | ||||||
|           repo_token: ${{ secrets.GITHUB_TOKEN }} |  | ||||||
|           file: ${{ github.workspace }}/custom_components/hon/haier_hon.zip |  | ||||||
|           asset_name: haier_hon.zip |  | ||||||
|           tag: ${{ github.ref }} |  | ||||||
|           overwrite: true |  | ||||||
							
								
								
									
										14
									
								
								.github/workflows/validate.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/validate.yml
									
									
									
									
										vendored
									
									
								
							| @ -1,14 +1,16 @@ | |||||||
| name: Validate with hassfest | name: Validate | ||||||
|  |  | ||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|   pull_request: |   pull_request: | ||||||
|   schedule: |  | ||||||
|     - cron:  '0 0 * * *' |  | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   validate: |   validate: | ||||||
|     runs-on: "ubuntu-latest" |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|         - uses: "actions/checkout@v3" |       - uses: actions/checkout@v2 | ||||||
|         - uses: "home-assistant/actions/hassfest@master" |       - uses: home-assistant/actions/hassfest@master | ||||||
|  |       - name: HACS validation | ||||||
|  |         uses: hacs/action@main | ||||||
|  |         with: | ||||||
|  |           category: integration | ||||||
							
								
								
									
										111
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								README.md
									
									
									
									
									
								
							| @ -1,106 +1,27 @@ | |||||||
| # Haier hOn | # Haier hOn | ||||||
| [](https://hacs.xyz) | Home Assistant component supporting hOn cloud. | ||||||
| [](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 |  | ||||||
| - Washing Machine |  | ||||||
| - Tumble Dryer |  | ||||||
| - Washer Dryer |  | ||||||
| - Oven |  | ||||||
| - Hob |  | ||||||
| - Dish Washer |  | ||||||
|  |  | ||||||
| ## Installation | ## 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   | ## Supported Appliances | ||||||
|  | - Washing Machine | ||||||
| **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! |  | ||||||
| ### Read out device data |  | ||||||
| If you want to make a request for adding new appliances or additional attributes and don't want to use the command line, here is how you can read out your device data. |  | ||||||
| For every device exists a hidden button which can be used to log all info of your appliance. |  | ||||||
| 1. Enable the "Log Device Info" button   |  | ||||||
|    _This button can be found in the diagnostic section of your device or in the entity overview if "show disabled entities" is enabled._ |  | ||||||
| 2. Press the button |  | ||||||
| 3. Go to Settings > System > Logs, click _load full logs_ and scroll down   |  | ||||||
|    _The formatting is messy if you not load full logs_ |  | ||||||
| 4. Here you can find all data which can be read out via the api |  | ||||||
|    ```yaml |  | ||||||
|    data: |  | ||||||
|      appliance: |  | ||||||
|        applianceId: 12-34-56-78-90-ab#2022-10-25T19:47:11Z |  | ||||||
|        applianceModelId: 1569  |  | ||||||
|        ... |  | ||||||
|    ``` |  | ||||||
| 5. Copy this data and create a [new issue](https://github.com/Andre0512/hon/issues/new) with your request |  | ||||||
|  |  | ||||||
| ### Add appliances or additional attributes |  | ||||||
| 1. Install [pyhOn](https://github.com/Andre0512/pyhOn) |  | ||||||
|    ```commandline |  | ||||||
|     $ pip install pyhOn |  | ||||||
|     ``` |  | ||||||
| 2. Use the command line 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's translate command](https://github.com/Andre0512/pyhOn#translation) to read out the official translations  |  | ||||||
|  |  | ||||||
| ## Tested Devices | ## Tested Devices | ||||||
| - Haier WD90-B14TEAM5 | - Haier WD90 | ||||||
| - Haier HD80-A3959 |  | ||||||
| - Haier HWO60SM2F3XH |  | ||||||
| - Hoover H-WASH 500 |  | ||||||
|  |  | ||||||
| ## About this Repo | ## About this Repo | ||||||
| The existing integrations missed some features from the app I liked to have in HomeAssistant. | 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 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). | I moved the api related stuff into the package [pyhOn](https://github.com/Andre0512/pyhOn). | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import logging | import logging | ||||||
| 
 | 
 | ||||||
| import voluptuous as vol | import voluptuous as vol | ||||||
| from pyhon import Hon | from pyhon import HonConnection | ||||||
| 
 | 
 | ||||||
| from homeassistant.config_entries import ConfigEntry | from homeassistant.config_entries import ConfigEntry | ||||||
| from homeassistant.const import CONF_EMAIL, CONF_PASSWORD | from homeassistant.const import CONF_EMAIL, CONF_PASSWORD | ||||||
| @ -28,9 +28,8 @@ CONFIG_SCHEMA = vol.Schema( | |||||||
| 
 | 
 | ||||||
| async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): | async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): | ||||||
|     session = aiohttp_client.async_get_clientsession(hass) |     session = aiohttp_client.async_get_clientsession(hass) | ||||||
|     hon = await Hon( |     hon = HonConnection(entry.data["email"], entry.data["password"], session) | ||||||
|         entry.data["email"], entry.data["password"], session=session |     await hon.setup() | ||||||
|     ).create() |  | ||||||
|     hass.data.setdefault(DOMAIN, {}) |     hass.data.setdefault(DOMAIN, {}) | ||||||
|     hass.data[DOMAIN][entry.unique_id] = hon |     hass.data[DOMAIN][entry.unique_id] = hon | ||||||
|     hass.data[DOMAIN]["coordinators"] = {} |     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() | ||||||
							
								
								
									
										59
									
								
								custom_components/haier/button.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								custom_components/haier/button.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | |||||||
|  | from pyhon import HonConnection | ||||||
|  | from pyhon.device import HonDevice | ||||||
|  |  | ||||||
|  | from homeassistant.components.button import ButtonEntityDescription, ButtonEntity | ||||||
|  | from homeassistant.config_entries import ConfigEntry | ||||||
|  |  | ||||||
|  | from .const import DOMAIN | ||||||
|  | from .hon import HonCoordinator, HonEntity | ||||||
|  |  | ||||||
|  | BUTTONS: dict[str, tuple[ButtonEntityDescription, ...]] = { | ||||||
|  |     "WM": ( | ||||||
|  |         ButtonEntityDescription( | ||||||
|  |             key="pauseProgram", | ||||||
|  |             name="Pause Program", | ||||||
|  |             icon="mdi:pause", | ||||||
|  |         ), | ||||||
|  |         ButtonEntityDescription( | ||||||
|  |             key="resumeProgram", | ||||||
|  |             name="Resume Program", | ||||||
|  |             icon="mdi:play-pause", | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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 := BUTTONS.get(device.appliance_type_name): | ||||||
|  |             for description in descriptions: | ||||||
|  |                 if not device.commands.get(description.key): | ||||||
|  |                     continue | ||||||
|  |                 appliances.extend([ | ||||||
|  |                     HonButtonEntity(hass, coordinator, entry, device, description)] | ||||||
|  |                 ) | ||||||
|  |  | ||||||
|  |     async_add_entities(appliances) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonButtonEntity(HonEntity, ButtonEntity): | ||||||
|  |     def __init__(self, hass, coordinator, entry, device: HonDevice, description) -> None: | ||||||
|  |         super().__init__(hass, entry, coordinator, device) | ||||||
|  |  | ||||||
|  |         self._coordinator = coordinator | ||||||
|  |         self._device = device | ||||||
|  |         self.entity_description = description | ||||||
|  |         self._attr_unique_id = f"{super().unique_id}{description.key}" | ||||||
|  |  | ||||||
|  |     async def async_press(self) -> None: | ||||||
|  |         await self._device.commands[self.entity_description.key].send() | ||||||
| @ -20,12 +20,8 @@ class HonFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): | |||||||
| 
 | 
 | ||||||
|     async def async_step_user(self, user_input=None): |     async def async_step_user(self, user_input=None): | ||||||
|         if user_input is None: |         if user_input is None: | ||||||
|             return self.async_show_form( |             return self.async_show_form(step_id="user", data_schema=vol.Schema( | ||||||
|                 step_id="user", |                 {vol.Required(CONF_EMAIL): str, vol.Required(CONF_PASSWORD): str})) | ||||||
|                 data_schema=vol.Schema( |  | ||||||
|                     {vol.Required(CONF_EMAIL): str, vol.Required(CONF_PASSWORD): str} |  | ||||||
|                 ), |  | ||||||
|             ) |  | ||||||
| 
 | 
 | ||||||
|         self._email = user_input[CONF_EMAIL] |         self._email = user_input[CONF_EMAIL] | ||||||
|         self._password = user_input[CONF_PASSWORD] |         self._password = user_input[CONF_PASSWORD] | ||||||
| @ -1,4 +1,4 @@ | |||||||
| DOMAIN = "hon" | DOMAIN = "haier" | ||||||
| 
 | 
 | ||||||
| PLATFORMS = [ | PLATFORMS = [ | ||||||
|     "sensor", |     "sensor", | ||||||
| @ -1,7 +1,7 @@ | |||||||
| import logging | import logging | ||||||
| from datetime import timedelta | from datetime import timedelta | ||||||
| 
 | 
 | ||||||
| from pyhon.appliance import HonAppliance | from pyhon.device import HonDevice | ||||||
| 
 | 
 | ||||||
| from homeassistant.helpers.entity import DeviceInfo | from homeassistant.helpers.entity import DeviceInfo | ||||||
| from homeassistant.helpers.update_coordinator import CoordinatorEntity | from homeassistant.helpers.update_coordinator import CoordinatorEntity | ||||||
| @ -15,37 +15,30 @@ _LOGGER = logging.getLogger(__name__) | |||||||
| class HonEntity(CoordinatorEntity): | class HonEntity(CoordinatorEntity): | ||||||
|     _attr_has_entity_name = True |     _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) |         super().__init__(coordinator) | ||||||
| 
 | 
 | ||||||
|         self._hon = hass.data[DOMAIN][entry.unique_id] |         self._hon = hass.data[DOMAIN][entry.unique_id] | ||||||
|         self._hass = hass |         self._hass = hass | ||||||
|         self._device = device |         self._device = device | ||||||
| 
 | 
 | ||||||
|         self._attr_unique_id = self._device.unique_id |         self._attr_unique_id = self._device.mac_address | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|     def device_info(self): |     def device_info(self): | ||||||
|         return DeviceInfo( |         return DeviceInfo( | ||||||
|             identifiers={(DOMAIN, self._device.unique_id)}, |             identifiers={(DOMAIN, self._device.mac_address)}, | ||||||
|             manufacturer=self._device.get("brand", ""), |             manufacturer=self._device.brand, | ||||||
|             name=self._device.nick_name |             name=self._device.nick_name if self._device.nick_name else self._device.model_name, | ||||||
|             if self._device.nick_name |  | ||||||
|             else self._device.model_name, |  | ||||||
|             model=self._device.model_name, |             model=self._device.model_name, | ||||||
|             sw_version=self._device.get("fwVersion", ""), |             sw_version=self._device.fw_version, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class HonCoordinator(DataUpdateCoordinator): | class HonCoordinator(DataUpdateCoordinator): | ||||||
|     def __init__(self, hass, device: HonAppliance): |     def __init__(self, hass, device: HonDevice): | ||||||
|         """Initialize my coordinator.""" |         """Initialize my coordinator.""" | ||||||
|         super().__init__( |         super().__init__(hass, _LOGGER, name=device.mac_address, update_interval=timedelta(seconds=30)) | ||||||
|             hass, |  | ||||||
|             _LOGGER, |  | ||||||
|             name=device.unique_id, |  | ||||||
|             update_interval=timedelta(seconds=30), |  | ||||||
|         ) |  | ||||||
|         self._device = device |         self._device = device | ||||||
| 
 | 
 | ||||||
|     async def _async_update_data(self): |     async def _async_update_data(self): | ||||||
							
								
								
									
										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() | ||||||
							
								
								
									
										97
									
								
								custom_components/haier/select.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								custom_components/haier/select.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,97 @@ | |||||||
|  | from __future__ import annotations | ||||||
|  |  | ||||||
|  | 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, REVOLUTIONS_PER_MINUTE | ||||||
|  | from homeassistant.core import callback | ||||||
|  | from homeassistant.helpers.entity import EntityCategory | ||||||
|  |  | ||||||
|  | from .const import DOMAIN | ||||||
|  | from .hon import HonEntity, HonCoordinator | ||||||
|  |  | ||||||
|  | SELECTS = { | ||||||
|  |     "WM": ( | ||||||
|  |         SelectEntityDescription( | ||||||
|  |             key="startProgram.spinSpeed", | ||||||
|  |             name="Spin speed", | ||||||
|  |             entity_category=EntityCategory.CONFIG, | ||||||
|  |             icon="mdi:numeric", | ||||||
|  |             unit_of_measurement=REVOLUTIONS_PER_MINUTE | ||||||
|  |         ), | ||||||
|  |         SelectEntityDescription( | ||||||
|  |             key="startProgram.temp", | ||||||
|  |             name="Temperature", | ||||||
|  |             entity_category=EntityCategory.CONFIG, | ||||||
|  |             icon="mdi:thermometer", | ||||||
|  |             unit_of_measurement=UnitOfTemperature.CELSIUS | ||||||
|  |         ), | ||||||
|  |         SelectEntityDescription( | ||||||
|  |             key="startProgram.program", | ||||||
|  |             name="Programme", | ||||||
|  |             entity_category=EntityCategory.CONFIG | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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 := SELECTS.get(device.appliance_type_name): | ||||||
|  |             for description in descriptions: | ||||||
|  |                 if not device.data.get(description.key): | ||||||
|  |                     continue | ||||||
|  |                 appliances.extend([ | ||||||
|  |                     HonSelectEntity(hass, coordinator, entry, device, description)] | ||||||
|  |                 ) | ||||||
|  |     async_add_entities(appliances) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonSelectEntity(HonEntity, SelectEntity): | ||||||
|  |     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._data, HonParameterFixed): | ||||||
|  |             self._attr_options: list[str] = self._data.values | ||||||
|  |         else: | ||||||
|  |             self._attr_options = [self._data.value] | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def current_option(self) -> str | None: | ||||||
|  |         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._data.value = option | ||||||
|  |         await self.coordinator.async_request_refresh() | ||||||
|  |  | ||||||
|  |     @callback | ||||||
|  |     def _handle_coordinator_update(self): | ||||||
|  |         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 = [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() | ||||||
							
								
								
									
										111
									
								
								custom_components/haier/switch.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								custom_components/haier/switch.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,111 @@ | |||||||
|  | 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 HonConnection | ||||||
|  | from pyhon.device import HonDevice | ||||||
|  |  | ||||||
|  | from .const import DOMAIN | ||||||
|  | from .hon import HonCoordinator, HonEntity | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonSwitchEntityDescriptionMixin: | ||||||
|  |     turn_on_key: str = "" | ||||||
|  |     turn_off_key: str = "" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @dataclass | ||||||
|  | class HonSwitchEntityDescription(HonSwitchEntityDescriptionMixin, | ||||||
|  |     SwitchEntityDescription | ||||||
|  | ): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { | ||||||
|  |     "WM": ( | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="startProgram", | ||||||
|  |             name="Start Program", | ||||||
|  |             icon="mdi:play", | ||||||
|  |             turn_on_key="startProgram", | ||||||
|  |             turn_off_key="stopProgram", | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="startProgram.delayStatus", | ||||||
|  |             name="Delay Status", | ||||||
|  |             entity_category=EntityCategory.CONFIG | ||||||
|  |         ), | ||||||
|  |         HonSwitchEntityDescription( | ||||||
|  |             key="startProgram.haier_SoakPrewashSelection", | ||||||
|  |             name="Soak Prewash Selection", | ||||||
|  |             entity_category=EntityCategory.CONFIG | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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 := SWITCHES.get(device.appliance_type_name): | ||||||
|  |             for description in descriptions: | ||||||
|  |                 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)] | ||||||
|  |                     ) | ||||||
|  |  | ||||||
|  |     async_add_entities(appliances) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class HonSwitchEntity(HonEntity, SwitchEntity): | ||||||
|  |     entity_description: HonSwitchEntityDescription | ||||||
|  |  | ||||||
|  |     def __init__(self, hass, coordinator, entry, device: HonDevice, description: HonSwitchEntityDescription) -> None: | ||||||
|  |         super().__init__(hass, entry, coordinator, device) | ||||||
|  |         self._coordinator = coordinator | ||||||
|  |         self._device = device | ||||||
|  |         self.entity_description = description | ||||||
|  |         self._attr_unique_id = f"{super().unique_id}{description.key}" | ||||||
|  |  | ||||||
|  |     def available(self) -> bool: | ||||||
|  |         if self.entity_category == EntityCategory.CONFIG: | ||||||
|  |             return self._device.settings[self.entity_description.key].typology == "fixed" | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def is_on(self) -> bool | None: | ||||||
|  |         """Return True if entity is on.""" | ||||||
|  |         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.data.get(self.entity_description.key, "") | ||||||
|  |  | ||||||
|  |     async def async_turn_on(self, **kwargs: Any) -> None: | ||||||
|  |         if self.entity_category == EntityCategory.CONFIG: | ||||||
|  |             setting = self._device.settings[self.entity_description.key] | ||||||
|  |             setting.value = setting.max | ||||||
|  |             self.async_write_ha_state() | ||||||
|  |         else: | ||||||
|  |             await self._device.commands[self.entity_description.turn_on_key].send() | ||||||
|  |  | ||||||
|  |     async def async_turn_off(self, **kwargs: Any) -> None: | ||||||
|  |         if self.entity_category == EntityCategory.CONFIG: | ||||||
|  |             setting = self._device.settings[self.entity_description.key] | ||||||
|  |             setting.value = setting.min | ||||||
|  |             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,247 +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="Connection", |  | ||||||
|             device_class=BinarySensorDeviceClass.CONNECTIVITY, |  | ||||||
|             on_value="CONNECTED", |  | ||||||
|             icon="mdi:wifi", |  | ||||||
|         ), |  | ||||||
|         HonBinarySensorEntityDescription( |  | ||||||
|             key="attributes.parameters.remoteCtrValid", |  | ||||||
|             name="Remote Control", |  | ||||||
|             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", |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
|     "IH": ( |  | ||||||
|         HonBinarySensorEntityDescription( |  | ||||||
|             key="attributes.lastConnEvent.category", |  | ||||||
|             name="Connection", |  | ||||||
|             device_class=BinarySensorDeviceClass.CONNECTIVITY, |  | ||||||
|             on_value="CONNECTED", |  | ||||||
|             icon="mdi:wifi", |  | ||||||
|         ), |  | ||||||
|         HonBinarySensorEntityDescription( |  | ||||||
|             key="attributes.parameters.remoteCtrValid", |  | ||||||
|             name="Remote Control", |  | ||||||
|             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", |  | ||||||
|         ), |  | ||||||
|         HonBinarySensorEntityDescription( |  | ||||||
|             key="hotStatus", |  | ||||||
|             name="Hot Status", |  | ||||||
|             device_class=BinarySensorDeviceClass.HEAT, |  | ||||||
|             on_value="1", |  | ||||||
|         ), |  | ||||||
|         HonBinarySensorEntityDescription( |  | ||||||
|             key="hobLockStatus", |  | ||||||
|             name="Hob Lock", |  | ||||||
|             device_class=BinarySensorDeviceClass.LOCK, |  | ||||||
|             on_value="0", |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
|     "DW": ( |  | ||||||
|         HonBinarySensorEntityDescription( |  | ||||||
|             key="saltStatus", |  | ||||||
|             name="Salt", |  | ||||||
|             device_class=BinarySensorDeviceClass.PROBLEM, |  | ||||||
|             on_value="1", |  | ||||||
|             icon="mdi:shaker-outline", |  | ||||||
|         ), |  | ||||||
|         HonBinarySensorEntityDescription( |  | ||||||
|             key="rinseAidStatus", |  | ||||||
|             name="Rinse Aid", |  | ||||||
|             device_class=BinarySensorDeviceClass.PROBLEM, |  | ||||||
|             on_value="1", |  | ||||||
|             icon="mdi:spray-bottle", |  | ||||||
|         ), |  | ||||||
|         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", |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 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.unique_id in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.unique_id] = 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,90 +0,0 @@ | |||||||
| import logging |  | ||||||
| import urllib |  | ||||||
| from urllib.parse import quote |  | ||||||
|  |  | ||||||
| from homeassistant.components.button import ButtonEntityDescription, ButtonEntity |  | ||||||
| from homeassistant.config_entries import ConfigEntry |  | ||||||
| from pyhon import Hon |  | ||||||
| from pyhon.appliance import HonAppliance |  | ||||||
|  |  | ||||||
| from homeassistant.const import EntityCategory |  | ||||||
| from .const import DOMAIN |  | ||||||
| from .hon import HonCoordinator, HonEntity |  | ||||||
|  |  | ||||||
| _LOGGER = logging.getLogger(__name__) |  | ||||||
|  |  | ||||||
| BUTTONS: dict[str, tuple[ButtonEntityDescription, ...]] = { |  | ||||||
|     "OV": ( |  | ||||||
|         ButtonEntityDescription( |  | ||||||
|             key="startProgram", |  | ||||||
|             name="Start Program", |  | ||||||
|             icon="mdi:power-cycle", |  | ||||||
|         ), |  | ||||||
|         ButtonEntityDescription( |  | ||||||
|             key="stopProgram", |  | ||||||
|             name="Stop Program", |  | ||||||
|             icon="mdi:power-off", |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
|     "IH": ( |  | ||||||
|         ButtonEntityDescription( |  | ||||||
|             key="startProgram", |  | ||||||
|             name="Start Program", |  | ||||||
|             icon="mdi:pot-steam", |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 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.unique_id in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.unique_id] = coordinator |  | ||||||
|         await coordinator.async_config_entry_first_refresh() |  | ||||||
|  |  | ||||||
|         if descriptions := BUTTONS.get(device.appliance_type): |  | ||||||
|             for description in descriptions: |  | ||||||
|                 if not device.commands.get(description.key): |  | ||||||
|                     continue |  | ||||||
|                 appliances.extend( |  | ||||||
|                     [HonButtonEntity(hass, coordinator, entry, device, description)] |  | ||||||
|                 ) |  | ||||||
|         appliances.extend([HonFeatureRequestButton(hass, coordinator, entry, device)]) |  | ||||||
|  |  | ||||||
|     async_add_entities(appliances) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonButtonEntity(HonEntity, ButtonEntity): |  | ||||||
|     def __init__( |  | ||||||
|         self, hass, coordinator, entry, device: HonAppliance, description |  | ||||||
|     ) -> None: |  | ||||||
|         super().__init__(hass, entry, coordinator, device) |  | ||||||
|  |  | ||||||
|         self._coordinator = coordinator |  | ||||||
|         self._device = device |  | ||||||
|         self.entity_description = description |  | ||||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" |  | ||||||
|  |  | ||||||
|     async def async_press(self) -> None: |  | ||||||
|         await self._device.commands[self.entity_description.key].send() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonFeatureRequestButton(HonEntity, ButtonEntity): |  | ||||||
|     def __init__(self, hass, coordinator, entry, device: HonAppliance) -> None: |  | ||||||
|         super().__init__(hass, entry, coordinator, device) |  | ||||||
|  |  | ||||||
|         self._device = device |  | ||||||
|         self._attr_unique_id = f"{super().unique_id}_log_device_info" |  | ||||||
|         self._attr_icon = "mdi:information" |  | ||||||
|         self._attr_name = "Log Device Info" |  | ||||||
|         self._attr_entity_category = EntityCategory.DIAGNOSTIC |  | ||||||
|         self._attr_entity_registry_enabled_default = False |  | ||||||
|  |  | ||||||
|     async def async_press(self) -> None: |  | ||||||
|         _LOGGER.error("Device Info:\n" + self._device.diagnose) |  | ||||||
| @ -1,11 +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.8.0b5"], |  | ||||||
|   "version": "0.6.0-beta.5" |  | ||||||
| } |  | ||||||
| @ -1,195 +0,0 @@ | |||||||
| from __future__ import annotations |  | ||||||
|  |  | ||||||
| from pyhon import Hon |  | ||||||
| from pyhon.parameter.range 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, |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
|     "IH": ( |  | ||||||
|         NumberEntityDescription( |  | ||||||
|             key="startProgram.temp", |  | ||||||
|             name="Temperature", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             icon="mdi:thermometer", |  | ||||||
|         ), |  | ||||||
|         NumberEntityDescription( |  | ||||||
|             key="startProgram.powerManagement", |  | ||||||
|             name="Power Management", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             icon="mdi:timelapse", |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
|     "DW": ( |  | ||||||
|         NumberEntityDescription( |  | ||||||
|             key="startProgram.delayTime", |  | ||||||
|             name="Delay time", |  | ||||||
|             icon="mdi:timer-plus", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             native_unit_of_measurement=UnitOfTime.MINUTES, |  | ||||||
|         ), |  | ||||||
|         NumberEntityDescription( |  | ||||||
|             key="startProgram.waterHard", |  | ||||||
|             name="Water hard", |  | ||||||
|             icon="mdi:water", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 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.unique_id in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.unique_id] = 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,157 +0,0 @@ | |||||||
| from __future__ import annotations |  | ||||||
|  |  | ||||||
| import logging |  | ||||||
|  |  | ||||||
| from pyhon import Hon |  | ||||||
| from pyhon.appliance import HonAppliance |  | ||||||
| from pyhon.parameter.fixed 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.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( |  | ||||||
|             key="startProgram.spinSpeed", |  | ||||||
|             name="Spin speed", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             icon="mdi:numeric", |  | ||||||
|             unit_of_measurement=REVOLUTIONS_PER_MINUTE, |  | ||||||
|         ), |  | ||||||
|         SelectEntityDescription( |  | ||||||
|             key="startProgram.temp", |  | ||||||
|             name="Temperature", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             icon="mdi:thermometer", |  | ||||||
|             unit_of_measurement=UnitOfTemperature.CELSIUS, |  | ||||||
|         ), |  | ||||||
|         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, |  | ||||||
|             translation_key="programs", |  | ||||||
|         ), |  | ||||||
|         SelectEntityDescription( |  | ||||||
|             key="startProgram.preheatStatus", |  | ||||||
|             name="Preheat", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
|     "IH": ( |  | ||||||
|         SelectEntityDescription( |  | ||||||
|             key="startProgram.program", |  | ||||||
|             name="Program", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             translation_key="programs", |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
|     "DW": ( |  | ||||||
|         SelectEntityDescription( |  | ||||||
|             key="startProgram.program", |  | ||||||
|             name="Program", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|             translation_key="programs_dw", |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 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.unique_id in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.unique_id] = coordinator |  | ||||||
|         await coordinator.async_config_entry_first_refresh() |  | ||||||
|  |  | ||||||
|         if descriptions := SELECTS.get(device.appliance_type): |  | ||||||
|             for description in descriptions: |  | ||||||
|                 if not device.settings.get(description.key): |  | ||||||
|                     continue |  | ||||||
|                 appliances.extend( |  | ||||||
|                     [HonSelectEntity(hass, coordinator, entry, device, description)] |  | ||||||
|                 ) |  | ||||||
|     async_add_entities(appliances) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonSelectEntity(HonEntity, SelectEntity): |  | ||||||
|     def __init__( |  | ||||||
|         self, hass, coordinator, entry, device: HonAppliance, description |  | ||||||
|     ) -> None: |  | ||||||
|         super().__init__(hass, entry, coordinator, device) |  | ||||||
|  |  | ||||||
|         self._coordinator = coordinator |  | ||||||
|         self._device = device |  | ||||||
|         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 |  | ||||||
|         else: |  | ||||||
|             self._attr_options: list[str] = [device.settings[description.key].value] |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def current_option(self) -> str | None: |  | ||||||
|         value = self._device.settings[self.entity_description.key].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 |  | ||||||
|         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 |  | ||||||
|         else: |  | ||||||
|             self._attr_options = [setting.value] |  | ||||||
|         self._attr_native_value = setting.value |  | ||||||
|         self.async_write_ha_state() |  | ||||||
| @ -1,349 +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 homeassistant.const import PERCENTAGE |  | ||||||
|  |  | ||||||
| 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", |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
|     "IH": ( |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="remainingTimeMM", |  | ||||||
|             name="Remaining Time", |  | ||||||
|             icon="mdi:timer", |  | ||||||
|             native_unit_of_measurement=UnitOfTime.MINUTES, |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="temp", |  | ||||||
|             name="Temperature", |  | ||||||
|             icon="mdi:thermometer", |  | ||||||
|             state_class=SensorStateClass.MEASUREMENT, |  | ||||||
|             native_unit_of_measurement=UnitOfTemperature.CELSIUS, |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription(key="errors", name="Error", icon="mdi:math-log"), |  | ||||||
|     ), |  | ||||||
|     "DW": ( |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="startProgram.ecoIndex", |  | ||||||
|             name="Eco Index", |  | ||||||
|             icon="mdi:sprout", |  | ||||||
|             state_class=SensorStateClass.MEASUREMENT, |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="startProgram.waterEfficiency", |  | ||||||
|             name="Water Efficiency", |  | ||||||
|             icon="mdi:water", |  | ||||||
|             state_class=SensorStateClass.MEASUREMENT, |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="startProgram.waterSaving", |  | ||||||
|             name="Water Saving", |  | ||||||
|             icon="mdi:water-percent", |  | ||||||
|             state_class=SensorStateClass.MEASUREMENT, |  | ||||||
|             native_unit_of_measurement=PERCENTAGE, |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="startProgram.temp", |  | ||||||
|             name="Temperature", |  | ||||||
|             icon="mdi:thermometer", |  | ||||||
|             state_class=SensorStateClass.MEASUREMENT, |  | ||||||
|             native_unit_of_measurement=UnitOfTemperature.CELSIUS, |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="startProgram.energyLabel", |  | ||||||
|             name="Energy Label", |  | ||||||
|             icon="mdi:lightning-bolt-circle", |  | ||||||
|             state_class=SensorStateClass.MEASUREMENT, |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="startProgram.remainingTime", |  | ||||||
|             name="Time", |  | ||||||
|             icon="mdi:timer", |  | ||||||
|             state_class=SensorStateClass.MEASUREMENT, |  | ||||||
|             native_unit_of_measurement=UnitOfTime.MINUTES, |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|         SensorEntityDescription( |  | ||||||
|             key="machMode", |  | ||||||
|             name="Machine Status", |  | ||||||
|             icon="mdi:information", |  | ||||||
|             translation_key="mode_dw", |  | ||||||
|         ), |  | ||||||
|         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, |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 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.unique_id in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.unique_id] = 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,216 +0,0 @@ | |||||||
| 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.parameter.range import HonParameterRange |  | ||||||
|  |  | ||||||
| from .const import DOMAIN |  | ||||||
| from .hon import HonCoordinator, HonEntity |  | ||||||
|  |  | ||||||
| _LOGGER = logging.getLogger(__name__) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass |  | ||||||
| class HonSwitchEntityDescriptionMixin: |  | ||||||
|     turn_on_key: str = "" |  | ||||||
|     turn_off_key: str = "" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @dataclass |  | ||||||
| class HonSwitchEntityDescription( |  | ||||||
|     HonSwitchEntityDescriptionMixin, SwitchEntityDescription |  | ||||||
| ): |  | ||||||
|     pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { |  | ||||||
|     "WM": ( |  | ||||||
|         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", |  | ||||||
|         ), |  | ||||||
|         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", |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
|     "DW": ( |  | ||||||
|         HonSwitchEntityDescription( |  | ||||||
|             key="active", |  | ||||||
|             name="Dish Washer", |  | ||||||
|             icon="mdi:dishwasher", |  | ||||||
|             turn_on_key="startProgram", |  | ||||||
|             turn_off_key="stopProgram", |  | ||||||
|         ), |  | ||||||
|         HonSwitchEntityDescription( |  | ||||||
|             key="startProgram.extraDry", |  | ||||||
|             name="Extra Dry", |  | ||||||
|             icon="mdi:hair-dryer", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|         HonSwitchEntityDescription( |  | ||||||
|             key="startProgram.halfLoad", |  | ||||||
|             name="Half Load", |  | ||||||
|             icon="mdi:fraction-one-half", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|         HonSwitchEntityDescription( |  | ||||||
|             key="startProgram.openDoor", |  | ||||||
|             name="Open Door", |  | ||||||
|             icon="mdi:door-open", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|         HonSwitchEntityDescription( |  | ||||||
|             key="startProgram.threeInOne", |  | ||||||
|             name="Three in One", |  | ||||||
|             icon="mdi:numeric-3-box-outline", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|         HonSwitchEntityDescription( |  | ||||||
|             key="startProgram.ecoExpress", |  | ||||||
|             name="Eco Express", |  | ||||||
|             icon="mdi:sprout", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|         HonSwitchEntityDescription( |  | ||||||
|             key="startProgram.addDish", |  | ||||||
|             name="Add Dish", |  | ||||||
|             icon="mdi:silverware-fork-knife", |  | ||||||
|             entity_category=EntityCategory.CONFIG, |  | ||||||
|         ), |  | ||||||
|     ), |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 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.unique_id in coordinators: |  | ||||||
|             coordinator = hass.data[DOMAIN]["coordinators"][device.unique_id] |  | ||||||
|         else: |  | ||||||
|             coordinator = HonCoordinator(hass, device) |  | ||||||
|             hass.data[DOMAIN]["coordinators"][device.unique_id] = coordinator |  | ||||||
|         await coordinator.async_config_entry_first_refresh() |  | ||||||
|  |  | ||||||
|         if descriptions := SWITCHES.get(device.appliance_type): |  | ||||||
|             for description in descriptions: |  | ||||||
|                 if ( |  | ||||||
|                     device.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) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonSwitchEntity(HonEntity, SwitchEntity): |  | ||||||
|     entity_description: HonSwitchEntityDescription |  | ||||||
|  |  | ||||||
|     def __init__( |  | ||||||
|         self, |  | ||||||
|         hass, |  | ||||||
|         coordinator, |  | ||||||
|         entry, |  | ||||||
|         device: HonAppliance, |  | ||||||
|         description: HonSwitchEntityDescription, |  | ||||||
|     ) -> None: |  | ||||||
|         super().__init__(hass, entry, coordinator, device) |  | ||||||
|         self._coordinator = coordinator |  | ||||||
|         self._device = device |  | ||||||
|         self.entity_description = description |  | ||||||
|         self._attr_unique_id = f"{super().unique_id}{description.key}" |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def is_on(self) -> bool | None: |  | ||||||
|         """Return True if entity is on.""" |  | ||||||
|         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) |  | ||||||
|  |  | ||||||
|     async def async_turn_on(self, **kwargs: Any) -> None: |  | ||||||
|         if self.entity_category == EntityCategory.CONFIG: |  | ||||||
|             setting = self._device.settings[self.entity_description.key] |  | ||||||
|             setting.value = ( |  | ||||||
|                 setting.max if isinstance(setting, HonParameterRange) else "1" |  | ||||||
|             ) |  | ||||||
|             self.async_write_ha_state() |  | ||||||
|         else: |  | ||||||
|             await self._device.commands[self.entity_description.turn_on_key].send() |  | ||||||
|  |  | ||||||
|     async def async_turn_off(self, **kwargs: Any) -> None: |  | ||||||
|         if self.entity_category == EntityCategory.CONFIG: |  | ||||||
|             setting = self._device.settings[self.entity_description.key] |  | ||||||
|             setting.value = ( |  | ||||||
|                 setting.min if isinstance(setting, HonParameterRange) else "0" |  | ||||||
|             ) |  | ||||||
|             self.async_write_ha_state() |  | ||||||
|         else: |  | ||||||
|             await self._device.commands[self.entity_description.turn_off_key].send() |  | ||||||
| @ -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,583 +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" |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|       "mode_dw": { |  | ||||||
|         "state": { |  | ||||||
|           "0": "Disconnected", |  | ||||||
|           "1": "Ready", |  | ||||||
|           "2": "Running", |  | ||||||
|           "3": "Delayed start", |  | ||||||
|           "5": "Delayed start cancelled", |  | ||||||
|           "7": "Finished" |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "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", |  | ||||||
|           "bakery": "Pasta and Pastries", |  | ||||||
|           "bakery_steam": "Steam-baked bread", |  | ||||||
|           "bottom_heating": "Bottom Heating", |  | ||||||
|           "bottom_heating_fan": "Bottom Heating + Fan", |  | ||||||
|           "bread": "Bread", |  | ||||||
|           "bread_steam": "Steam-baked pastries", |  | ||||||
|           "combi": "Combi", |  | ||||||
|           "convection_fan": "Convection + Fan", |  | ||||||
|           "convection_fan_turnspit": "Convection + Fan + Turnspit", |  | ||||||
|           "conventional": "Conventional", |  | ||||||
|           "conventional_turnspit": "Convection + Turnspit", |  | ||||||
|           "defrost": "Defrost", |  | ||||||
|           "descaling": "Descaling", |  | ||||||
|           "fish": "Fish", |  | ||||||
|           "fish_steam": "Steam-cooked fish", |  | ||||||
|           "grill_cata": "Grill", |  | ||||||
|           "grill_fan_cata": "Grill fan", |  | ||||||
|           "grill_fan_pyro": "Grill + Fan", |  | ||||||
|           "grill_pyro": "Grill", |  | ||||||
|           "h20_clean": "H2O-Clean", |  | ||||||
|           "iot_bread": "Bread", |  | ||||||
|           "iot_h20_clean": "h2O clean", |  | ||||||
|           "leavening": "Leavening", |  | ||||||
|           "light_fan": "Light Fan", |  | ||||||
|           "low_temp_cooking": "Low Temperature Cooking", |  | ||||||
|           "low_temp_cooking_fish": "Low Temperature Cooking - Fish", |  | ||||||
|           "low_temp_cooking_fish_steam": "Low Temperature Steam Cooking - Fish", |  | ||||||
|           "low_temp_cooking_meat": "Low Temperature Cooking - Meat", |  | ||||||
|           "low_temp_cooking_meat_steam": "Low Temperature Steam Cooking - Meat", |  | ||||||
|           "low_temp_cooking_steam": "Low Temperature Steam Cooking", |  | ||||||
|           "meat": "Meat", |  | ||||||
|           "meat_steam": "Steam-cooked meat", |  | ||||||
|           "multi_level": "Multi-Level", |  | ||||||
|           "paella": "Paella", |  | ||||||
|           "pasta_and_bakery": "Pasta and Bakery", |  | ||||||
|           "pizza": "Pizza", |  | ||||||
|           "pyrolysis": "Pyrolysis", |  | ||||||
|           "pyrolysis_plus": "Pyrolysis +", |  | ||||||
|           "red_meat": "Red Meat", |  | ||||||
|           "red_meat_steam": "Steam-cooked red meat", |  | ||||||
|           "regenerate": "Regeneration", |  | ||||||
|           "soft_plus": "Soft+", |  | ||||||
|           "super_grill": "Super Grill", |  | ||||||
|           "tailor_bake": "Tailor bake", |  | ||||||
|           "tailor_bake_cata": "Tailor Bake", |  | ||||||
|           "tailor_bake_pyro": "Tailor Bake", |  | ||||||
|           "vegetables": "Vegetables", |  | ||||||
|           "vegetables_cata": "Vegetables", |  | ||||||
|           "vegetables_pyro": "Vegetables", |  | ||||||
|           "water_discharge": "Water Drain", |  | ||||||
|           "white_meat": "White Meat", |  | ||||||
|           "white_meat_steam": "Steam-cooked white meat", |  | ||||||
|           "iot_standard_boiling": "Boiling", |  | ||||||
|           "iot_standard_frying": "Frying", |  | ||||||
|           "iot_standard_keep_warm": "Keep Warm", |  | ||||||
|           "iot_standard_melting": "Melting", |  | ||||||
|           "iot_standard_simmering": "Simmering" |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|       "programs_dw": { |  | ||||||
|         "state": { |  | ||||||
|           "59_min": "Rapid 59'", |  | ||||||
|           "auto_care": "Auto Care", |  | ||||||
|           "auto_care_soil": "Auto Care", |  | ||||||
|           "auto_hygiene": "Auto Hygiene", |  | ||||||
|           "auto_plus": "AutoPlus", |  | ||||||
|           "auto_rapid": "Auto Rapid", |  | ||||||
|           "auto_sensor": "Auto Sensor", |  | ||||||
|           "auto_sensor_soil": "Auto Sensor", |  | ||||||
|           "auto_universal": "Auto Universal 50 - 60°C", |  | ||||||
|           "auto_universal_plus": "Auto Universal+ 65 - 75°C", |  | ||||||
|           "auto_universal_plus_soil": "Auto Universal+ 65 - 75°C", |  | ||||||
|           "auto_universal_soil": "Auto Universal 50 - 60°C", |  | ||||||
|           "auto_wash": "Auto Wash", |  | ||||||
|           "auto_wash_soil": "Auto Wash", |  | ||||||
|           "classe_a_59": "A Wash 59' 65°C", |  | ||||||
|           "delicate": "Delicate 45°C", |  | ||||||
|           "dishwasher_care": "Limescale cleaning", |  | ||||||
|           "eco": "Eco", |  | ||||||
|           "eco_asynch": "Eco 45°C", |  | ||||||
|           "eco_bldc": "Eco 45°C", |  | ||||||
|           "eco_synch": "Eco 45°C", |  | ||||||
|           "gentle_wash": "Gentle wash", |  | ||||||
|           "glass": "Glass", |  | ||||||
|           "glassware": "Glassware 45°C", |  | ||||||
|           "glass_care": "Glass Care", |  | ||||||
|           "hygiene": "Hygiene", |  | ||||||
|           "hygiene_plus": "Hygiene+ 75°C", |  | ||||||
|           "intensive": "Intensive", |  | ||||||
|           "intensive_rapid": "Intensive Rapid", |  | ||||||
|           "iot_auto_sensor": "Auto Sensor", |  | ||||||
|           "iot_auto_universal_soil": "Auto Universal 50 - 60°C", |  | ||||||
|           "iot_auto_wash_soil": "Auto Wash", |  | ||||||
|           "iot_baby_care": "Baby Care", |  | ||||||
|           "iot_breakfast": "Breakfast", |  | ||||||
|           "iot_checkup": "Check-Up", |  | ||||||
|           "iot_china_crystals": "China Crystals", |  | ||||||
|           "iot_classe_a_59": "Rapid 59'", |  | ||||||
|           "iot_cocktail_glasses": "Coktail Glasses", |  | ||||||
|           "iot_cocktail_glasses_soil": "Coktail Glasses", |  | ||||||
|           "iot_daily_care": "Daily Care", |  | ||||||
|           "iot_daily_care_soil": "Daily Care", |  | ||||||
|           "iot_delicate": "Delicate 45°C", |  | ||||||
|           "iot_dinner_for_two": "Dinner for 2", |  | ||||||
|           "iot_dinner_for_two_soil": "Dinner for 2", |  | ||||||
|           "iot_dreft_quick_cycle": "Dreft Quick", |  | ||||||
|           "iot_eco_asynch": "Eco 45°C", |  | ||||||
|           "iot_eco_bldc": "Eco 45°C", |  | ||||||
|           "iot_eco_synch": "Eco 45°C", |  | ||||||
|           "iot_extra_hygiene": "Extra Hygiene", |  | ||||||
|           "iot_fairy_quick_cycle": "Fairy Short", |  | ||||||
|           "iot_happy_hour": "Happy Hour", |  | ||||||
|           "iot_jar_quick_cycle": "Jar Quick", |  | ||||||
|           "iot_party": "Party", |  | ||||||
|           "iot_party_soil": "Party", |  | ||||||
|           "iot_pizza_menu": "Pizza Menu", |  | ||||||
|           "iot_pizza_menu_soil": "Pizza Menu", |  | ||||||
|           "iot_plastic_tupperware": "Plastic & Tupperware", |  | ||||||
|           "iot_porcelain": "Porcelain", |  | ||||||
|           "iot_pot_and_pans": "Pot & Pans", |  | ||||||
|           "iot_pot_and_pans_soil": "Pot & Pans", |  | ||||||
|           "iot_power_mix_wash": "Power Mix Wash", |  | ||||||
|           "iot_power_mix_wash_soil": "Power Mix Wash", |  | ||||||
|           "iot_prewash": "Pre-wash", |  | ||||||
|           "iot_pyrex_and_glassware": "Pyrex & Glassware", |  | ||||||
|           "iot_rapid_29": "Rapid 29'", |  | ||||||
|           "iot_rapid_39": "Rapid 39' 60°C", |  | ||||||
|           "iot_single": "Single", |  | ||||||
|           "iot_steam": "Steam 75°C", |  | ||||||
|           "iot_super_flash": "Super Flash", |  | ||||||
|           "iot_super_wash": "Super Wash", |  | ||||||
|           "iot_turbopower": "TurboPower", |  | ||||||
|           "iot_universal": "Universal 60°C", |  | ||||||
|           "iot_wok_grids_maxi_pans": "Special Pans (Wok, Grids & Maxi Pans)", |  | ||||||
|           "iot_wok_grids_maxi_pans_soil": "Special Pans (Wok, Grids & Maxi Pans)", |  | ||||||
|           "iot_yes_quick_cycle": "Yes Quick", |  | ||||||
|           "night": "Night 55°C", |  | ||||||
|           "prewash": "Pre-wash", |  | ||||||
|           "rapid_20": "Rapid 20'", |  | ||||||
|           "rapid_24": "Rapid 24'", |  | ||||||
|           "rapid_29": "Rapid 29' 50°C", |  | ||||||
|           "rapid_35": "Wash&Dry 35'", |  | ||||||
|           "rapid_39": "Rapid 39' 60°C", |  | ||||||
|           "rapid_49": "Rapid 49'", |  | ||||||
|           "rapid_59": "Rapid 59'", |  | ||||||
|           "sanitising": "Sanitising", |  | ||||||
|           "silence": "Silence", |  | ||||||
|           "silent": "Silent", |  | ||||||
|           "silent_care": "Silent Care", |  | ||||||
|           "smart_ai": "Smart AI", |  | ||||||
|           "smart_ai_pro": "Smart AI Pro", |  | ||||||
|           "smart_ai_rapid": "Smart AI Rapid", |  | ||||||
|           "special": "Special", |  | ||||||
|           "special_pw_prz": "Special", |  | ||||||
|           "steam": "Steam 75°C", |  | ||||||
|           "steam_plus": "Steam Plus 75°C", |  | ||||||
|           "total_care": "Total Care 50°C", |  | ||||||
|           "ultra_silence": "Ultra Silence 55°C", |  | ||||||
|           "ultra_silent": "Ultra Silent 55°C", |  | ||||||
|           "universal": "Universal 60°C", |  | ||||||
|           "universal_plus": "Universal Plus 70°C", |  | ||||||
|           "zone_wash": "Flex Zone Wash", |  | ||||||
|           "zoom_39": "Zoom 39 min" |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,6 +1,5 @@ | |||||||
| { | { | ||||||
|     "name": "Haier hOn", |     "name": "Haier hOn", | ||||||
|     "homeassistant": "2023.2.0", |     "render_readme": true, | ||||||
|     "zip_release": true, |     "homeassistant": "2023.2.0" | ||||||
|     "filename": "haier_hon.zip" |  | ||||||
| } | } | ||||||
							
								
								
									
										40
									
								
								info.md
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								info.md
									
									
									
									
									
								
							| @ -1,40 +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 |  | ||||||
| - Hob |  | ||||||
|  |  | ||||||
| ## 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! |  | ||||||
|  |  | ||||||
| ## Useful Links |  | ||||||
|  |  | ||||||
| * [GitHub repository](https://github.com/Andre0512/hon) (please add a star if you like this integration!) |  | ||||||
| * [pyhOn library](https://github.com/Andre0512/pyhOn) |  | ||||||
| * [Release notes](https://github.com/Andre0512/hon/releases) |  | ||||||
| * [Discussion and help](https://github.com/Andre0512/hon/discussions) |  | ||||||
| * [Issues](https://github.com/Andre0512/hon/issues) |  | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user
	