diff --git a/homeassistant/components/melnor/manifest.json b/homeassistant/components/melnor/manifest.json index a59758f705b..c57549aa647 100644 --- a/homeassistant/components/melnor/manifest.json +++ b/homeassistant/components/melnor/manifest.json @@ -12,5 +12,5 @@ "documentation": "https://www.home-assistant.io/integrations/melnor", "iot_class": "local_polling", "name": "Melnor Bluetooth", - "requirements": ["melnor-bluetooth==0.0.15"] + "requirements": ["melnor-bluetooth==0.0.20"] } diff --git a/homeassistant/components/melnor/sensor.py b/homeassistant/components/melnor/sensor.py index bda70dfee3b..e642df4f9c3 100644 --- a/homeassistant/components/melnor/sensor.py +++ b/homeassistant/components/melnor/sensor.py @@ -38,38 +38,39 @@ class MelnorSensorEntityDescription( """Describes Melnor sensor entity.""" +sensors = [ + MelnorSensorEntityDescription( + device_class=SensorDeviceClass.BATTERY, + entity_category=EntityCategory.DIAGNOSTIC, + key="battery", + name="Battery", + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + state_fn=lambda device: device.battery_level, + ), + MelnorSensorEntityDescription( + device_class=SensorDeviceClass.SIGNAL_STRENGTH, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + key="rssi", + name="RSSI", + native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT, + state_class=SensorStateClass.MEASUREMENT, + state_fn=lambda device: device.rssi, + ), +] + + async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, - async_add_devices: AddEntitiesCallback, + async_add_entities: AddEntitiesCallback, ) -> None: """Set up the sensor platform.""" coordinator: MelnorDataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] - sensors: list[MelnorSensorEntityDescription] = [ - MelnorSensorEntityDescription( - device_class=SensorDeviceClass.BATTERY, - entity_category=EntityCategory.DIAGNOSTIC, - key="battery", - name="Battery", - native_unit_of_measurement=PERCENTAGE, - state_class=SensorStateClass.MEASUREMENT, - state_fn=lambda device: device.battery_level, - ), - MelnorSensorEntityDescription( - device_class=SensorDeviceClass.SIGNAL_STRENGTH, - entity_category=EntityCategory.DIAGNOSTIC, - entity_registry_enabled_default=False, - key="rssi", - name="RSSI", - native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT, - state_class=SensorStateClass.MEASUREMENT, - state_fn=lambda device: device.rssi, - ), - ] - - async_add_devices( + async_add_entities( MelnorSensorEntity( coordinator, description, diff --git a/homeassistant/components/melnor/switch.py b/homeassistant/components/melnor/switch.py index 34e0ca331b1..20d95ad99a6 100644 --- a/homeassistant/components/melnor/switch.py +++ b/homeassistant/components/melnor/switch.py @@ -2,7 +2,7 @@ from __future__ import annotations -from collections.abc import Callable +from collections.abc import Callable, Coroutine from dataclasses import dataclass from typing import Any @@ -21,16 +21,11 @@ from .const import DOMAIN from .models import MelnorDataUpdateCoordinator, MelnorZoneEntity -def set_is_watering(valve: Valve, value: bool) -> None: - """Set the is_watering state of a valve.""" - valve.is_watering = value - - @dataclass class MelnorSwitchEntityDescriptionMixin: """Mixin for required keys.""" - on_off_fn: Callable[[Valve, bool], Any] + on_off_fn: Callable[[Valve, bool], Coroutine[Any, Any, None]] state_fn: Callable[[Valve], Any] @@ -41,6 +36,18 @@ class MelnorSwitchEntityDescription( """Describes Melnor switch entity.""" +switches = [ + MelnorSwitchEntityDescription( + device_class=SwitchDeviceClass.SWITCH, + icon="mdi:sprinkler", + key="manual", + name="Manual", + on_off_fn=lambda valve, bool: valve.set_is_watering(bool), + state_fn=lambda valve: valve.is_watering, + ) +] + + async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, @@ -56,20 +63,8 @@ async def async_setup_entry( valve = coordinator.data[f"zone{i}"] if valve is not None: - entities.append( - MelnorZoneSwitch( - coordinator, - valve, - MelnorSwitchEntityDescription( - device_class=SwitchDeviceClass.SWITCH, - icon="mdi:sprinkler", - key="manual", - name="Manual", - on_off_fn=set_is_watering, - state_fn=lambda valve: valve.is_watering, - ), - ) - ) + for description in switches: + entities.append(MelnorZoneSwitch(coordinator, valve, description)) async_add_devices(entities) @@ -98,12 +93,10 @@ class MelnorZoneSwitch(MelnorZoneEntity, SwitchEntity): async def async_turn_on(self, **kwargs: Any) -> None: """Turn the device on.""" - self.entity_description.on_off_fn(self._valve, True) - await self._device.push_state() + await self.entity_description.on_off_fn(self._valve, True) self.async_write_ha_state() async def async_turn_off(self, **kwargs: Any) -> None: """Turn the device off.""" - self.entity_description.on_off_fn(self._valve, False) - await self._device.push_state() + await self.entity_description.on_off_fn(self._valve, False) self.async_write_ha_state() diff --git a/requirements_all.txt b/requirements_all.txt index 8ef6d6c1ee7..2bfe314040f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1046,7 +1046,7 @@ mcstatus==6.0.0 meater-python==0.0.8 # homeassistant.components.melnor -melnor-bluetooth==0.0.15 +melnor-bluetooth==0.0.20 # homeassistant.components.message_bird messagebird==1.2.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 90eeabcba37..2ff915966f0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -748,7 +748,7 @@ mcstatus==6.0.0 meater-python==0.0.8 # homeassistant.components.melnor -melnor-bluetooth==0.0.15 +melnor-bluetooth==0.0.20 # homeassistant.components.meteo_france meteofrance-api==1.0.2 diff --git a/tests/components/melnor/conftest.py b/tests/components/melnor/conftest.py index 5aee6264501..554349109ef 100644 --- a/tests/components/melnor/conftest.py +++ b/tests/components/melnor/conftest.py @@ -6,7 +6,7 @@ from unittest.mock import AsyncMock, patch from bleak.backends.device import BLEDevice from bleak.backends.scanner import AdvertisementData -from melnor_bluetooth.device import Device, Valve +from melnor_bluetooth.device import Device from homeassistant.components.bluetooth.models import BluetoothServiceInfoBleak from homeassistant.components.melnor.const import DOMAIN @@ -52,6 +52,34 @@ FAKE_SERVICE_INFO_2 = BluetoothServiceInfoBleak( ) +class MockedValve: + """Mocked class for a Valve.""" + + _id: int + _is_watering: bool + _manual_watering_minutes: int + + def __init__(self, identifier: int) -> None: + """Initialize a mocked valve.""" + self._id = identifier + self._is_watering = False + self._manual_watering_minutes = 0 + + @property + def id(self) -> int: + """Return the valve id.""" + return self._id + + @property + def is_watering(self): + """Return true if the valve is currently watering.""" + return self._is_watering + + async def set_is_watering(self, is_watering: bool): + """Set the valve to manual watering.""" + self._is_watering = is_watering + + def mock_config_entry(hass: HomeAssistant): """Return a mock config entry.""" @@ -83,10 +111,10 @@ def mock_melnor_device(): device.name = "test_melnor" device.rssi = -50 - device.zone1 = Valve(0, device) - device.zone2 = Valve(1, device) - device.zone3 = Valve(2, device) - device.zone4 = Valve(3, device) + device.zone1 = MockedValve(0) + device.zone2 = MockedValve(1) + device.zone3 = MockedValve(2) + device.zone4 = MockedValve(3) device.__getitem__.side_effect = lambda key: getattr(device, key)