diff --git a/custom_components/hOn/binary_sensor.py b/custom_components/hOn/binary_sensor.py new file mode 100644 index 0000000..55f907c --- /dev/null +++ b/custom_components/hOn/binary_sensor.py @@ -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="1", + ), + ) +} + + +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() diff --git a/custom_components/hOn/button.py b/custom_components/hOn/button.py index 410d6ab..8f48fa9 100644 --- a/custom_components/hOn/button.py +++ b/custom_components/hOn/button.py @@ -9,16 +9,6 @@ from .hon import HonCoordinator, HonEntity BUTTONS: dict[str, tuple[ButtonEntityDescription, ...]] = { "WM": ( - ButtonEntityDescription( - key="startProgram", - name="Start Program", - icon="mdi:play", - ), - ButtonEntityDescription( - key="stopProgram", - name="Stop Program", - icon="mdi:stop", - ), ButtonEntityDescription( key="pauseProgram", name="Pause Program", @@ -47,6 +37,8 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non 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)] ) diff --git a/custom_components/hOn/const.py b/custom_components/hOn/const.py index ad87ea4..5dae56e 100755 --- a/custom_components/hOn/const.py +++ b/custom_components/hOn/const.py @@ -5,5 +5,6 @@ PLATFORMS = [ "select", "number", "switch", - "button" + "button", + "binary_sensor", ] diff --git a/custom_components/hOn/manifest.json b/custom_components/hOn/manifest.json index d01bfc4..8701ffa 100755 --- a/custom_components/hOn/manifest.json +++ b/custom_components/hOn/manifest.json @@ -2,9 +2,9 @@ "domain": "hon", "name": "hOn", "config_flow": true, - "version": "0.0.1", + "version": "0.1.0", "codeowners": ["@Andre0512"], "iot_class": "cloud_polling", - "requirements": ["pyhon"], + "requirements": ["pyhOn==0.2.4"], "documentation": "https://github.com/Andre0512/hOn/" } diff --git a/custom_components/hOn/select.py b/custom_components/hOn/select.py index 6ba29e8..7c0406a 100644 --- a/custom_components/hOn/select.py +++ b/custom_components/hOn/select.py @@ -54,10 +54,11 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non 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) diff --git a/custom_components/hOn/sensor.py b/custom_components/hOn/sensor.py index 774019f..2dbd0c4 100644 --- a/custom_components/hOn/sensor.py +++ b/custom_components/hOn/sensor.py @@ -57,7 +57,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { ), SensorEntityDescription( key="startProgram.weight", - name="Weight", + name="Suggested weight", state_class=SensorStateClass.MEASUREMENT, entity_category=EntityCategory.CONFIG, native_unit_of_measurement=UnitOfMass.KILOGRAMS, @@ -65,14 +65,17 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { ), SensorEntityDescription( key="machMode", - name="Mode", + name="Machine Last Status", + icon="mdi:information", translation_key="mode" ), SensorEntityDescription( key="errors", name="Last Error", + icon="mdi:math-log", translation_key="errors" ), + ) } @@ -91,6 +94,8 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non 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)] ) diff --git a/custom_components/hOn/switch.py b/custom_components/hOn/switch.py index 05155f1..28e7887 100644 --- a/custom_components/hOn/switch.py +++ b/custom_components/hOn/switch.py @@ -63,9 +63,10 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non if descriptions := SWITCHES.get(device.appliance_type_name): for description in descriptions: - appliances.extend([ - HonSwitchEntity(hass, coordinator, entry, device, description)] - ) + 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) @@ -85,7 +86,6 @@ class HonSwitchEntity(HonEntity, SwitchEntity): 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.""" diff --git a/custom_components/hOn/translations/en.json b/custom_components/hOn/translations/en.json index c65dadc..c4d9edd 100644 --- a/custom_components/hOn/translations/en.json +++ b/custom_components/hOn/translations/en.json @@ -23,9 +23,11 @@ } }, "errors": { - "00": "No error", - "100000000000": "E2: Check if the door is closed", - "8000000000000": "E4: Check the water supply" + "state": { + "00": "No error", + "100000000000": "E2: Check if the door is closed", + "8000000000000": "E4: Check the water supply" + } } } } diff --git a/hacs.json b/hacs.json index 2cf5be6..a24c0d4 100644 --- a/hacs.json +++ b/hacs.json @@ -1,5 +1,5 @@ { - "name": "Haier hOn", + "name": "hOn", "render_readme": false, "homeassistant": "2023.2.0" } \ No newline at end of file