Refactor eheimdigital tests to use fixtures (#145428)

This commit is contained in:
Sid 2025-05-26 19:13:20 +02:00 committed by GitHub
parent 99ebac5452
commit 03a26836ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 462 additions and 197 deletions

View File

@ -94,8 +94,6 @@ class EheimDigitalClassicLEDControlLight(
await self._device.set_light_mode(EFFECT_TO_LIGHT_MODE[kwargs[ATTR_EFFECT]]) await self._device.set_light_mode(EFFECT_TO_LIGHT_MODE[kwargs[ATTR_EFFECT]])
return return
if ATTR_BRIGHTNESS in kwargs: if ATTR_BRIGHTNESS in kwargs:
if self._device.light_mode == LightMode.DAYCL_MODE:
await self._device.set_light_mode(LightMode.MAN_MODE)
await self._device.turn_on( await self._device.turn_on(
int(brightness_to_value(BRIGHTNESS_SCALE, kwargs[ATTR_BRIGHTNESS])), int(brightness_to_value(BRIGHTNESS_SCALE, kwargs[ATTR_BRIGHTNESS])),
self._channel, self._channel,
@ -104,8 +102,6 @@ class EheimDigitalClassicLEDControlLight(
@exception_handler @exception_handler
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the light.""" """Turn off the light."""
if self._device.light_mode == LightMode.DAYCL_MODE:
await self._device.set_light_mode(LightMode.MAN_MODE)
await self._device.turn_off(self._channel) await self._device.turn_off(self._channel)
def _async_update_attrs(self) -> None: def _async_update_attrs(self) -> None:

View File

@ -1,7 +1,6 @@
"""Configurations for the EHEIM Digital tests.""" """Configurations for the EHEIM Digital tests."""
from collections.abc import Generator from collections.abc import Generator
from datetime import time, timedelta, timezone
from unittest.mock import AsyncMock, MagicMock, patch from unittest.mock import AsyncMock, MagicMock, patch
from eheimdigital.classic_led_ctrl import EheimDigitalClassicLEDControl from eheimdigital.classic_led_ctrl import EheimDigitalClassicLEDControl
@ -9,12 +8,13 @@ from eheimdigital.classic_vario import EheimDigitalClassicVario
from eheimdigital.heater import EheimDigitalHeater from eheimdigital.heater import EheimDigitalHeater
from eheimdigital.hub import EheimDigitalHub from eheimdigital.hub import EheimDigitalHub
from eheimdigital.types import ( from eheimdigital.types import (
EheimDeviceType, AcclimatePacket,
FilterErrorCode, CCVPacket,
FilterMode, ClassicVarioDataPacket,
HeaterMode, ClockPacket,
HeaterUnit, CloudPacket,
LightMode, MoonPacket,
UsrDtaPacket,
) )
import pytest import pytest
@ -22,7 +22,7 @@ from homeassistant.components.eheimdigital.const import DOMAIN
from homeassistant.const import CONF_HOST from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, load_json_object_fixture
@pytest.fixture @pytest.fixture
@ -36,66 +36,50 @@ def mock_config_entry() -> MockConfigEntry:
@pytest.fixture @pytest.fixture
def classic_led_ctrl_mock(): def classic_led_ctrl_mock():
"""Mock a classicLEDcontrol device.""" """Mock a classicLEDcontrol device."""
classic_led_ctrl_mock = MagicMock(spec=EheimDigitalClassicLEDControl) classic_led_ctrl = EheimDigitalClassicLEDControl(
classic_led_ctrl_mock.tankconfig = [["CLASSIC_DAYLIGHT"], []] MagicMock(spec=EheimDigitalHub),
classic_led_ctrl_mock.mac_address = "00:00:00:00:00:01" UsrDtaPacket(load_json_object_fixture("classic_led_ctrl/usrdta.json", DOMAIN)),
classic_led_ctrl_mock.device_type = (
EheimDeviceType.VERSION_EHEIM_CLASSIC_LED_CTRL_PLUS_E
) )
classic_led_ctrl_mock.name = "Mock classicLEDcontrol+e" classic_led_ctrl.ccv = CCVPacket(
classic_led_ctrl_mock.aquarium_name = "Mock Aquarium" load_json_object_fixture("classic_led_ctrl/ccv.json", DOMAIN)
classic_led_ctrl_mock.sw_version = "1.0.0_1.0.0" )
classic_led_ctrl_mock.light_mode = LightMode.DAYCL_MODE classic_led_ctrl.moon = MoonPacket(
classic_led_ctrl_mock.light_level = (10, 39) load_json_object_fixture("classic_led_ctrl/moon.json", DOMAIN)
classic_led_ctrl_mock.sys_led = 20 )
return classic_led_ctrl_mock classic_led_ctrl.acclimate = AcclimatePacket(
load_json_object_fixture("classic_led_ctrl/acclimate.json", DOMAIN)
)
classic_led_ctrl.cloud = CloudPacket(
load_json_object_fixture("classic_led_ctrl/cloud.json", DOMAIN)
)
classic_led_ctrl.clock = ClockPacket(
load_json_object_fixture("classic_led_ctrl/clock.json", DOMAIN)
)
return classic_led_ctrl
@pytest.fixture @pytest.fixture
def heater_mock(): def heater_mock():
"""Mock a Heater device.""" """Mock a Heater device."""
heater_mock = MagicMock(spec=EheimDigitalHeater) heater = EheimDigitalHeater(
heater_mock.mac_address = "00:00:00:00:00:02" MagicMock(spec=EheimDigitalHub),
heater_mock.device_type = EheimDeviceType.VERSION_EHEIM_EXT_HEATER load_json_object_fixture("heater/usrdta.json", DOMAIN),
heater_mock.name = "Mock Heater" )
heater_mock.aquarium_name = "Mock Aquarium" heater.heater_data = load_json_object_fixture("heater/heater_data.json", DOMAIN)
heater_mock.sw_version = "1.0.0_1.0.0" return heater
heater_mock.temperature_unit = HeaterUnit.CELSIUS
heater_mock.current_temperature = 24.2
heater_mock.target_temperature = 25.5
heater_mock.temperature_offset = 0.1
heater_mock.night_temperature_offset = -0.2
heater_mock.is_heating = True
heater_mock.is_active = True
heater_mock.operation_mode = HeaterMode.MANUAL
heater_mock.day_start_time = time(8, 0, tzinfo=timezone(timedelta(hours=1)))
heater_mock.night_start_time = time(20, 0, tzinfo=timezone(timedelta(hours=1)))
heater_mock.sys_led = 20
return heater_mock
@pytest.fixture @pytest.fixture
def classic_vario_mock(): def classic_vario_mock():
"""Mock a classicVARIO device.""" """Mock a classicVARIO device."""
classic_vario_mock = MagicMock(spec=EheimDigitalClassicVario) classic_vario = EheimDigitalClassicVario(
classic_vario_mock.mac_address = "00:00:00:00:00:03" MagicMock(spec=EheimDigitalHub),
classic_vario_mock.device_type = EheimDeviceType.VERSION_EHEIM_CLASSIC_VARIO UsrDtaPacket(load_json_object_fixture("classic_vario/usrdta.json", DOMAIN)),
classic_vario_mock.name = "Mock classicVARIO"
classic_vario_mock.aquarium_name = "Mock Aquarium"
classic_vario_mock.sw_version = "1.0.0_1.0.0"
classic_vario_mock.current_speed = 75
classic_vario_mock.manual_speed = 75
classic_vario_mock.day_speed = 80
classic_vario_mock.day_start_time = time(8, 0, tzinfo=timezone(timedelta(hours=1)))
classic_vario_mock.night_start_time = time(
20, 0, tzinfo=timezone(timedelta(hours=1))
) )
classic_vario_mock.night_speed = 20 classic_vario.classic_vario_data = ClassicVarioDataPacket(
classic_vario_mock.is_active = True load_json_object_fixture("classic_vario/classic_vario_data.json", DOMAIN)
classic_vario_mock.filter_mode = FilterMode.MANUAL )
classic_vario_mock.error_code = FilterErrorCode.NO_ERROR return classic_vario
classic_vario_mock.service_hours = 360
return classic_vario_mock
@pytest.fixture @pytest.fixture

View File

@ -0,0 +1,9 @@
{
"title": "ACCLIMATE",
"from": "00:00:00:00:00:01",
"duration": 30,
"intensityReduction": 99,
"currentAcclDay": 0,
"acclActive": 0,
"pause": 0
}

View File

@ -0,0 +1 @@
{ "title": "CCV", "from": "00:00:00:00:00:01", "currentValues": [10, 39] }

View File

@ -0,0 +1,13 @@
{
"title": "CLOCK",
"from": "00:00:00:00:00:01",
"year": 2025,
"month": 5,
"day": 22,
"hour": 5,
"min": 53,
"sec": 22,
"mode": "DAYCL_MODE",
"valid": 1,
"to": "USER"
}

View File

@ -0,0 +1,12 @@
{
"title": "CLOUD",
"from": "00:00:00:00:00:01",
"probability": 50,
"maxAmount": 90,
"minIntensity": 60,
"maxIntensity": 100,
"minDuration": 600,
"maxDuration": 1500,
"cloudActive": 1,
"mode": 2
}

View File

@ -0,0 +1,8 @@
{
"title": "MOON",
"from": "00:00:00:00:00:01",
"maxmoonlight": 18,
"minmoonlight": 4,
"moonlightActive": 1,
"moonlightCycle": 1
}

View File

@ -0,0 +1,35 @@
{
"title": "USRDTA",
"from": "00:00:00:00:00:01",
"name": "Mock classicLEDcontrol+e",
"aqName": "Mock Aquarium",
"mode": "DAYCL_MODE",
"version": 17,
"language": "EN",
"timezone": 60,
"tID": 30,
"dst": 1,
"tankconfig": "[[],[\"CLASSIC_DAYLIGHT\"]]",
"power": "[[],[14]]",
"netmode": "ST",
"host": "eheimdigital",
"groupID": 0,
"meshing": 1,
"firstStart": 0,
"revision": [2034, 2034],
"build": ["1722600896000", "1722596503307"],
"latestAvailableRevision": [-1, -1, -1, -1],
"firmwareAvailable": 0,
"softChange": 0,
"emailAddr": "",
"stMail": 0,
"stMailMode": 0,
"fstTime": 0,
"sstTime": 0,
"liveTime": 832140,
"usrName": "",
"unit": 0,
"demoUse": 0,
"sysLED": 20,
"to": "USER"
}

View File

@ -0,0 +1,22 @@
{
"title": "CLASSIC_VARIO_DATA",
"from": "00:00:00:00:00:03",
"rel_speed": 75,
"pumpMode": 16,
"filterActive": 1,
"turnOffTime": 0,
"serviceHour": 360,
"rel_manual_motor_speed": 75,
"rel_motor_speed_day": 80,
"rel_motor_speed_night": 20,
"startTime_day": 480,
"startTime_night": 1200,
"pulse_motorSpeed_High": 100,
"pulse_motorSpeed_Low": 20,
"pulse_Time_High": 100,
"pulse_Time_Low": 50,
"turnTimeFeeding": 0,
"errorCode": 0,
"version": 0,
"to": "USER"
}

View File

@ -0,0 +1,34 @@
{
"title": "USRDTA",
"from": "00:00:00:00:00:03",
"name": "Mock classicVARIO",
"aqName": "Mock Aquarium",
"version": 18,
"language": "EN",
"timezone": 60,
"tID": 30,
"dst": 1,
"tankconfig": "CLASSIC-VARIO",
"power": "9",
"netmode": "ST",
"host": "eheimdigital",
"groupID": 0,
"meshing": 1,
"firstStart": 0,
"revision": [2034, 2034],
"build": ["1722600896000", "1722596503307"],
"latestAvailableRevision": [1024, 1028, 2036, 2036],
"firmwareAvailable": 1,
"softChange": 0,
"emailAddr": "",
"stMail": 0,
"stMailMode": 0,
"fstTime": 720,
"sstTime": 0,
"liveTime": 444600,
"usrName": "",
"unit": 0,
"demoUse": 0,
"sysLED": 100,
"to": "USER"
}

View File

@ -0,0 +1,20 @@
{
"title": "HEATER_DATA",
"from": "00:00:00:00:00:02",
"mUnit": 0,
"sollTemp": 255,
"isTemp": 242,
"hystLow": 5,
"hystHigh": 5,
"offset": 1,
"active": 1,
"isHeating": 1,
"mode": 0,
"sync": "",
"partnerName": "",
"dayStartT": 480,
"nightStartT": 1200,
"nReduce": -2,
"alertState": 0,
"to": "USER"
}

View File

@ -0,0 +1,34 @@
{
"title": "USRDTA",
"from": "00:00:00:00:00:02",
"name": "Mock Heater",
"aqName": "Mock Aquarium",
"version": 5,
"language": "EN",
"timezone": 60,
"tID": 30,
"dst": 1,
"tankconfig": "HEAT400",
"power": "9",
"netmode": "ST",
"host": "eheimdigital",
"groupID": 0,
"meshing": 1,
"firstStart": 0,
"remote": 0,
"revision": [1021, 1024],
"build": ["1718889198000", "1718868200327"],
"latestAvailableRevision": [-1, -1, -1, -1],
"firmwareAvailable": 0,
"emailAddr": "",
"stMail": 0,
"stMailMode": 0,
"fstTime": 0,
"sstTime": 0,
"liveTime": 302580,
"usrName": "",
"unit": 0,
"demoUse": 0,
"sysLED": 20,
"to": "USER"
}

View File

@ -1,5 +1,5 @@
# serializer version: 1 # serializer version: 1
# name: test_dynamic_new_devices[light.mock_classicledcontrol_e_channel_0-entry] # name: test_dynamic_new_devices[light.mock_classicledcontrol_e_channel_1-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({
}), }),
@ -19,7 +19,7 @@
'disabled_by': None, 'disabled_by': None,
'domain': 'light', 'domain': 'light',
'entity_category': None, 'entity_category': None,
'entity_id': 'light.mock_classicledcontrol_e_channel_0', 'entity_id': 'light.mock_classicledcontrol_e_channel_1',
'has_entity_name': True, 'has_entity_name': True,
'hidden_by': None, 'hidden_by': None,
'icon': None, 'icon': None,
@ -31,32 +31,32 @@
}), }),
'original_device_class': None, 'original_device_class': None,
'original_icon': None, 'original_icon': None,
'original_name': 'Channel 0', 'original_name': 'Channel 1',
'platform': 'eheimdigital', 'platform': 'eheimdigital',
'previous_unique_id': None, 'previous_unique_id': None,
'supported_features': <LightEntityFeature: 4>, 'supported_features': <LightEntityFeature: 4>,
'translation_key': 'channel', 'translation_key': 'channel',
'unique_id': '00:00:00:00:00:01_0', 'unique_id': '00:00:00:00:00:01_1',
'unit_of_measurement': None, 'unit_of_measurement': None,
}) })
# --- # ---
# name: test_dynamic_new_devices[light.mock_classicledcontrol_e_channel_0-state] # name: test_dynamic_new_devices[light.mock_classicledcontrol_e_channel_1-state]
StateSnapshot({ StateSnapshot({
'attributes': ReadOnlyDict({ 'attributes': ReadOnlyDict({
'brightness': 26, 'brightness': 99,
'color_mode': <ColorMode.BRIGHTNESS: 'brightness'>, 'color_mode': <ColorMode.BRIGHTNESS: 'brightness'>,
'effect': 'daycl_mode', 'effect': 'daycl_mode',
'effect_list': list([ 'effect_list': list([
'daycl_mode', 'daycl_mode',
]), ]),
'friendly_name': 'Mock classicLEDcontrol+e Channel 0', 'friendly_name': 'Mock classicLEDcontrol+e Channel 1',
'supported_color_modes': list([ 'supported_color_modes': list([
<ColorMode.BRIGHTNESS: 'brightness'>, <ColorMode.BRIGHTNESS: 'brightness'>,
]), ]),
'supported_features': <LightEntityFeature: 4>, 'supported_features': <LightEntityFeature: 4>,
}), }),
'context': <ANY>, 'context': <ANY>,
'entity_id': 'light.mock_classicledcontrol_e_channel_0', 'entity_id': 'light.mock_classicledcontrol_e_channel_1',
'last_changed': <ANY>, 'last_changed': <ANY>,
'last_reported': <ANY>, 'last_reported': <ANY>,
'last_updated': <ANY>, 'last_updated': <ANY>,

View File

@ -2,6 +2,7 @@
from unittest.mock import AsyncMock, MagicMock, patch from unittest.mock import AsyncMock, MagicMock, patch
from eheimdigital.heater import EheimDigitalHeater
from eheimdigital.types import ( from eheimdigital.types import (
EheimDeviceType, EheimDeviceType,
EheimDigitalClientError, EheimDigitalClientError,
@ -67,7 +68,7 @@ async def test_setup_heater(
async def test_dynamic_new_devices( async def test_dynamic_new_devices(
hass: HomeAssistant, hass: HomeAssistant,
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
heater_mock: MagicMock, heater_mock: EheimDigitalHeater,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
@ -116,7 +117,7 @@ async def test_dynamic_new_devices(
async def test_set_preset_mode( async def test_set_preset_mode(
hass: HomeAssistant, hass: HomeAssistant,
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
heater_mock: MagicMock, heater_mock: EheimDigitalHeater,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
preset_mode: str, preset_mode: str,
heater_mode: HeaterMode, heater_mode: HeaterMode,
@ -129,7 +130,7 @@ async def test_set_preset_mode(
) )
await hass.async_block_till_done() await hass.async_block_till_done()
heater_mock.set_operation_mode.side_effect = EheimDigitalClientError heater_mock.hub.send_packet.side_effect = EheimDigitalClientError
with pytest.raises(HomeAssistantError): with pytest.raises(HomeAssistantError):
await hass.services.async_call( await hass.services.async_call(
@ -139,7 +140,7 @@ async def test_set_preset_mode(
blocking=True, blocking=True,
) )
heater_mock.set_operation_mode.side_effect = None heater_mock.hub.send_packet.side_effect = None
await hass.services.async_call( await hass.services.async_call(
CLIMATE_DOMAIN, CLIMATE_DOMAIN,
@ -148,7 +149,8 @@ async def test_set_preset_mode(
blocking=True, blocking=True,
) )
heater_mock.set_operation_mode.assert_awaited_with(heater_mode) calls = [call for call in heater_mock.hub.mock_calls if call[0] == "send_packet"]
assert len(calls) == 2 and calls[1][1][0]["mode"] == int(heater_mode)
async def test_set_temperature( async def test_set_temperature(
@ -165,7 +167,7 @@ async def test_set_temperature(
) )
await hass.async_block_till_done() await hass.async_block_till_done()
heater_mock.set_target_temperature.side_effect = EheimDigitalClientError heater_mock.hub.send_packet.side_effect = EheimDigitalClientError
with pytest.raises(HomeAssistantError): with pytest.raises(HomeAssistantError):
await hass.services.async_call( await hass.services.async_call(
@ -175,7 +177,7 @@ async def test_set_temperature(
blocking=True, blocking=True,
) )
heater_mock.set_target_temperature.side_effect = None heater_mock.hub.send_packet.side_effect = None
await hass.services.async_call( await hass.services.async_call(
CLIMATE_DOMAIN, CLIMATE_DOMAIN,
@ -184,7 +186,8 @@ async def test_set_temperature(
blocking=True, blocking=True,
) )
heater_mock.set_target_temperature.assert_awaited_with(26.0) calls = [call for call in heater_mock.hub.mock_calls if call[0] == "send_packet"]
assert len(calls) == 2 and calls[1][1][0]["sollTemp"] == 260
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -206,7 +209,7 @@ async def test_set_hvac_mode(
) )
await hass.async_block_till_done() await hass.async_block_till_done()
heater_mock.set_active.side_effect = EheimDigitalClientError heater_mock.hub.send_packet.side_effect = EheimDigitalClientError
with pytest.raises(HomeAssistantError): with pytest.raises(HomeAssistantError):
await hass.services.async_call( await hass.services.async_call(
@ -216,7 +219,7 @@ async def test_set_hvac_mode(
blocking=True, blocking=True,
) )
heater_mock.set_active.side_effect = None heater_mock.hub.send_packet.side_effect = None
await hass.services.async_call( await hass.services.async_call(
CLIMATE_DOMAIN, CLIMATE_DOMAIN,
@ -225,19 +228,20 @@ async def test_set_hvac_mode(
blocking=True, blocking=True,
) )
heater_mock.set_active.assert_awaited_with(active=active) calls = [call for call in heater_mock.hub.mock_calls if call[0] == "send_packet"]
assert len(calls) == 2 and calls[1][1][0]["active"] == int(active)
async def test_state_update( async def test_state_update(
hass: HomeAssistant, hass: HomeAssistant,
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
heater_mock: MagicMock, heater_mock: EheimDigitalHeater,
) -> None: ) -> None:
"""Test the climate state update.""" """Test the climate state update."""
heater_mock.temperature_unit = HeaterUnit.FAHRENHEIT heater_mock.heater_data["mUnit"] = int(HeaterUnit.FAHRENHEIT)
heater_mock.is_heating = False heater_mock.heater_data["isHeating"] = int(False)
heater_mock.operation_mode = HeaterMode.BIO heater_mock.heater_data["mode"] = int(HeaterMode.BIO)
await init_integration(hass, mock_config_entry) await init_integration(hass, mock_config_entry)
@ -251,8 +255,8 @@ async def test_state_update(
assert state.attributes["hvac_action"] == HVACAction.IDLE assert state.attributes["hvac_action"] == HVACAction.IDLE
assert state.attributes["preset_mode"] == HEATER_BIO_MODE assert state.attributes["preset_mode"] == HEATER_BIO_MODE
heater_mock.is_active = False heater_mock.heater_data["active"] = int(False)
heater_mock.operation_mode = HeaterMode.SMART heater_mock.heater_data["mode"] = int(HeaterMode.SMART)
await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]() await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]()

View File

@ -4,7 +4,8 @@ from datetime import timedelta
from unittest.mock import AsyncMock, MagicMock, patch from unittest.mock import AsyncMock, MagicMock, patch
from aiohttp import ClientError from aiohttp import ClientError
from eheimdigital.types import EheimDeviceType, LightMode from eheimdigital.classic_led_ctrl import EheimDigitalClassicLEDControl
from eheimdigital.types import EheimDeviceType
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
@ -117,7 +118,7 @@ async def test_dynamic_new_devices(
async def test_turn_off( async def test_turn_off(
hass: HomeAssistant, hass: HomeAssistant,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
classic_led_ctrl_mock: MagicMock, classic_led_ctrl_mock: EheimDigitalClassicLEDControl,
) -> None: ) -> None:
"""Test turning off the light.""" """Test turning off the light."""
await init_integration(hass, mock_config_entry) await init_integration(hass, mock_config_entry)
@ -130,12 +131,18 @@ async def test_turn_off(
await hass.services.async_call( await hass.services.async_call(
LIGHT_DOMAIN, LIGHT_DOMAIN,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "light.mock_classicledcontrol_e_channel_0"}, {ATTR_ENTITY_ID: "light.mock_classicledcontrol_e_channel_1"},
blocking=True, blocking=True,
) )
classic_led_ctrl_mock.set_light_mode.assert_awaited_once_with(LightMode.MAN_MODE) calls = [
classic_led_ctrl_mock.turn_off.assert_awaited_once_with(0) call
for call in classic_led_ctrl_mock.hub.mock_calls
if call[0] == "send_packet"
]
assert len(calls) == 2
assert calls[0][1][0].get("title") == "MAN_MODE"
assert calls[1][1][0]["currentValues"][1] == 0
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -150,7 +157,7 @@ async def test_turn_on_brightness(
hass: HomeAssistant, hass: HomeAssistant,
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
classic_led_ctrl_mock: MagicMock, classic_led_ctrl_mock: EheimDigitalClassicLEDControl,
dim_input: int, dim_input: int,
expected_dim_value: int, expected_dim_value: int,
) -> None: ) -> None:
@ -166,24 +173,30 @@ async def test_turn_on_brightness(
LIGHT_DOMAIN, LIGHT_DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
{ {
ATTR_ENTITY_ID: "light.mock_classicledcontrol_e_channel_0", ATTR_ENTITY_ID: "light.mock_classicledcontrol_e_channel_1",
ATTR_BRIGHTNESS: dim_input, ATTR_BRIGHTNESS: dim_input,
}, },
blocking=True, blocking=True,
) )
classic_led_ctrl_mock.set_light_mode.assert_awaited_once_with(LightMode.MAN_MODE) calls = [
classic_led_ctrl_mock.turn_on.assert_awaited_once_with(expected_dim_value, 0) call
for call in classic_led_ctrl_mock.hub.mock_calls
if call[0] == "send_packet"
]
assert len(calls) == 2
assert calls[0][1][0].get("title") == "MAN_MODE"
assert calls[1][1][0]["currentValues"][1] == expected_dim_value
async def test_turn_on_effect( async def test_turn_on_effect(
hass: HomeAssistant, hass: HomeAssistant,
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
classic_led_ctrl_mock: MagicMock, classic_led_ctrl_mock: EheimDigitalClassicLEDControl,
) -> None: ) -> None:
"""Test turning on the light with an effect value.""" """Test turning on the light with an effect value."""
classic_led_ctrl_mock.light_mode = LightMode.MAN_MODE classic_led_ctrl_mock.clock["mode"] = "MAN_MODE"
await init_integration(hass, mock_config_entry) await init_integration(hass, mock_config_entry)
@ -196,20 +209,26 @@ async def test_turn_on_effect(
LIGHT_DOMAIN, LIGHT_DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
{ {
ATTR_ENTITY_ID: "light.mock_classicledcontrol_e_channel_0", ATTR_ENTITY_ID: "light.mock_classicledcontrol_e_channel_1",
ATTR_EFFECT: EFFECT_DAYCL_MODE, ATTR_EFFECT: EFFECT_DAYCL_MODE,
}, },
blocking=True, blocking=True,
) )
classic_led_ctrl_mock.set_light_mode.assert_awaited_once_with(LightMode.DAYCL_MODE) calls = [
call
for call in classic_led_ctrl_mock.hub.mock_calls
if call[0] == "send_packet"
]
assert len(calls) == 1
assert calls[0][1][0].get("title") == "DAYCL_MODE"
async def test_state_update( async def test_state_update(
hass: HomeAssistant, hass: HomeAssistant,
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
classic_led_ctrl_mock: MagicMock, classic_led_ctrl_mock: EheimDigitalClassicLEDControl,
) -> None: ) -> None:
"""Test the light state update.""" """Test the light state update."""
await init_integration(hass, mock_config_entry) await init_integration(hass, mock_config_entry)
@ -219,11 +238,11 @@ async def test_state_update(
) )
await hass.async_block_till_done() await hass.async_block_till_done()
classic_led_ctrl_mock.light_level = (20, 30) classic_led_ctrl_mock.ccv["currentValues"] = [30, 20]
await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]() await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]()
assert (state := hass.states.get("light.mock_classicledcontrol_e_channel_0")) assert (state := hass.states.get("light.mock_classicledcontrol_e_channel_1"))
assert state.attributes["brightness"] == value_to_brightness((1, 100), 20) assert state.attributes["brightness"] == value_to_brightness((1, 100), 20)
@ -248,6 +267,6 @@ async def test_update_failed(
await hass.async_block_till_done() await hass.async_block_till_done()
assert ( assert (
hass.states.get("light.mock_classicledcontrol_e_channel_0").state hass.states.get("light.mock_classicledcontrol_e_channel_1").state
== STATE_UNAVAILABLE == STATE_UNAVAILABLE
) )

View File

@ -58,20 +58,20 @@ async def test_setup(
( (
"number.mock_heater_temperature_offset", "number.mock_heater_temperature_offset",
0.4, 0.4,
"set_temperature_offset", "offset",
(0.4,), 4,
), ),
( (
"number.mock_heater_night_temperature_offset", "number.mock_heater_night_temperature_offset",
0.4, 0.4,
"set_night_temperature_offset", "nReduce",
(0.4,), 4,
), ),
( (
"number.mock_heater_system_led_brightness", "number.mock_heater_system_led_brightness",
20, 20,
"set_sys_led", "sysLED",
(20,), 20,
), ),
], ],
), ),
@ -81,26 +81,26 @@ async def test_setup(
( (
"number.mock_classicvario_manual_speed", "number.mock_classicvario_manual_speed",
72.1, 72.1,
"set_manual_speed", "rel_manual_motor_speed",
(int(72.1),), int(72.1),
), ),
( (
"number.mock_classicvario_day_speed", "number.mock_classicvario_day_speed",
72.1, 72.1,
"set_day_speed", "rel_motor_speed_day",
(int(72.1),), int(72.1),
), ),
( (
"number.mock_classicvario_night_speed", "number.mock_classicvario_night_speed",
72.1, 72.1,
"set_night_speed", "rel_motor_speed_night",
(int(72.1),), int(72.1),
), ),
( (
"number.mock_classicvario_system_led_brightness", "number.mock_classicvario_system_led_brightness",
20, 20,
"set_sys_led", "sysLED",
(20,), 20,
), ),
], ],
), ),
@ -131,8 +131,8 @@ async def test_set_value(
{ATTR_ENTITY_ID: item[0], ATTR_VALUE: item[1]}, {ATTR_ENTITY_ID: item[0], ATTR_VALUE: item[1]},
blocking=True, blocking=True,
) )
calls = [call for call in device.mock_calls if call[0] == item[2]] calls = [call for call in device.hub.mock_calls if call[0] == "send_packet"]
assert len(calls) == 1 and calls[0][1] == item[3] assert calls[-1][1][0][item[2]] == item[3]
@pytest.mark.usefixtures("classic_vario_mock", "heater_mock") @pytest.mark.usefixtures("classic_vario_mock", "heater_mock")
@ -144,17 +144,23 @@ async def test_set_value(
[ [
( (
"number.mock_heater_temperature_offset", "number.mock_heater_temperature_offset",
"temperature_offset", "heater_data",
"offset",
-11,
-1.1, -1.1,
), ),
( (
"number.mock_heater_night_temperature_offset", "number.mock_heater_night_temperature_offset",
"night_temperature_offset", "heater_data",
2.3, "nReduce",
-23,
-2.3,
), ),
( (
"number.mock_heater_system_led_brightness", "number.mock_heater_system_led_brightness",
"sys_led", "usrdta",
"sysLED",
87,
87, 87,
), ),
], ],
@ -164,23 +170,31 @@ async def test_set_value(
[ [
( (
"number.mock_classicvario_manual_speed", "number.mock_classicvario_manual_speed",
"manual_speed", "classic_vario_data",
"rel_manual_motor_speed",
34,
34, 34,
), ),
( (
"number.mock_classicvario_day_speed", "number.mock_classicvario_day_speed",
"day_speed", "classic_vario_data",
79, "rel_motor_speed_day",
72,
72,
), ),
( (
"number.mock_classicvario_night_speed", "number.mock_classicvario_night_speed",
"night_speed", "classic_vario_data",
12, "rel_motor_speed_night",
20,
20,
), ),
( (
"number.mock_classicvario_system_led_brightness", "number.mock_classicvario_system_led_brightness",
"sys_led", "usrdta",
35, "sysLED",
20,
20,
), ),
], ],
), ),
@ -191,7 +205,7 @@ async def test_state_update(
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
device_name: str, device_name: str,
entity_list: list[tuple[str, str, float]], entity_list: list[tuple[str, str, str, float, float]],
request: pytest.FixtureRequest, request: pytest.FixtureRequest,
) -> None: ) -> None:
"""Test state updates.""" """Test state updates."""
@ -205,7 +219,7 @@ async def test_state_update(
await hass.async_block_till_done() await hass.async_block_till_done()
for item in entity_list: for item in entity_list:
setattr(device, item[1], item[2]) getattr(device, item[1])[item[2]] = item[3]
await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]() await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]()
assert (state := hass.states.get(item[0])) assert (state := hass.states.get(item[0]))
assert state.state == str(item[2]) assert state.state == str(item[4])

View File

@ -59,8 +59,8 @@ async def test_setup(
( (
"select.mock_classicvario_filter_mode", "select.mock_classicvario_filter_mode",
"manual", "manual",
"set_filter_mode", "pumpMode",
(FilterMode.MANUAL,), int(FilterMode.MANUAL),
), ),
], ],
), ),
@ -71,7 +71,7 @@ async def test_set_value(
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
device_name: str, device_name: str,
entity_list: list[tuple[str, float, str, tuple[FilterMode]]], entity_list: list[tuple[str, str, str, int]],
request: pytest.FixtureRequest, request: pytest.FixtureRequest,
) -> None: ) -> None:
"""Test setting a value.""" """Test setting a value."""
@ -91,8 +91,8 @@ async def test_set_value(
{ATTR_ENTITY_ID: item[0], ATTR_OPTION: item[1]}, {ATTR_ENTITY_ID: item[0], ATTR_OPTION: item[1]},
blocking=True, blocking=True,
) )
calls = [call for call in device.mock_calls if call[0] == item[2]] calls = [call for call in device.hub.mock_calls if call[0] == "send_packet"]
assert len(calls) == 1 and calls[0][1] == item[3] assert calls[-1][1][0][item[2]] == item[3]
@pytest.mark.usefixtures("classic_vario_mock", "heater_mock") @pytest.mark.usefixtures("classic_vario_mock", "heater_mock")
@ -104,8 +104,10 @@ async def test_set_value(
[ [
( (
"select.mock_classicvario_filter_mode", "select.mock_classicvario_filter_mode",
"filter_mode", "classic_vario_data",
FilterMode.BIO, "pumpMode",
int(FilterMode.BIO),
"bio",
), ),
], ],
), ),
@ -116,7 +118,7 @@ async def test_state_update(
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
device_name: str, device_name: str,
entity_list: list[tuple[str, str, FilterMode]], entity_list: list[tuple[str, str, str, int, str]],
request: pytest.FixtureRequest, request: pytest.FixtureRequest,
) -> None: ) -> None:
"""Test state updates.""" """Test state updates."""
@ -130,7 +132,7 @@ async def test_state_update(
await hass.async_block_till_done() await hass.async_block_till_done()
for item in entity_list: for item in entity_list:
setattr(device, item[1], item[2]) getattr(device, item[1])[item[2]] = item[3]
await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]() await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]()
assert (state := hass.states.get(item[0])) assert (state := hass.states.get(item[0]))
assert state.state == item[2].name.lower() assert state.state == item[4]

View File

@ -43,35 +43,58 @@ async def test_setup_classic_vario(
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
@pytest.mark.usefixtures("classic_vario_mock")
@pytest.mark.parametrize(
("device_name", "entity_list"),
[
(
"classic_vario_mock",
[
(
"sensor.mock_classicvario_current_speed",
"classic_vario_data",
"rel_speed",
10,
10,
),
(
"sensor.mock_classicvario_error_code",
"classic_vario_data",
"errorCode",
int(FilterErrorCode.ROTOR_STUCK),
"rotor_stuck",
),
(
"sensor.mock_classicvario_remaining_hours_until_service",
"classic_vario_data",
"serviceHour",
100,
str(round(100 / 24, 1)),
),
],
),
],
)
async def test_state_update( async def test_state_update(
hass: HomeAssistant, hass: HomeAssistant,
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
classic_vario_mock: MagicMock, device_name: str,
entity_list: list[tuple[str, str, str, float, float]],
request: pytest.FixtureRequest,
) -> None: ) -> None:
"""Test the sensor state update.""" """Test the sensor state update."""
device: MagicMock = request.getfixturevalue(device_name)
await init_integration(hass, mock_config_entry) await init_integration(hass, mock_config_entry)
await eheimdigital_hub_mock.call_args.kwargs["device_found_callback"]( await eheimdigital_hub_mock.call_args.kwargs["device_found_callback"](
"00:00:00:00:00:03", EheimDeviceType.VERSION_EHEIM_CLASSIC_VARIO device.mac_address, device.device_type
) )
await hass.async_block_till_done() await hass.async_block_till_done()
classic_vario_mock.current_speed = 10 for item in entity_list:
classic_vario_mock.error_code = FilterErrorCode.ROTOR_STUCK getattr(device, item[1])[item[2]] = item[3]
classic_vario_mock.service_hours = 100
await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]() await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]()
assert (state := hass.states.get(item[0]))
assert (state := hass.states.get("sensor.mock_classicvario_current_speed")) assert state.state == str(item[4])
assert state.state == "10"
assert (state := hass.states.get("sensor.mock_classicvario_error_code"))
assert state.state == "rotor_stuck"
assert (
state := hass.states.get(
"sensor.mock_classicvario_remaining_hours_until_service"
)
)
assert state.state == str(round(100 / 24, 1))

View File

@ -11,8 +11,6 @@ from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
SERVICE_TURN_ON, SERVICE_TURN_ON,
STATE_OFF,
STATE_ON,
Platform, Platform,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -77,29 +75,58 @@ async def test_turn_on_off(
blocking=True, blocking=True,
) )
classic_vario_mock.set_active.assert_awaited_once_with(active=active) calls = [
call for call in classic_vario_mock.hub.mock_calls if call[0] == "send_packet"
]
assert len(calls) == 1
assert calls[0][1][0].get("filterActive") == int(active)
@pytest.mark.usefixtures("classic_vario_mock")
@pytest.mark.parametrize(
("device_name", "entity_list"),
[
(
"classic_vario_mock",
[
(
"switch.mock_classicvario",
"classic_vario_data",
"filterActive",
1,
"on",
),
(
"switch.mock_classicvario",
"classic_vario_data",
"filterActive",
0,
"off",
),
],
),
],
)
async def test_state_update( async def test_state_update(
hass: HomeAssistant, hass: HomeAssistant,
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
classic_vario_mock: MagicMock, device_name: str,
entity_list: list[tuple[str, str, str, float, float]],
request: pytest.FixtureRequest,
) -> None: ) -> None:
"""Test the switch state update.""" """Test the switch state update."""
device: MagicMock = request.getfixturevalue(device_name)
await init_integration(hass, mock_config_entry) await init_integration(hass, mock_config_entry)
await eheimdigital_hub_mock.call_args.kwargs["device_found_callback"]( await eheimdigital_hub_mock.call_args.kwargs["device_found_callback"](
"00:00:00:00:00:03", EheimDeviceType.VERSION_EHEIM_CLASSIC_VARIO device.mac_address, device.device_type
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert (state := hass.states.get("switch.mock_classicvario")) for item in entity_list:
assert state.state == STATE_ON getattr(device, item[1])[item[2]] = item[3]
classic_vario_mock.is_active = False
await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]() await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]()
assert (state := hass.states.get(item[0]))
assert (state := hass.states.get("switch.mock_classicvario")) assert state.state == str(item[4])
assert state.state == STATE_OFF

View File

@ -59,14 +59,14 @@ async def test_setup(
( (
"time.mock_heater_day_start_time", "time.mock_heater_day_start_time",
time(9, 0, tzinfo=timezone(timedelta(hours=1))), time(9, 0, tzinfo=timezone(timedelta(hours=1))),
"set_day_start_time", "dayStartT",
(time(9, 0, tzinfo=timezone(timedelta(hours=1))),), 9 * 60,
), ),
( (
"time.mock_heater_night_start_time", "time.mock_heater_night_start_time",
time(19, 0, tzinfo=timezone(timedelta(hours=1))), time(19, 0, tzinfo=timezone(timedelta(hours=1))),
"set_night_start_time", "nightStartT",
(time(19, 0, tzinfo=timezone(timedelta(hours=1))),), 19 * 60,
), ),
], ],
), ),
@ -76,14 +76,14 @@ async def test_setup(
( (
"time.mock_classicvario_day_start_time", "time.mock_classicvario_day_start_time",
time(9, 0, tzinfo=timezone(timedelta(hours=1))), time(9, 0, tzinfo=timezone(timedelta(hours=1))),
"set_day_start_time", "startTime_day",
(time(9, 0, tzinfo=timezone(timedelta(hours=1))),), 9 * 60,
), ),
( (
"time.mock_classicvario_night_start_time", "time.mock_classicvario_night_start_time",
time(19, 0, tzinfo=timezone(timedelta(hours=1))), time(19, 0, tzinfo=timezone(timedelta(hours=1))),
"set_night_start_time", "startTime_night",
(time(19, 0, tzinfo=timezone(timedelta(hours=1))),), 19 * 60,
), ),
], ],
), ),
@ -114,8 +114,8 @@ async def test_set_value(
{ATTR_ENTITY_ID: item[0], ATTR_TIME: item[1]}, {ATTR_ENTITY_ID: item[0], ATTR_TIME: item[1]},
blocking=True, blocking=True,
) )
calls = [call for call in device.mock_calls if call[0] == item[2]] calls = [call for call in device.hub.mock_calls if call[0] == "send_packet"]
assert len(calls) == 1 and calls[0][1] == item[3] assert calls[-1][1][0][item[2]] == item[3]
@pytest.mark.usefixtures("classic_vario_mock", "heater_mock") @pytest.mark.usefixtures("classic_vario_mock", "heater_mock")
@ -127,13 +127,17 @@ async def test_set_value(
[ [
( (
"time.mock_heater_day_start_time", "time.mock_heater_day_start_time",
"day_start_time", "heater_data",
time(9, 0, tzinfo=timezone(timedelta(hours=3))), "dayStartT",
540,
time(9, 0, tzinfo=timezone(timedelta(hours=1))).isoformat(),
), ),
( (
"time.mock_heater_night_start_time", "time.mock_heater_night_start_time",
"night_start_time", "heater_data",
time(19, 0, tzinfo=timezone(timedelta(hours=3))), "nightStartT",
1140,
time(19, 0, tzinfo=timezone(timedelta(hours=1))).isoformat(),
), ),
], ],
), ),
@ -142,13 +146,17 @@ async def test_set_value(
[ [
( (
"time.mock_classicvario_day_start_time", "time.mock_classicvario_day_start_time",
"day_start_time", "classic_vario_data",
time(9, 0, tzinfo=timezone(timedelta(hours=1))), "startTime_day",
540,
time(9, 0, tzinfo=timezone(timedelta(hours=1))).isoformat(),
), ),
( (
"time.mock_classicvario_night_start_time", "time.mock_classicvario_night_start_time",
"night_start_time", "classic_vario_data",
time(22, 0, tzinfo=timezone(timedelta(hours=1))), "startTime_night",
1320,
time(22, 0, tzinfo=timezone(timedelta(hours=1))).isoformat(),
), ),
], ],
), ),
@ -159,7 +167,7 @@ async def test_state_update(
eheimdigital_hub_mock: MagicMock, eheimdigital_hub_mock: MagicMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
device_name: str, device_name: str,
entity_list: list[tuple[str, str, time]], entity_list: list[tuple[str, str, str, float, str]],
request: pytest.FixtureRequest, request: pytest.FixtureRequest,
) -> None: ) -> None:
"""Test state updates.""" """Test state updates."""
@ -173,7 +181,7 @@ async def test_state_update(
await hass.async_block_till_done() await hass.async_block_till_done()
for item in entity_list: for item in entity_list:
setattr(device, item[1], item[2]) getattr(device, item[1])[item[2]] = item[3]
await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]() await eheimdigital_hub_mock.call_args.kwargs["receive_callback"]()
assert (state := hass.states.get(item[0])) assert (state := hass.states.get(item[0]))
assert state.state == item[2].isoformat() assert state.state == item[4]