diff --git a/README.md b/README.md
index 48ba375..85eb1a1 100644
--- a/README.md
+++ b/README.md
@@ -61,42 +61,18 @@ Translation of internal names like programs are available for all languages whic
## Supported Models
Support has been confirmed for these models, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8).
-- Haier AD105S2SM3FA
-- Haier AS20HPL1HRA
-- Haier AS25PBAHRA
-- Haier AS25S2SF1FA-WH
-- Haier AS25TADHRA-2
-- Haier AS35TADHRA-2
-- Haier EG9012B19SU1JD
-- Haier HA2MTSJ68MC
-- Haier HADG6DS46BWIFI
-- Haier HD80-A3959
-- Haier HW90-B14TEAM5
-- Haier HW100-B14959U1
-- Haier HWD100-B14979
-- Haier HWO60SM2F3XH
-- Haier XIB 3B2SFS-80
-- Haier XIB 6B2D3FB
-- Candy BCTDH7A1TE
-- Candy CCE4T620EWU
-- Candy CIS633SCTTWIFI
-- Candy CSOE C10DE-80
-- Candy RO44 1286DWMC4-07
-- Candy ROE H9A3TCEX-S
-- Candy RPW41066BWMR/1-S
-- Hoover H-WASH 500
-- Hoover H-DRY 500
-- Hoover H7W4 48MBC-S
-- Hoover H9A3TCBEXS-S
-- Hoover HFB 6B2S3FX
-- Hoover HLE C10DCE-80
-- Hoover HSOT3161WG
-- Hoover HW 68AMC/1-80
-- Hoover HWPD 69AMBC/1-S
-- Hoover HWPS4954DAMR-11
-- Hoover NDE H10A2TCE-80
-- Hoover NDE H9A2TSBEXS-S
-- Hoover NDPHY10A2TCBEXSS
+
+| | **Haier** | **Hoover** | **Candy** |
+|--------------------|------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------|
+| **Washing Machine** | HW90-B14TEAM5
HW100-B14959U1 | H-WASH 500
H7W4 48MBC-S | RO44 1286DWMC4-07
HW 68AMC/1-80
HWPD 69AMBC/1-S |
+| **Tumble Dryer** | HD80-A3959 | H-DRY 500
H9A3TCBEXS-S
HLE C10DCE-80
NDE H10A2TCE-80
NDE H9A2TSBEXS-S
NDPHY10A2TCBEXSS | BCTDH7A1TE
CSOE C10DE-80
ROE H9A3TCEX-S |
+| **Washer Dryer** | HWD100-B14979 | HWPS4954DAMR-11 | RPW41066BWMR/1-S |
+| **Oven** | HWO60SM2F3XH | HSOT3161WG | |
+| **Dish Washer** | XIB 3B2SFS-80
XIB 6B2D3FB | HFB 6B2S3FX | |
+| **Air conditioner** | AD105S2SM3FA
AS20HPL1HRA
AS25PBAHRA
AS25S2SF1FA-WH
AS25TADHRA-2
AS35TADHRA-2
| | |
+| **Fridge** | HFW7720ENMB | | CCE4T620EWU |
+| **Hob** | HA2MTSJ68MC | | CIS633SCTTWIFI |
+| **Hood** | HADG6DS46BWIFI | | |
## Contribute
Any kind of contribution is welcome!
@@ -237,11 +213,11 @@ For every device exists a hidden button which can be used to log all infos of yo
| --- | --- | --- | --- |
| Start Program | `hvac` | `button` | `startProgram` |
| Stop Program | `hvac-off` | `button` | `stopProgram` |
+| Wind Speed | | `fan` | `settings.windSpeed` |
#### Configs
| Name | Icon | Entity | Key |
| --- | --- | --- | --- |
| Light status | `lightbulb` | `number` | `startProgram.lightStatus` |
-| Wind speed | `fan` | `number` | `startProgram.windSpeed` |
#### Sensors
| Name | Icon | Entity | Key |
| --- | --- | --- | --- |
@@ -257,7 +233,6 @@ For every device exists a hidden button which can be used to log all infos of yo
| Quick Delay Time Status | | `sensor` | `quickDelayTimeStatus` |
| RGB Light Color | `lightbulb` | `sensor` | `rgbLightColors` |
| RGB Light Status | `lightbulb` | `sensor` | `rgbLightStatus` |
-| Wind Speed | `fan` | `sensor` | `windSpeed` |
### Hob
#### Controls
diff --git a/custom_components/hon/climate.py b/custom_components/hon/climate.py
index 5c5fa2a..c8fd587 100644
--- a/custom_components/hon/climate.py
+++ b/custom_components/hon/climate.py
@@ -213,7 +213,7 @@ class HonACClimateEntity(HonEntity, ClimateEntity):
class HonClimateEntity(HonEntity, ClimateEntity):
- entity_description = HonClimateEntityDescription
+ entity_description: HonClimateEntityDescription
def __init__(self, hass, entry, device: HonAppliance, description) -> None:
super().__init__(hass, entry, device, description)
diff --git a/custom_components/hon/const.py b/custom_components/hon/const.py
index 1a2d022..5c89ef4 100644
--- a/custom_components/hon/const.py
+++ b/custom_components/hon/const.py
@@ -17,6 +17,7 @@ PLATFORMS = [
"button",
"binary_sensor",
"climate",
+ "fan",
]
HON_HVAC_MODE = {
diff --git a/custom_components/hon/fan.py b/custom_components/hon/fan.py
new file mode 100644
index 0000000..80e3251
--- /dev/null
+++ b/custom_components/hon/fan.py
@@ -0,0 +1,122 @@
+import logging
+import math
+from dataclasses import dataclass
+from typing import Any
+
+from homeassistant.components.fan import (
+ FanEntityDescription,
+ FanEntity,
+ FanEntityFeature,
+)
+from homeassistant.config_entries import ConfigEntry
+from homeassistant.core import callback
+from homeassistant.util.percentage import (
+ percentage_to_ranged_value,
+ ranged_value_to_percentage,
+)
+from pyhon.appliance import HonAppliance
+from pyhon.parameter.range import HonParameterRange
+
+from .const import DOMAIN
+from .hon import HonEntity
+
+_LOGGER = logging.getLogger(__name__)
+
+
+@dataclass
+class HonFanEntityDescription(FanEntityDescription):
+ pass
+
+
+FANS = {
+ "HO": (
+ HonFanEntityDescription(
+ key="settings.windSpeed",
+ name="Wind Speed",
+ translation_key="air_extraction",
+ ),
+ ),
+}
+
+
+async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None:
+ entities = []
+ for device in hass.data[DOMAIN][entry.unique_id].appliances:
+ for description in FANS.get(device.appliance_type, []):
+ if isinstance(description, HonFanEntityDescription):
+ if description.key not in device.available_settings or not device.get(
+ description.key.split(".")[-1]
+ ):
+ continue
+ entity = HonFanEntity(hass, entry, device, description)
+ else:
+ continue
+ await entity.coordinator.async_config_entry_first_refresh()
+ entities.append(entity)
+ async_add_entities(entities)
+
+
+class HonFanEntity(HonEntity, FanEntity):
+ entity_description: HonFanEntityDescription
+
+ def __init__(self, hass, entry, device: HonAppliance, description) -> None:
+ self._attr_supported_features = FanEntityFeature.SET_SPEED
+ self._wind_speed: HonParameterRange = device.settings.get(description.key)
+ self._speed_range = (
+ int(self._wind_speed.values[1]),
+ int(self._wind_speed.values[-1]),
+ )
+ self._command, self._parameter = description.key.split(".")
+
+ super().__init__(hass, entry, device, description)
+ self._handle_coordinator_update(update=False)
+
+ @property
+ def percentage(self) -> int | None:
+ """Return the current speed."""
+ value = int(self._device.get(self._parameter, "0"))
+ return ranged_value_to_percentage(self._speed_range, value)
+
+ @property
+ def speed_count(self) -> int:
+ """Return the number of speeds the fan supports."""
+ return len(self._wind_speed.values[1:])
+
+ async def async_set_percentage(self, percentage: int) -> None:
+ """Set the speed percentage of the fan."""
+ mode = math.ceil(percentage_to_ranged_value(self._speed_range, percentage))
+ self._device.settings[self.entity_description.key].value = mode
+ await self._device.commands[self._command].send()
+ self.async_write_ha_state()
+
+ @property
+ def is_on(self) -> bool | None:
+ """Return true if device is on."""
+ mode = math.ceil(percentage_to_ranged_value(self._speed_range, self.percentage))
+ return mode > self._wind_speed.min
+
+ async def async_turn_on(
+ self,
+ percentage: int | None = None,
+ preset_mode: str | None = None,
+ **kwargs: Any,
+ ) -> None:
+ """Turn the entity on."""
+ if percentage is None:
+ percentage = ranged_value_to_percentage(
+ self._speed_range, int(self._wind_speed.values[1])
+ )
+ await self.async_set_percentage(percentage)
+
+ async def async_turn_off(self, **kwargs: Any) -> None:
+ """Turn the entity off."""
+ self._device.settings[self.entity_description.key].value = 0
+ await self._device.commands[self._command].send()
+ self.async_write_ha_state()
+
+ @callback
+ def _handle_coordinator_update(self, update=True) -> None:
+ self._wind_speed = self._device.settings.get(self.entity_description.key)
+ self._attr_percentage = self.percentage
+ if update:
+ self.async_write_ha_state()
diff --git a/custom_components/hon/number.py b/custom_components/hon/number.py
index cd9f182..43f3761 100644
--- a/custom_components/hon/number.py
+++ b/custom_components/hon/number.py
@@ -163,12 +163,6 @@ NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = {
),
),
"HO": (
- HonNumberEntityDescription(
- key="startProgram.windSpeed",
- name="Wind speed",
- icon="mdi:fan",
- entity_category=EntityCategory.CONFIG,
- ),
HonNumberEntityDescription(
key="startProgram.lightStatus",
name="Light status",
diff --git a/custom_components/hon/sensor.py b/custom_components/hon/sensor.py
index 58eddd5..7de75f9 100644
--- a/custom_components/hon/sensor.py
+++ b/custom_components/hon/sensor.py
@@ -593,11 +593,6 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = {
name="RGB Light Status",
icon="mdi:lightbulb",
),
- HonSensorEntityDescription(
- key="windSpeed",
- name="Wind Speed",
- icon="mdi:fan",
- ),
),
}
SENSORS["WD"] = unique_entities(SENSORS["WM"], SENSORS["TD"])
diff --git a/custom_components/hon/translations/cs.json b/custom_components/hon/translations/cs.json
index b4b0174..32d551d 100644
--- a/custom_components/hon/translations/cs.json
+++ b/custom_components/hon/translations/cs.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Odsávání vzduchu"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/de.json b/custom_components/hon/translations/de.json
index 1e5de11..3948c4c 100644
--- a/custom_components/hon/translations/de.json
+++ b/custom_components/hon/translations/de.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Dunstabzug"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/el.json b/custom_components/hon/translations/el.json
index 8b44d1d..67ea26c 100644
--- a/custom_components/hon/translations/el.json
+++ b/custom_components/hon/translations/el.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Εξαγωγή αέρα"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/en.json b/custom_components/hon/translations/en.json
index 40ee14b..865947d 100644
--- a/custom_components/hon/translations/en.json
+++ b/custom_components/hon/translations/en.json
@@ -2056,6 +2056,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Air extraction"
+ }
}
}
}
\ No newline at end of file
diff --git a/custom_components/hon/translations/es.json b/custom_components/hon/translations/es.json
index d328fb1..716bef3 100644
--- a/custom_components/hon/translations/es.json
+++ b/custom_components/hon/translations/es.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Extracción de aire"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/fr.json b/custom_components/hon/translations/fr.json
index c114d0e..c8bef75 100644
--- a/custom_components/hon/translations/fr.json
+++ b/custom_components/hon/translations/fr.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Extraction de l'air"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/he.json b/custom_components/hon/translations/he.json
index 95543ba..9a735c9 100644
--- a/custom_components/hon/translations/he.json
+++ b/custom_components/hon/translations/he.json
@@ -1065,6 +1065,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Air extraction"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/hr.json b/custom_components/hon/translations/hr.json
index cf4a912..56f91e6 100644
--- a/custom_components/hon/translations/hr.json
+++ b/custom_components/hon/translations/hr.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Odvođenje zraka"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/it.json b/custom_components/hon/translations/it.json
index 3528120..c1bfb25 100644
--- a/custom_components/hon/translations/it.json
+++ b/custom_components/hon/translations/it.json
@@ -2031,6 +2031,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Aspirazione aria"
+ }
}
}
}
\ No newline at end of file
diff --git a/custom_components/hon/translations/nl.json b/custom_components/hon/translations/nl.json
index 931ccd0..a8cd576 100644
--- a/custom_components/hon/translations/nl.json
+++ b/custom_components/hon/translations/nl.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Luchtafvoer"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/pl.json b/custom_components/hon/translations/pl.json
index 4ca0b36..a757390 100644
--- a/custom_components/hon/translations/pl.json
+++ b/custom_components/hon/translations/pl.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Wyciąg powietrza"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/pt.json b/custom_components/hon/translations/pt.json
index 0828ace..1e68672 100644
--- a/custom_components/hon/translations/pt.json
+++ b/custom_components/hon/translations/pt.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Extração de ar"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/ro.json b/custom_components/hon/translations/ro.json
index 496959f..8c55275 100644
--- a/custom_components/hon/translations/ro.json
+++ b/custom_components/hon/translations/ro.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Extracția aerului"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/ru.json b/custom_components/hon/translations/ru.json
index fda96d3..334f94d 100644
--- a/custom_components/hon/translations/ru.json
+++ b/custom_components/hon/translations/ru.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Отвод воздуха"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/sk.json b/custom_components/hon/translations/sk.json
index c362022..7828e6b 100644
--- a/custom_components/hon/translations/sk.json
+++ b/custom_components/hon/translations/sk.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Odsávanie vzduchu"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/sl.json b/custom_components/hon/translations/sl.json
index 9ecfb4a..e0b5fff 100644
--- a/custom_components/hon/translations/sl.json
+++ b/custom_components/hon/translations/sl.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Odvajanje zraka"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/sr.json b/custom_components/hon/translations/sr.json
index 0f6d151..7faaece 100644
--- a/custom_components/hon/translations/sr.json
+++ b/custom_components/hon/translations/sr.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Usisavanje vazduha"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/tr.json b/custom_components/hon/translations/tr.json
index 3ce58af..1c80588 100644
--- a/custom_components/hon/translations/tr.json
+++ b/custom_components/hon/translations/tr.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "Hava tahliyesi"
+ }
}
},
"config": {
diff --git a/custom_components/hon/translations/zh.json b/custom_components/hon/translations/zh.json
index 2dd5af7..199f7ff 100644
--- a/custom_components/hon/translations/zh.json
+++ b/custom_components/hon/translations/zh.json
@@ -1979,6 +1979,11 @@
}
}
}
+ },
+ "fan": {
+ "air_extraction": {
+ "name": "抽气"
+ }
}
},
"config": {
diff --git a/info.md b/info.md
index dd6d537..88d50e8 100644
--- a/info.md
+++ b/info.md
@@ -50,42 +50,18 @@ Translation of internal names like programs are available for all languages whic
## Supported Models
Support has been confirmed for these models, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8).
-- Haier AD105S2SM3FA
-- Haier AS20HPL1HRA
-- Haier AS25PBAHRA
-- Haier AS25S2SF1FA-WH
-- Haier AS25TADHRA-2
-- Haier AS35TADHRA-2
-- Haier EG9012B19SU1JD
-- Haier HA2MTSJ68MC
-- Haier HADG6DS46BWIFI
-- Haier HD80-A3959
-- Haier HW90-B14TEAM5
-- Haier HW100-B14959U1
-- Haier HWD100-B14979
-- Haier HWO60SM2F3XH
-- Haier XIB 3B2SFS-80
-- Haier XIB 6B2D3FB
-- Candy BCTDH7A1TE
-- Candy CCE4T620EWU
-- Candy CIS633SCTTWIFI
-- Candy CSOE C10DE-80
-- Candy RO44 1286DWMC4-07
-- Candy ROE H9A3TCEX-S
-- Candy RPW41066BWMR/1-S
-- Hoover H-WASH 500
-- Hoover H-DRY 500
-- Hoover H7W4 48MBC-S
-- Hoover H9A3TCBEXS-S
-- Hoover HFB 6B2S3FX
-- Hoover HLE C10DCE-80
-- Hoover HSOT3161WG
-- Hoover HW 68AMC/1-80
-- Hoover HWPD 69AMBC/1-S
-- Hoover HWPS4954DAMR-11
-- Hoover NDE H10A2TCE-80
-- Hoover NDE H9A2TSBEXS-S
-- Hoover NDPHY10A2TCBEXSS
+
+| | **Haier** | **Hoover** | **Candy** |
+|--------------------|------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------|
+| **Washing Machine** | HW90-B14TEAM5
HW100-B14959U1 | H-WASH 500
H7W4 48MBC-S | RO44 1286DWMC4-07
HW 68AMC/1-80
HWPD 69AMBC/1-S |
+| **Tumble Dryer** | HD80-A3959 | H-DRY 500
H9A3TCBEXS-S
HLE C10DCE-80
NDE H10A2TCE-80
NDE H9A2TSBEXS-S
NDPHY10A2TCBEXSS | BCTDH7A1TE
CSOE C10DE-80
ROE H9A3TCEX-S |
+| **Washer Dryer** | HWD100-B14979 | HWPS4954DAMR-11 | RPW41066BWMR/1-S |
+| **Oven** | HWO60SM2F3XH | HSOT3161WG | |
+| **Dish Washer** | XIB 3B2SFS-80
XIB 6B2D3FB | HFB 6B2S3FX | |
+| **Air conditioner** | AD105S2SM3FA
AS20HPL1HRA
AS25PBAHRA
AS25S2SF1FA-WH
AS25TADHRA-2
AS35TADHRA-2
| | |
+| **Fridge** | HFW7720ENMB | | CCE4T620EWU |
+| **Hob** | HA2MTSJ68MC | | CIS633SCTTWIFI |
+| **Hood** | HADG6DS46BWIFI | | |
## Contribute
Want to help us to support more appliances? Or add more sensors? Or help with translating? Or beautify some icons or captions?
diff --git a/scripts/generate_translation.py b/scripts/generate_translation.py
index 01164af..53d66bc 100755
--- a/scripts/generate_translation.py
+++ b/scripts/generate_translation.py
@@ -248,6 +248,7 @@ NAMES = {
"freezer": "REF.ZONES.FREEZER",
"oven": "GLOBALS.APPLIANCES_NAME.OV",
},
+ "fan": {"air_extraction": "HO.DASHBOARD.AIR_EXTRACTION_TITLE"},
}
diff --git a/scripts/sensor_docs.py b/scripts/sensor_docs.py
index 655dbf6..e009186 100755
--- a/scripts/sensor_docs.py
+++ b/scripts/sensor_docs.py
@@ -14,6 +14,7 @@ from custom_components.hon.climate import CLIMATES
from custom_components.hon.number import NUMBERS
from custom_components.hon.select import SELECTS
from custom_components.hon.sensor import SENSORS
+from custom_components.hon.fan import FANS
from custom_components.hon.switch import (
SWITCHES,
HonControlSwitchEntityDescription,
@@ -48,6 +49,7 @@ entities = {
"sensor": SENSORS,
"switch": SWITCHES,
"climate": CLIMATES,
+ "fan": FANS,
}
result = {}