diff --git a/.coveragerc b/.coveragerc index 898a14b9c86..2a8e6cdec9a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1020,10 +1020,6 @@ omit = homeassistant/components/senseme/fan.py homeassistant/components/senseme/light.py homeassistant/components/senseme/switch.py - homeassistant/components/sensibo/number.py - homeassistant/components/sensibo/select.py - homeassistant/components/sensibo/sensor.py - homeassistant/components/sensibo/update.py homeassistant/components/senz/__init__.py homeassistant/components/senz/api.py homeassistant/components/senz/climate.py diff --git a/tests/components/sensibo/fixtures/data.json b/tests/components/sensibo/fixtures/data.json index c75423fe464..c787ea5592c 100644 --- a/tests/components/sensibo/fixtures/data.json +++ b/tests/components/sensibo/fixtures/data.json @@ -61,7 +61,7 @@ "firmwareType": "esp8266ex", "productModel": "skyv2", "configGroup": "stable", - "currentlyAvailableFirmwareVersion": "SKY30046", + "currentlyAvailableFirmwareVersion": "SKY30048", "cleanFiltersNotificationEnabled": false, "shouldShowFilterCleaningNotification": false, "isGeofenceOnExitEnabled": false, diff --git a/tests/components/sensibo/response.py b/tests/components/sensibo/response.py deleted file mode 100644 index e6b39b81881..00000000000 --- a/tests/components/sensibo/response.py +++ /dev/null @@ -1,400 +0,0 @@ -"""Test api response for the Sensibo integration.""" -from __future__ import annotations - -from pysensibo.model import MotionSensor, SensiboData, SensiboDevice - -DATA_FROM_API = SensiboData( - raw={ - "status": "success", - "result": [ - { - "id": "ABC999111", - "qrId": "AAAAAAAAAA", - "room": {"uid": "99TT99TT", "name": "Hallway", "icon": "Lounge"}, - "acState": { - "timestamp": { - "time": "2022-04-30T19:58:15.544787Z", - "secondsAgo": 0, - }, - "on": False, - "mode": "fan", - "fanLevel": "high", - "swing": "stopped", - "horizontalSwing": "stopped", - "light": "on", - }, - "location": { - "id": "ZZZZZZZZZZZZ", - "name": "Home", - "latLon": [58.9806976, 20.5864297], - "address": ["Sealand 99", "Some county"], - "country": "United Country", - "createTime": { - "time": "2020-03-21T15:44:15Z", - "secondsAgo": 66543240, - }, - "updateTime": None, - "features": [], - "geofenceTriggerRadius": 200, - "subscription": None, - "technician": None, - "shareAnalytics": False, - "occupancy": "n/a", - }, - "accessPoint": {"ssid": "SENSIBO-I-99999", "password": None}, - "macAddress": "00:02:00:B6:00:00", - "autoOffMinutes": None, - "autoOffEnabled": False, - "antiMoldTimer": None, - "antiMoldConfig": None, - } - ], - }, - parsed={ - "ABC999111": SensiboDevice( - id="ABC999111", - mac="00:02:00:B6:00:00", - name="Hallway", - ac_states={ - "timestamp": {"time": "2022-04-30T19:58:15.544787Z", "secondsAgo": 0}, - "on": False, - "mode": "heat", - "fanLevel": "high", - "swing": "stopped", - "horizontalSwing": "stopped", - "light": "on", - }, - temp=22.4, - humidity=38, - target_temp=25, - hvac_mode="heat", - device_on=True, - fan_mode="high", - swing_mode="stopped", - horizontal_swing_mode="stopped", - light_mode="on", - available=True, - hvac_modes=["cool", "heat", "dry", "auto", "fan", "off"], - fan_modes=["quiet", "low", "medium"], - swing_modes=[ - "stopped", - "fixedTop", - "fixedMiddleTop", - ], - horizontal_swing_modes=[ - "stopped", - "fixedLeft", - "fixedCenterLeft", - ], - light_modes=["on", "off"], - temp_unit="C", - temp_list=[18, 19, 20], - temp_step=1, - active_features=[ - "timestamp", - "on", - "mode", - "fanLevel", - "swing", - "targetTemperature", - "horizontalSwing", - "light", - ], - full_features={ - "targetTemperature", - "fanLevel", - "swing", - "horizontalSwing", - "light", - }, - state="heat", - fw_ver="SKY30046", - fw_ver_available="SKY30046", - fw_type="esp8266ex", - model="skyv2", - calibration_temp=0.1, - calibration_hum=0.1, - full_capabilities={ - "modes": { - "cool": { - "temperatures": { - "F": { - "isNative": False, - "values": [ - 64, - 66, - 68, - ], - }, - "C": { - "isNative": True, - "values": [ - 18, - 19, - 20, - ], - }, - }, - "fanLevels": [ - "quiet", - "low", - "medium", - ], - "swing": [ - "stopped", - "fixedTop", - "fixedMiddleTop", - ], - "horizontalSwing": [ - "stopped", - "fixedLeft", - "fixedCenterLeft", - ], - "light": ["on", "off"], - }, - "heat": { - "temperatures": { - "F": { - "isNative": False, - "values": [ - 63, - 64, - 66, - ], - }, - "C": { - "isNative": True, - "values": [ - 17, - 18, - 19, - ], - }, - }, - "fanLevels": ["quiet", "low", "medium"], - "swing": [ - "stopped", - "fixedTop", - "fixedMiddleTop", - ], - "horizontalSwing": [ - "stopped", - "fixedLeft", - "fixedCenterLeft", - ], - "light": ["on", "off"], - }, - "dry": { - "temperatures": { - "F": { - "isNative": False, - "values": [ - 64, - 66, - 68, - ], - }, - "C": { - "isNative": True, - "values": [ - 18, - 19, - 20, - ], - }, - }, - "swing": [ - "stopped", - "fixedTop", - "fixedMiddleTop", - ], - "horizontalSwing": [ - "stopped", - "fixedLeft", - "fixedCenterLeft", - ], - "light": ["on", "off"], - }, - "auto": { - "temperatures": { - "F": { - "isNative": False, - "values": [ - 64, - 66, - 68, - ], - }, - "C": { - "isNative": True, - "values": [ - 18, - 19, - 20, - ], - }, - }, - "fanLevels": [ - "quiet", - "low", - "medium", - ], - "swing": [ - "stopped", - "fixedTop", - "fixedMiddleTop", - ], - "horizontalSwing": [ - "stopped", - "fixedLeft", - "fixedCenterLeft", - ], - "light": ["on", "off"], - }, - "fan": { - "temperatures": {}, - "fanLevels": [ - "quiet", - "low", - ], - "swing": [ - "stopped", - "fixedTop", - "fixedMiddleTop", - ], - "horizontalSwing": [ - "stopped", - "fixedLeft", - "fixedCenterLeft", - ], - "light": ["on", "off"], - }, - } - }, - motion_sensors={ - "AABBCC": MotionSensor( - id="AABBCC", - alive=True, - motion=True, - fw_ver="V17", - fw_type="nrf52", - is_main_sensor=True, - battery_voltage=3000, - humidity=57, - temperature=23.9, - model="motion_sensor", - rssi=-72, - ) - }, - pm25=None, - room_occupied=True, - update_available=False, - schedules={}, - pure_boost_enabled=None, - pure_sensitivity=None, - pure_ac_integration=None, - pure_geo_integration=None, - pure_measure_integration=None, - timer_on=False, - timer_id=None, - timer_state_on=None, - timer_time=None, - smart_on=False, - smart_type="temperature", - smart_low_temp_threshold=0.0, - smart_high_temp_threshold=27.5, - smart_low_state={ - "on": True, - "targetTemperature": 21, - "temperatureUnit": "C", - "mode": "heat", - "fanLevel": "low", - "swing": "stopped", - "horizontalSwing": "stopped", - "light": "on", - }, - smart_high_state={ - "on": True, - "targetTemperature": 21, - "temperatureUnit": "C", - "mode": "cool", - "fanLevel": "high", - "swing": "stopped", - "horizontalSwing": "stopped", - "light": "on", - }, - filter_clean=False, - filter_last_reset="2022-03-12T15:24:26Z", - ), - "AAZZAAZZ": SensiboDevice( - id="AAZZAAZZ", - mac="00:01:00:01:00:01", - name="Kitchen", - ac_states={ - "timestamp": {"time": "2022-04-30T19:58:15.568753Z", "secondsAgo": 0}, - "on": False, - "mode": "fan", - "fanLevel": "low", - "light": "on", - }, - temp=None, - humidity=None, - target_temp=None, - hvac_mode="off", - device_on=False, - fan_mode="low", - swing_mode=None, - horizontal_swing_mode=None, - light_mode="on", - available=True, - hvac_modes=["fan", "off"], - fan_modes=["low", "high"], - swing_modes=None, - horizontal_swing_modes=None, - light_modes=["on", "dim", "off"], - temp_unit="C", - temp_list=[0, 1], - temp_step=1, - active_features=["timestamp", "on", "mode", "fanLevel", "light"], - full_features={"light", "targetTemperature", "fanLevel"}, - state="off", - fw_ver="PUR00111", - fw_ver_available="PUR00111", - fw_type="pure-esp32", - model="pure", - calibration_temp=0.0, - calibration_hum=0.0, - full_capabilities={ - "modes": { - "fan": { - "temperatures": {}, - "fanLevels": ["low", "high"], - "light": ["on", "dim", "off"], - } - } - }, - motion_sensors={}, - pm25=1, - room_occupied=None, - update_available=False, - schedules={}, - pure_boost_enabled=False, - pure_sensitivity="N", - pure_ac_integration=False, - pure_geo_integration=False, - pure_measure_integration=True, - timer_on=None, - timer_id=None, - timer_state_on=None, - timer_time=None, - smart_on=None, - smart_type=None, - smart_low_temp_threshold=None, - smart_high_temp_threshold=None, - smart_low_state=None, - smart_high_state=None, - filter_clean=False, - filter_last_reset="2022-04-23T15:58:45Z", - ), - }, -) diff --git a/tests/components/sensibo/test_entity.py b/tests/components/sensibo/test_entity.py index 27e0f4df772..bf512f9f220 100644 --- a/tests/components/sensibo/test_entity.py +++ b/tests/components/sensibo/test_entity.py @@ -1,8 +1,7 @@ """The test for the sensibo entity.""" from __future__ import annotations -from datetime import timedelta -from unittest.mock import patch +from unittest.mock import AsyncMock, patch from pysensibo.model import SensiboData import pytest @@ -23,9 +22,6 @@ from homeassistant.const import ATTR_ENTITY_ID from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import device_registry as dr, entity_registry as er -from homeassistant.util import dt - -from tests.common import async_fire_time_changed async def test_entity( @@ -98,26 +94,13 @@ async def test_entity_send_command( async def test_entity_send_command_calibration( - hass: HomeAssistant, load_int: ConfigEntry, get_data: SensiboData + hass: HomeAssistant, + entity_registry_enabled_by_default: AsyncMock, + load_int: ConfigEntry, + get_data: SensiboData, ) -> None: """Test the Sensibo send command for calibration.""" - registry = er.async_get(hass) - registry.async_update_entity( - "number.hallway_temperature_calibration", disabled_by=None - ) - await hass.async_block_till_done() - - with patch( - "homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", - return_value=get_data, - ): - async_fire_time_changed( - hass, - dt.utcnow() + timedelta(minutes=5), - ) - await hass.async_block_till_done() - state = hass.states.get("number.hallway_temperature_calibration") assert state.state == "0.1" diff --git a/tests/components/sensibo/test_number.py b/tests/components/sensibo/test_number.py new file mode 100644 index 00000000000..ed60d6653e9 --- /dev/null +++ b/tests/components/sensibo/test_number.py @@ -0,0 +1,101 @@ +"""The test for the sensibo number platform.""" +from __future__ import annotations + +from datetime import timedelta +from unittest.mock import AsyncMock, patch + +from pysensibo.model import SensiboData +import pytest +from pytest import MonkeyPatch + +from homeassistant.components.number.const import ( + ATTR_VALUE, + DOMAIN as NUMBER_DOMAIN, + SERVICE_SET_VALUE, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.util import dt + +from tests.common import async_fire_time_changed + + +async def test_number( + hass: HomeAssistant, + entity_registry_enabled_by_default: AsyncMock, + load_int: ConfigEntry, + monkeypatch: MonkeyPatch, + get_data: SensiboData, +) -> None: + """Test the Sensibo number.""" + + state1 = hass.states.get("number.hallway_temperature_calibration") + state2 = hass.states.get("number.hallway_humidity_calibration") + assert state1.state == "0.1" + assert state2.state == "0.0" + + monkeypatch.setattr(get_data.parsed["ABC999111"], "calibration_temp", 0.2) + + with patch( + "homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", + return_value=get_data, + ): + async_fire_time_changed( + hass, + dt.utcnow() + timedelta(minutes=5), + ) + await hass.async_block_till_done() + + state1 = hass.states.get("number.hallway_temperature_calibration") + assert state1.state == "0.2" + + +async def test_number_set_value( + hass: HomeAssistant, + entity_registry_enabled_by_default: AsyncMock, + load_int: ConfigEntry, + get_data: SensiboData, +) -> None: + """Test the Sensibo number service.""" + + state1 = hass.states.get("number.hallway_temperature_calibration") + assert state1.state == "0.1" + + with patch( + "homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", + return_value=get_data, + ), patch( + "homeassistant.components.sensibo.util.SensiboClient.async_set_calibration", + return_value={"status": "failure"}, + ): + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + {ATTR_ENTITY_ID: state1.entity_id, ATTR_VALUE: "0.2"}, + blocking=True, + ) + await hass.async_block_till_done() + + state2 = hass.states.get("number.hallway_temperature_calibration") + assert state2.state == "0.1" + + with patch( + "homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", + return_value=get_data, + ), patch( + "homeassistant.components.sensibo.util.SensiboClient.async_set_calibration", + return_value={"status": "success"}, + ): + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + {ATTR_ENTITY_ID: state1.entity_id, ATTR_VALUE: "0.2"}, + blocking=True, + ) + await hass.async_block_till_done() + + state2 = hass.states.get("number.hallway_temperature_calibration") + assert state2.state == "0.2" diff --git a/tests/components/sensibo/test_select.py b/tests/components/sensibo/test_select.py new file mode 100644 index 00000000000..ce361e224c9 --- /dev/null +++ b/tests/components/sensibo/test_select.py @@ -0,0 +1,163 @@ +"""The test for the sensibo select platform.""" +from __future__ import annotations + +from datetime import timedelta +from unittest.mock import patch + +from pysensibo.model import SensiboData +import pytest +from pytest import MonkeyPatch + +from homeassistant.components.select.const import ( + ATTR_OPTION, + DOMAIN as SELECT_DOMAIN, + SERVICE_SELECT_OPTION, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.util import dt + +from tests.common import async_fire_time_changed + + +async def test_select( + hass: HomeAssistant, + load_int: ConfigEntry, + monkeypatch: MonkeyPatch, + get_data: SensiboData, +) -> None: + """Test the Sensibo select.""" + + state1 = hass.states.get("select.hallway_horizontal_swing") + assert state1.state == "stopped" + + monkeypatch.setattr( + get_data.parsed["ABC999111"], "horizontal_swing_mode", "fixedLeft" + ) + + with patch( + "homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", + return_value=get_data, + ): + async_fire_time_changed( + hass, + dt.utcnow() + timedelta(minutes=5), + ) + await hass.async_block_till_done() + + state1 = hass.states.get("select.hallway_horizontal_swing") + assert state1.state == "fixedLeft" + + +async def test_select_set_option( + hass: HomeAssistant, + load_int: ConfigEntry, + monkeypatch: MonkeyPatch, + get_data: SensiboData, +) -> None: + """Test the Sensibo select service.""" + + monkeypatch.setattr( + get_data.parsed["ABC999111"], + "active_features", + [ + "timestamp", + "on", + "mode", + "targetTemperature", + "light", + ], + ) + + with patch( + "homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", + return_value=get_data, + ): + async_fire_time_changed( + hass, + dt.utcnow() + timedelta(minutes=5), + ) + await hass.async_block_till_done() + + state1 = hass.states.get("select.hallway_horizontal_swing") + assert state1.state == "stopped" + + with patch( + "homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", + return_value=get_data, + ), patch( + "homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property", + return_value={"result": {"status": "failed"}}, + ): + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + {ATTR_ENTITY_ID: state1.entity_id, ATTR_OPTION: "fixedLeft"}, + blocking=True, + ) + await hass.async_block_till_done() + + state2 = hass.states.get("select.hallway_horizontal_swing") + assert state2.state == "stopped" + + monkeypatch.setattr( + get_data.parsed["ABC999111"], + "active_features", + [ + "timestamp", + "on", + "mode", + "targetTemperature", + "horizontalSwing", + "light", + ], + ) + + with patch( + "homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", + return_value=get_data, + ): + async_fire_time_changed( + hass, + dt.utcnow() + timedelta(minutes=5), + ) + await hass.async_block_till_done() + + with patch( + "homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", + ), patch( + "homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property", + return_value={"result": {"status": "Failed", "failureReason": "No connection"}}, + ): + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + {ATTR_ENTITY_ID: state1.entity_id, ATTR_OPTION: "fixedLeft"}, + blocking=True, + ) + await hass.async_block_till_done() + + state2 = hass.states.get("select.hallway_horizontal_swing") + assert state2.state == "stopped" + + with patch( + "homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data", + return_value=get_data, + ), patch( + "homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property", + return_value={"result": {"status": "Success"}}, + ): + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + {ATTR_ENTITY_ID: state1.entity_id, ATTR_OPTION: "fixedLeft"}, + blocking=True, + ) + await hass.async_block_till_done() + + state2 = hass.states.get("select.hallway_horizontal_swing") + assert state2.state == "fixedLeft" diff --git a/tests/components/sensibo/test_sensor.py b/tests/components/sensibo/test_sensor.py new file mode 100644 index 00000000000..413b62f6b9f --- /dev/null +++ b/tests/components/sensibo/test_sensor.py @@ -0,0 +1,50 @@ +"""The test for the sensibo select platform.""" +from __future__ import annotations + +from datetime import timedelta +from unittest.mock import patch + +from pysensibo.model import SensiboData +from pytest import MonkeyPatch + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.util import dt + +from tests.common import async_fire_time_changed + + +async def test_sensor( + hass: HomeAssistant, + load_int: ConfigEntry, + monkeypatch: MonkeyPatch, + get_data: SensiboData, +) -> None: + """Test the Sensibo sensor.""" + + state1 = hass.states.get("sensor.hallway_motion_sensor_battery_voltage") + state2 = hass.states.get("sensor.kitchen_pm2_5") + assert state1.state == "3000" + assert state2.state == "1" + assert state2.attributes == { + "state_class": "measurement", + "unit_of_measurement": "µg/m³", + "device_class": "pm25", + "icon": "mdi:air-filter", + "friendly_name": "Kitchen PM2.5", + } + + monkeypatch.setattr(get_data.parsed["AAZZAAZZ"], "pm25", 2) + + with patch( + "homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", + return_value=get_data, + ): + async_fire_time_changed( + hass, + dt.utcnow() + timedelta(minutes=5), + ) + await hass.async_block_till_done() + + state1 = hass.states.get("sensor.kitchen_pm2_5") + assert state1.state == "2" diff --git a/tests/components/sensibo/test_update.py b/tests/components/sensibo/test_update.py new file mode 100644 index 00000000000..11b019d111e --- /dev/null +++ b/tests/components/sensibo/test_update.py @@ -0,0 +1,47 @@ +"""The test for the sensibo update platform.""" +from __future__ import annotations + +from datetime import timedelta +from unittest.mock import patch + +from pysensibo.model import SensiboData +from pytest import MonkeyPatch + +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import STATE_OFF, STATE_ON +from homeassistant.core import HomeAssistant +from homeassistant.util import dt + +from tests.common import async_fire_time_changed + + +async def test_select( + hass: HomeAssistant, + load_int: ConfigEntry, + monkeypatch: MonkeyPatch, + get_data: SensiboData, +) -> None: + """Test the Sensibo update.""" + + state1 = hass.states.get("update.hallway_update_available") + state2 = hass.states.get("update.kitchen_update_available") + assert state1.state == STATE_ON + assert state1.attributes["installed_version"] == "SKY30046" + assert state1.attributes["latest_version"] == "SKY30048" + assert state1.attributes["title"] == "skyv2" + assert state2.state == STATE_OFF + + monkeypatch.setattr(get_data.parsed["ABC999111"], "fw_ver", "SKY30048") + + with patch( + "homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data", + return_value=get_data, + ): + async_fire_time_changed( + hass, + dt.utcnow() + timedelta(minutes=5), + ) + await hass.async_block_till_done() + + state1 = hass.states.get("update.hallway_update_available") + assert state1.state == STATE_OFF