diff --git a/.gitignore b/.gitignore index 6024b17..1dcccdc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ __pycache__/ -test.py +scripts/test.py .idea/ diff --git a/README.md b/README.md index 858567f..725f565 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,17 @@ # Haier hOn [![hacs_badge](https://img.shields.io/badge/HACS-Default-41BDF5.svg)](https://hacs.xyz) [![GitHub release (latest by date)](https://img.shields.io/github/v/release/Andre0512/hon?color=green)](https://github.com/Andre0512/hon/releases/latest) -![GitHub](https://img.shields.io/github/license/Andre0512/hon?color=red) -[![Home Assistant installs](https://img.shields.io/badge/dynamic/json?color=blue&label=usage&suffix=%20installs&cacheSeconds=15600&url=https://analytics.home-assistant.io/custom_integrations.json&query=$.hon.total)](https://analytics.home-assistant.io/) +[![GitHub](https://img.shields.io/github/license/Andre0512/hon?color=red)](https://github.com/Andre0512/hon/blob/main/LICENSE) +[![GitHub all releases](https://img.shields.io/github/downloads/Andre0512/hon/total?color=blue)](https://tooomm.github.io/github-release-stats/?username=Andre0512&repository=hon) Home Assistant integration for Haier hOn: support for Haier/Candy/Hoover home appliances like washing machines. + ## Supported Appliances -- Tumble Dryer -- Washer Dryer -- Washing Machine -- Oven -- Hob +- [Washing Machine](https://github.com/Andre0512/hon#washing-machine) +- [Tumble Dryer](https://github.com/Andre0512/hon#tumble-dryer) +- [Washer Dryer](https://github.com/Andre0512/hon#washer-dryer) +- [Oven](https://github.com/Andre0512/hon#oven) +- [Hob](https://github.com/Andre0512/hon#hob) +- [Dish Washer](https://github.com/Andre0512/hon#dish-washer) ## Installation **Method 1:** [![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=Andre0512&repository=hon&category=integration) @@ -27,8 +29,6 @@ _Restart Home Assistant_ **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 @@ -98,8 +98,199 @@ For every device exists a hidden button which can be used to log all info of you - Haier HD80-A3959 - Haier HWO60SM2F3XH - Hoover H-WASH 500 +- Candy CIS633SCTTWIFI +- Haier XIB 3B2SFS-80 +- Haier XIB 6B2D3FB ## About this Repo The existing integrations missed some features from the app I liked to have in HomeAssistant. I tried to create a pull request, but in the structures of these existing repos, I find it hard to fit in my needs, so I basically rewrote everything. I moved the api related stuff into the package [pyhOn](https://github.com/Andre0512/pyhOn). + +## Appliance Features + +### Dish washer +#### Controls +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Dish Washer | `mdi:dishwasher` | `switch` | `startProgram` / `stopProgram` | +#### Configs +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Add Dish | `mdi:silverware-fork-knife` | `switch` | `startProgram.addDish` | +| Delay time | `mdi:timer-plus` | `number` | `startProgram.delayTime` | +| Eco Express | `mdi:sprout` | `switch` | `startProgram.ecoExpress` | +| Eco Index | `mdi:sprout` | `sensor` | `startProgram.ecoIndex` | +| Energy Label | `mdi:lightning-bolt-circle` | `sensor` | `startProgram.energyLabel` | +| Extra Dry | `mdi:hair-dryer` | `switch` | `startProgram.extraDry` | +| Half Load | `mdi:fraction-one-half` | `switch` | `startProgram.halfLoad` | +| Open Door | `mdi:door-open` | `switch` | `startProgram.openDoor` | +| Program | | `select` | `startProgram.program` | +| Temperature | `mdi:thermometer` | `sensor` | `startProgram.temp` | +| Three in One | `mdi:numeric-3-box-outline` | `switch` | `startProgram.threeInOne` | +| Time | `mdi:timer` | `sensor` | `startProgram.remainingTime` | +| Water Efficiency | `mdi:water` | `sensor` | `startProgram.waterEfficiency` | +| Water Saving | `mdi:water-percent` | `sensor` | `startProgram.waterSaving` | +| Water hard | `mdi:water` | `number` | `startProgram.waterHard` | +#### Sensors +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Connection | | `binary_sensor` | `attributes.lastConnEvent.category` | +| Door | | `binary_sensor` | `doorStatus` | +| Error | `mdi:math-log` | `sensor` | `errors` | +| Machine Status | `mdi:information` | `sensor` | `machMode` | +| Remaining Time | `mdi:timer` | `sensor` | `remainingTimeMM` | +| Rinse Aid | `mdi:spray-bottle` | `binary_sensor` | `rinseAidStatus` | +| Salt | `mdi:shaker-outline` | `binary_sensor` | `saltStatus` | + +### Hob +#### Controls +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Start Program | `mdi:pot-steam` | `button` | `startProgram` | +#### Configs +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Power Management | `mdi:timelapse` | `number` | `startProgram.powerManagement` | +| Program | | `select` | `startProgram.program` | +| Temperature | `mdi:thermometer` | `number` | `startProgram.temp` | +#### Sensors +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Connection | `mdi:wifi` | `binary_sensor` | `attributes.lastConnEvent.category` | +| Error | `mdi:math-log` | `sensor` | `errors` | +| Hob Lock | | `binary_sensor` | `hobLockStatus` | +| Hot Status | | `binary_sensor` | `hotStatus` | +| On | `mdi:power-cycle` | `binary_sensor` | `attributes.parameters.onOffStatus` | +| Pan Status | `mdi:pot-mix` | `binary_sensor` | `panStatus` | +| Power | `mdi:lightning-bolt` | `sensor` | `power` | +| Remaining Time | `mdi:timer` | `sensor` | `remainingTimeMM` | +| Remote Control | `mdi:remote` | `binary_sensor` | `attributes.parameters.remoteCtrValid` | +| Temperature | `mdi:thermometer` | `sensor` | `temp` | + +### Oven +#### Controls +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Start Program | `mdi:power-cycle` | `button` | `startProgram` | +| Stop Program | `mdi:power-off` | `button` | `stopProgram` | +#### Configs +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Delay time | `mdi:timer-plus` | `number` | `startProgram.delayTime` | +| Preheat | | `select` | `startProgram.preheatStatus` | +| Program | | `select` | `startProgram.program` | +| Program Duration | `mdi:timelapse` | `number` | `startProgram.prTime` | +| Target Temperature | `mdi:thermometer` | `number` | `startProgram.tempSel` | +#### Sensors +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Connection | `mdi:wifi` | `binary_sensor` | `attributes.lastConnEvent.category` | +| On | `mdi:power-cycle` | `binary_sensor` | `attributes.parameters.onOffStatus` | +| Remaining Time | `mdi:timer` | `sensor` | `remainingTimeMM` | +| Remote Control | `mdi:remote` | `binary_sensor` | `attributes.parameters.remoteCtrValid` | +| Start Time | `mdi:clock-start` | `sensor` | `delayTime` | +| Temperature | `mdi:thermometer` | `sensor` | `temp` | +| Temperature Selected | `mdi:thermometer` | `sensor` | `tempSel` | + +### Tumble dryer +#### Controls +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Pause Tumble Dryer | `mdi:pause` | `switch` | `pauseProgram` / `resumeProgram` | +| Tumble Dryer | `mdi:tumble-dryer` | `switch` | `startProgram` / `stopProgram` | +#### Configs +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Anti-Crease time | `mdi:timer` | `number` | `startProgram.antiCreaseTime` | +| Delay time | `mdi:timer-plus` | `number` | `startProgram.delayTime` | +| Dry level | `mdi:hair-dryer` | `number` | `startProgram.dryLevel` | +| Program | | `select` | `startProgram.program` | +| Sterilization status | `mdi:clock-start` | `number` | `startProgram.sterilizationStatus` | +| Temperature level | `mdi:thermometer` | `number` | `startProgram.tempLevel` | +| Time | `mdi:timer` | `select` | `startProgram.dryTimeMM` | +#### Sensors +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Connection | | `binary_sensor` | `attributes.lastConnEvent.category` | +| Door | | `binary_sensor` | `doorStatus` | +| Dry level | `mdi:hair-dryer` | `sensor` | `dryLevel` | +| Error | `mdi:math-log` | `sensor` | `errors` | +| Machine Status | `mdi:information` | `sensor` | `machMode` | +| Program | `mdi:tumble-dryer` | `sensor` | `prCode` | +| Program Phase | `mdi:tumble-dryer` | `sensor` | `prPhase` | +| Remaining Time | `mdi:timer` | `sensor` | `remainingTimeMM` | +| Start Time | `mdi:clock-start` | `sensor` | `delayTime` | +| Temperature level | `mdi:thermometer` | `sensor` | `tempLevel` | + +### Washer dryer +#### Controls +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Pause Washing Machine | `mdi:pause` | `switch` | `pauseProgram` / `resumeProgram` | +| Washing Machine | `mdi:washing-machine` | `switch` | `startProgram` / `stopProgram` | +#### Configs +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Delay Time | `mdi:timer-plus` | `number` | `startProgram.delayTime` | +| Program | | `select` | `startProgram.program` | +| Suggested weight | `mdi:weight-kilogram` | `sensor` | `startProgram.weight` | +#### Sensors +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Acqua Plus | | `binary_sensor` | `acquaplus` | +| Anti-Crease | | `binary_sensor` | `anticrease` | +| Current Electricity Used | `mdi:lightning-bolt` | `sensor` | `currentElectricityUsed` | +| Current Program | `mdi:tumble-dryer` | `sensor` | `prCode` | +| Current Temperature | `mdi:thermometer` | `sensor` | `temp` | +| Current Water Used | `mdi:water` | `sensor` | `currentWaterUsed` | +| Dirt level | `mdi:liquid-spot` | `sensor` | `dirtyLevel` | +| Dry level | `mdi:hair-dryer` | `sensor` | `dryLevel` | +| Extra Rinse 1 | | `binary_sensor` | `extraRinse1` | +| Extra Rinse 2 | | `binary_sensor` | `extraRinse2` | +| Extra Rinse 3 | | `binary_sensor` | `extraRinse3` | +| Good Night Mode | | `binary_sensor` | `goodNight` | +| Machine Status | `mdi:information` | `sensor` | `machMode` | +| Pre Wash | | `binary_sensor` | `startProgram.prewash` | +| Program Phase | `mdi:tumble-dryer` | `sensor` | `prPhase` | +| Remaining Time | `mdi:timer` | `sensor` | `remainingTimeMM` | +| Remote Control | `mdi:remote` | `binary_sensor` | `attributes.lastConnEvent.category` | +| Spin Speed | `mdi:fast-forward-outline` | `sensor` | `spinSpeed` | +| Steam level | `mdi:smoke` | `sensor` | `steamLevel` | +| Total Power | | `sensor` | `totalElectricityUsed` | +| Total Wash Cycle | `mdi:counter` | `sensor` | `totalWashCycle` | +| Total Water | | `sensor` | `totalWaterUsed` | + +### Washing machine +#### Controls +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Pause Washing Machine | `mdi:pause` | `switch` | `pauseProgram` / `resumeProgram` | +| Washing Machine | `mdi:washing-machine` | `switch` | `startProgram` / `stopProgram` | +#### Configs +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Delay Status | `mdi:timer-check` | `switch` | `startProgram.delayStatus` | +| Delay Time | `mdi:timer-plus` | `number` | `startProgram.delayTime` | +| Main Wash Time | `mdi:clock-start` | `number` | `startProgram.mainWashTime` | +| Program | | `select` | `startProgram.program` | +| Rinse Iterations | `mdi:rotate-right` | `number` | `startProgram.rinseIterations` | +| Soak Prewash Selection | `mdi:tshirt-crew` | `switch` | `startProgram.haier_SoakPrewashSelection` | +| Spin speed | `mdi:numeric` | `select` | `startProgram.spinSpeed` | +| Suggested weight | `mdi:weight-kilogram` | `sensor` | `startProgram.weight` | +| Temperature | `mdi:thermometer` | `select` | `startProgram.temp` | +#### Sensors +| Name | Icon | Entity | Key | +| --- | --- | --- | --- | +| Current Electricity Used | `mdi:lightning-bolt` | `sensor` | `currentElectricityUsed` | +| Current Water Used | `mdi:water` | `sensor` | `currentWaterUsed` | +| Door | | `binary_sensor` | `doorStatus` | +| Door Lock | | `binary_sensor` | `doorLockStatus` | +| Error | `mdi:math-log` | `sensor` | `errors` | +| Machine Status | `mdi:information` | `sensor` | `machMode` | +| Remaining Time | `mdi:timer` | `sensor` | `remainingTimeMM` | +| Remote Control | `mdi:remote` | `binary_sensor` | `attributes.lastConnEvent.category` | +| Spin Speed | `mdi:speedometer` | `sensor` | `spinSpeed` | +| Total Power | | `sensor` | `totalElectricityUsed` | +| Total Wash Cycle | `mdi:counter` | `sensor` | `totalWashCycle` | +| Total Water | | `sensor` | `totalWaterUsed` | diff --git a/custom_components/hon/binary_sensor.py b/custom_components/hon/binary_sensor.py index b119722..725259c 100644 --- a/custom_components/hon/binary_sensor.py +++ b/custom_components/hon/binary_sensor.py @@ -152,6 +152,9 @@ BINARY_SENSORS: dict[str, tuple[HonBinarySensorEntityDescription, ...]] = { device_class=BinarySensorDeviceClass.HEAT, on_value="1", ), + HonBinarySensorEntityDescription( + key="panStatus", name="Pan Status", on_value="1", icon="mdi:pot-mix" + ), HonBinarySensorEntityDescription( key="hobLockStatus", name="Hob Lock", @@ -159,6 +162,34 @@ BINARY_SENSORS: dict[str, tuple[HonBinarySensorEntityDescription, ...]] = { 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", + ), + ), } diff --git a/custom_components/hon/number.py b/custom_components/hon/number.py index 67f8045..1e5e4fc 100644 --- a/custom_components/hon/number.py +++ b/custom_components/hon/number.py @@ -120,6 +120,21 @@ NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = { 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, + ), + ), } diff --git a/custom_components/hon/select.py b/custom_components/hon/select.py index bf90e0c..c57f1d9 100644 --- a/custom_components/hon/select.py +++ b/custom_components/hon/select.py @@ -79,6 +79,14 @@ SELECTS = { translation_key="programs", ), ), + "DW": ( + SelectEntityDescription( + key="startProgram.program", + name="Program", + entity_category=EntityCategory.CONFIG, + translation_key="programs_dw", + ), + ), } diff --git a/custom_components/hon/sensor.py b/custom_components/hon/sensor.py index 729ba93..32d7aee 100644 --- a/custom_components/hon/sensor.py +++ b/custom_components/hon/sensor.py @@ -21,6 +21,7 @@ from homeassistant.const import ( 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 @@ -54,7 +55,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { name="Current Electricity Used", state_class=SensorStateClass.MEASUREMENT, device_class=SensorDeviceClass.POWER, - native_unit_of_measurement=UnitOfPower.KILO_WATT, + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, icon="mdi:lightning-bolt", ), SensorEntityDescription( @@ -145,6 +146,48 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { ), ), "WD": ( + 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=UnitOfEnergy.KILO_WATT_HOUR, + 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", @@ -236,6 +279,75 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfTemperature.CELSIUS, ), SensorEntityDescription(key="errors", name="Error", icon="mdi:math-log"), + SensorEntityDescription( + key="power", + name="Power", + icon="mdi:lightning-bolt", + state_class=SensorStateClass.MEASUREMENT, + ), + ), + "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, + ), ), } diff --git a/custom_components/hon/switch.py b/custom_components/hon/switch.py index 47366ad..57a0a36 100644 --- a/custom_components/hon/switch.py +++ b/custom_components/hon/switch.py @@ -1,5 +1,4 @@ import logging - from dataclasses import dataclass from typing import Any @@ -101,6 +100,51 @@ SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { 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, + ), + ), } @@ -150,13 +194,6 @@ class HonSwitchEntity(HonEntity, SwitchEntity): 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.""" @@ -172,7 +209,9 @@ class HonSwitchEntity(HonEntity, SwitchEntity): 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 + 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() @@ -180,7 +219,9 @@ class HonSwitchEntity(HonEntity, SwitchEntity): 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 + 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() diff --git a/custom_components/hon/translations/en.json b/custom_components/hon/translations/en.json index cafd100..6225013 100644 --- a/custom_components/hon/translations/en.json +++ b/custom_components/hon/translations/en.json @@ -72,6 +72,16 @@ "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": { @@ -461,6 +471,112 @@ "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" + } } } } diff --git a/info.md b/info.md index a35b040..c72d790 100644 --- a/info.md +++ b/info.md @@ -1,15 +1,16 @@ # Haier hOn [![GitHub release (latest by date)](https://img.shields.io/github/v/release/Andre0512/hon?color=green)](https://github.com/Andre0512/hon/releases/latest) -![GitHub](https://img.shields.io/github/license/Andre0512/hon?color=red) -[![Home Assistant installs](https://img.shields.io/badge/dynamic/json?color=blue&label=usage&suffix=%20installs&cacheSeconds=15600&url=https://analytics.home-assistant.io/custom_integrations.json&query=$.hon.total)](https://analytics.home-assistant.io/) +[![GitHub](https://img.shields.io/github/license/Andre0512/hon?color=red)](https://github.com/Andre0512/hon/blob/main/LICENSE) +[![GitHub all releases](https://img.shields.io/github/downloads/Andre0512/hon/total?color=blue)](https://tooomm.github.io/github-release-stats/?username=Andre0512&repository=hon) Support for home appliances of Haier's mobile app hOn. ## Supported Appliances -- Tumble Dryer -- Washer Dryer -- Washing Machine -- Oven -- Hob +- [Washing Machine](https://github.com/Andre0512/hon#washing-machine) +- [Tumble Dryer](https://github.com/Andre0512/hon#tumble-dryer) +- [Washer Dryer](https://github.com/Andre0512/hon#washer-dryer) +- [Oven](https://github.com/Andre0512/hon#oven) +- [Hob](https://github.com/Andre0512/hon#hob) +- [Dish Washer](https://github.com/Andre0512/hon#dish-washer) ## Tested Appliances - Haier WD90-B14TEAM5 @@ -17,7 +18,6 @@ Support for home appliances of Haier's mobile app hOn. - Haier HWO60SM2F3XH - Hoover H-WASH 500 - ## Configuration **Method 1**: [![Open your Home Assistant instance and start setting up a new integration.](https://my.home-assistant.io/badges/config_flow_start.svg)](https://my.home-assistant.io/redirect/config_flow_start/?domain=hon) @@ -25,13 +25,11 @@ Support for home appliances of Haier's mobile app 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) diff --git a/scripts/sensor_docs.py b/scripts/sensor_docs.py new file mode 100755 index 0000000..f7dbafd --- /dev/null +++ b/scripts/sensor_docs.py @@ -0,0 +1,77 @@ +import re +from pathlib import Path + +from custom_components.hon.binary_sensor import BINARY_SENSORS +from custom_components.hon.button import BUTTONS +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.switch import SWITCHES, HonSwitchEntityDescription + +APPLIANCES = { + "AC": "Air conditioner", + "AP": "Air purifier", + "AS": "Air scanner", + "DW": "Dish washer", + "HO": "Hood", + "IH": "Hob", + "MW": "Microwave", + "OV": "Oven", + "REF": "Fridge", + "RVC": "Robot vacuum cleaner", + "TD": "Tumble dryer", + "WC": "Wine Cellar", + "WD": "Washer dryer", + "WH": "Water Heater", + "WM": "Washing machine", +} + +ENTITY_CATEGORY_SORT = ["control", "config", "sensor"] + +entities = { + "binary_sensor": BINARY_SENSORS, + "button": BUTTONS, + "number": NUMBERS, + "select": SELECTS, + "sensor": SENSORS, + "switch": SWITCHES, +} + +result = {} +for entity_type, appliances in entities.items(): + for appliance, data in appliances.items(): + for entity in data: + if ( + isinstance(entity, HonSwitchEntityDescription) + and entity.entity_category != "config" + ): + key = f"{entity.turn_on_key}` / `{entity.turn_off_key}" + else: + key = entity.key + attributes = (key, entity.name, entity.icon, entity_type) + category = "control" if entity_type in ["switch", "button"] else "sensor" + result.setdefault(appliance, {}).setdefault( + entity.entity_category or category, [] + ).append(attributes) +text = "" +for appliance, categories in sorted(result.items()): + text += f"\n### {APPLIANCES[appliance]}\n" + categories = {k: categories[k] for k in ENTITY_CATEGORY_SORT if k in categories} + for category, data in categories.items(): + text += f"#### {str(category).capitalize()}s\n" + text += "| Name | Icon | Entity | Key |\n" + text += "| --- | --- | --- | --- |\n" + for key, name, icon, entity_type in sorted(data, key=lambda d: d[1]): + icon = f"`{icon}`" if icon else "" + text += f"| {name} | {icon} | `{entity_type}` | `{key}` |\n" + +with open(Path(__file__).parent.parent / "README.md", "r") as file: + readme = file.read() +readme = re.sub( + "(## Appliance Features\n)(?:.|\\s)+?([^#]## |\\Z)", + f"\\1{text}\\2", + readme, + re.DOTALL, +) +with open(Path(__file__).parent.parent / "README.md", "w") as file: + file.write(readme)