Add tests for Sensibo (#71148)

* Initial commit

* Check temperature missing

* fix temp is none

* Fix parallell

* Commit to save

* Fix tests

* Fix test_init

* assert 25

* Adjustments tests

* Small removal

* Cleanup

* no hass.data

* Adjustment test_coordinator

* Minor change test_coordinator
This commit is contained in:
G Johansson 2022-05-06 09:05:15 +02:00 committed by GitHub
parent d612b9e0b4
commit 5931f6598a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1506 additions and 6 deletions

View File

@ -1017,12 +1017,6 @@ omit =
homeassistant/components/senseme/fan.py
homeassistant/components/senseme/light.py
homeassistant/components/senseme/switch.py
homeassistant/components/sensibo/__init__.py
homeassistant/components/sensibo/binary_sensor.py
homeassistant/components/sensibo/climate.py
homeassistant/components/sensibo/coordinator.py
homeassistant/components/sensibo/diagnostics.py
homeassistant/components/sensibo/entity.py
homeassistant/components/sensibo/number.py
homeassistant/components/sensibo/select.py
homeassistant/components/sensibo/sensor.py

View File

@ -1 +1,6 @@
"""Tests for the Sensibo integration."""
from __future__ import annotations
from homeassistant.const import CONF_API_KEY
ENTRY_CONFIG = {CONF_API_KEY: "1234567890"}

View File

@ -0,0 +1,45 @@
"""Fixtures for the Sensibo integration."""
from __future__ import annotations
from unittest.mock import patch
import pytest
from homeassistant.components.sensibo.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER
from homeassistant.core import HomeAssistant
from . import ENTRY_CONFIG
from .response import DATA_FROM_API
from tests.common import MockConfigEntry
@pytest.fixture
async def load_int(hass: HomeAssistant) -> MockConfigEntry:
"""Set up the Sensibo integration in Home Assistant."""
config_entry = MockConfigEntry(
domain=DOMAIN,
source=SOURCE_USER,
data=ENTRY_CONFIG,
entry_id="1",
unique_id="username",
version=2,
)
config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
):
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
return config_entry

View File

@ -0,0 +1,400 @@
"""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",
),
},
)

View File

@ -0,0 +1,52 @@
"""The test for the sensibo binary sensor platform."""
from __future__ import annotations
from datetime import timedelta
from unittest.mock import patch
from pytest import MonkeyPatch
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.util import dt
from .response import DATA_FROM_API
from tests.common import async_fire_time_changed
async def test_binary_sensor(
hass: HomeAssistant, load_int: ConfigEntry, monkeypatch: MonkeyPatch
) -> None:
"""Test the Sensibo binary sensor."""
state1 = hass.states.get("binary_sensor.hallway_motion_sensor_alive")
state2 = hass.states.get("binary_sensor.hallway_motion_sensor_main_sensor")
state3 = hass.states.get("binary_sensor.hallway_motion_sensor_motion")
state4 = hass.states.get("binary_sensor.hallway_room_occupied")
assert state1.state == "on"
assert state2.state == "on"
assert state3.state == "on"
assert state4.state == "on"
monkeypatch.setattr(
DATA_FROM_API.parsed["ABC999111"].motion_sensors["AABBCC"], "alive", False
)
monkeypatch.setattr(
DATA_FROM_API.parsed["ABC999111"].motion_sensors["AABBCC"], "motion", False
)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
):
async_fire_time_changed(
hass,
dt.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("binary_sensor.hallway_motion_sensor_alive")
state3 = hass.states.get("binary_sensor.hallway_motion_sensor_motion")
assert state1.state == "off"
assert state3.state == "off"

View File

@ -0,0 +1,601 @@
"""The test for the sensibo binary sensor platform."""
from __future__ import annotations
from datetime import timedelta
from unittest.mock import patch
import pytest
from voluptuous import MultipleInvalid
from homeassistant.components.climate.const import (
ATTR_FAN_MODE,
ATTR_HVAC_MODE,
ATTR_SWING_MODE,
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
DOMAIN as CLIMATE_DOMAIN,
SERVICE_SET_FAN_MODE,
SERVICE_SET_HVAC_MODE,
SERVICE_SET_SWING_MODE,
SERVICE_SET_TEMPERATURE,
)
from homeassistant.components.sensibo.climate import SERVICE_ASSUME_STATE
from homeassistant.components.sensibo.const import DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_STATE,
ATTR_TEMPERATURE,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.util import dt
from .response import DATA_FROM_API
from tests.common import async_fire_time_changed
async def test_climate(hass: HomeAssistant, load_int: ConfigEntry) -> None:
"""Test the Sensibo climate."""
state1 = hass.states.get("climate.hallway")
state2 = hass.states.get("climate.kitchen")
assert state1.state == "heat"
assert state1.attributes == {
"hvac_modes": [
"cool",
"heat",
"dry",
"heat_cool",
"fan_only",
"off",
],
"min_temp": 18,
"max_temp": 20,
"target_temp_step": 1,
"fan_modes": ["quiet", "low", "medium"],
"swing_modes": [
"stopped",
"fixedTop",
"fixedMiddleTop",
],
"current_temperature": 22.4,
"temperature": 25,
"current_humidity": 38,
"fan_mode": "high",
"swing_mode": "stopped",
"friendly_name": "Hallway",
"supported_features": 41,
}
assert state2.state == "off"
async def test_climate_fan(
hass: HomeAssistant, load_int: ConfigEntry, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test the Sensibo climate fan service."""
state1 = hass.states.get("climate.hallway")
assert state1.attributes["fan_mode"] == "high"
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_FAN_MODE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_FAN_MODE: "low"},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.attributes["fan_mode"] == "low"
monkeypatch.setattr(
DATA_FROM_API.parsed["ABC999111"],
"active_features",
[
"timestamp",
"on",
"mode",
"swing",
"targetTemperature",
"horizontalSwing",
"light",
],
)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
):
async_fire_time_changed(
hass,
dt.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
):
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_FAN_MODE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_FAN_MODE: "low"},
blocking=True,
)
await hass.async_block_till_done()
state3 = hass.states.get("climate.hallway")
assert state3.attributes["fan_mode"] == "low"
async def test_climate_swing(
hass: HomeAssistant, load_int: ConfigEntry, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test the Sensibo climate swing service."""
state1 = hass.states.get("climate.hallway")
assert state1.attributes["swing_mode"] == "stopped"
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_SWING_MODE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_SWING_MODE: "fixedTop"},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.attributes["swing_mode"] == "fixedTop"
monkeypatch.setattr(
DATA_FROM_API.parsed["ABC999111"],
"active_features",
[
"timestamp",
"on",
"mode",
"targetTemperature",
"horizontalSwing",
"light",
],
)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
):
async_fire_time_changed(
hass,
dt.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
):
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_SWING_MODE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_SWING_MODE: "fixedTop"},
blocking=True,
)
await hass.async_block_till_done()
state3 = hass.states.get("climate.hallway")
assert state3.attributes["swing_mode"] == "fixedTop"
async def test_climate_temperatures(
hass: HomeAssistant, load_int: ConfigEntry, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test the Sensibo climate temperature service."""
state1 = hass.states.get("climate.hallway")
assert state1.attributes["temperature"] == 25
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_TEMPERATURE: 20},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.attributes["temperature"] == 20
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_TEMPERATURE: 15},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.attributes["temperature"] == 18
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
with pytest.raises(ValueError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_TEMPERATURE: 18.5},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.attributes["temperature"] == 18
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_TEMPERATURE: 24},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.attributes["temperature"] == 20
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_TEMPERATURE: 20},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.attributes["temperature"] == 20
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
with pytest.raises(MultipleInvalid):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{ATTR_ENTITY_ID: state1.entity_id},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.attributes["temperature"] == 20
monkeypatch.setattr(
DATA_FROM_API.parsed["ABC999111"],
"active_features",
[
"timestamp",
"on",
"mode",
"swing",
"horizontalSwing",
"light",
],
)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
):
async_fire_time_changed(
hass,
dt.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_TEMPERATURE: 20},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.attributes["temperature"] == 20
async def test_climate_temperature_is_none(
hass: HomeAssistant, load_int: ConfigEntry, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test the Sensibo climate temperature service no temperature provided."""
monkeypatch.setattr(
DATA_FROM_API.parsed["ABC999111"],
"active_features",
[
"timestamp",
"on",
"mode",
"fanLevel",
"targetTemperature",
"swing",
"horizontalSwing",
"light",
],
)
monkeypatch.setattr(
DATA_FROM_API.parsed["ABC999111"],
"target_temp",
25,
)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
):
async_fire_time_changed(
hass,
dt.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("climate.hallway")
assert state1.attributes["temperature"] == 25
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
):
with pytest.raises(ValueError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{
ATTR_ENTITY_ID: state1.entity_id,
ATTR_TARGET_TEMP_HIGH: 30,
ATTR_TARGET_TEMP_LOW: 20,
},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.attributes["temperature"] == 25
async def test_climate_hvac_mode(
hass: HomeAssistant, load_int: ConfigEntry, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test the Sensibo climate hvac mode service."""
monkeypatch.setattr(
DATA_FROM_API.parsed["ABC999111"],
"active_features",
[
"timestamp",
"on",
"mode",
"fanLevel",
"targetTemperature",
"swing",
"horizontalSwing",
"light",
],
)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
):
async_fire_time_changed(
hass,
dt.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("climate.hallway")
assert state1.state == "heat"
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_HVAC_MODE: "off"},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.state == "off"
monkeypatch.setattr(DATA_FROM_API.parsed["ABC999111"], "device_on", False)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
):
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",
return_value=DATA_FROM_API,
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_HVAC_MODE: "heat"},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.state == "heat"
async def test_climate_on_off(
hass: HomeAssistant, load_int: ConfigEntry, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test the Sensibo climate on/off service."""
monkeypatch.setattr(DATA_FROM_API.parsed["ABC999111"], "hvac_mode", "heat")
monkeypatch.setattr(DATA_FROM_API.parsed["ABC999111"], "device_on", True)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
):
async_fire_time_changed(
hass,
dt.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("climate.hallway")
assert state1.state == "heat"
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: state1.entity_id},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.state == "off"
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: state1.entity_id},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.state == "heat"
async def test_climate_service_failed(
hass: HomeAssistant, load_int: ConfigEntry, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test the Sensibo climate service failed."""
monkeypatch.setattr(DATA_FROM_API.parsed["ABC999111"], "hvac_mode", "heat")
monkeypatch.setattr(DATA_FROM_API.parsed["ABC999111"], "device_on", True)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
):
async_fire_time_changed(
hass,
dt.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("climate.hallway")
assert state1.state == "heat"
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Error", "failureReason": "Did not work"}},
):
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: state1.entity_id},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.state == "heat"
async def test_climate_assumed_state(
hass: HomeAssistant, load_int: ConfigEntry, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test the Sensibo climate assumed state service."""
monkeypatch.setattr(DATA_FROM_API.parsed["ABC999111"], "hvac_mode", "heat")
monkeypatch.setattr(DATA_FROM_API.parsed["ABC999111"], "device_on", True)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
):
async_fire_time_changed(
hass,
dt.utcnow() + timedelta(minutes=5),
)
await hass.async_block_till_done()
state1 = hass.states.get("climate.hallway")
assert state1.state == "heat"
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
DOMAIN,
SERVICE_ASSUME_STATE,
{ATTR_ENTITY_ID: state1.entity_id, ATTR_STATE: "off"},
blocking=True,
)
await hass.async_block_till_done()
state2 = hass.states.get("climate.hallway")
assert state2.state == "off"

View File

@ -0,0 +1,91 @@
"""The test for the sensibo coordinator."""
from __future__ import annotations
from datetime import timedelta
from unittest.mock import patch
from pysensibo.exceptions import AuthenticationError, SensiboError
from pysensibo.model import SensiboData
import pytest
from homeassistant.components.sensibo.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from homeassistant.util import dt
from . import ENTRY_CONFIG
from .response import DATA_FROM_API
from tests.common import MockConfigEntry, async_fire_time_changed
async def test_coordinator(
hass: HomeAssistant, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test the Sensibo coordinator with errors."""
config_entry = MockConfigEntry(
domain=DOMAIN,
source=SOURCE_USER,
data=ENTRY_CONFIG,
entry_id="1",
unique_id="username",
version=2,
)
config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
) as mock_data, patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
):
monkeypatch.setattr(DATA_FROM_API.parsed["ABC999111"], "hvac_mode", "heat")
monkeypatch.setattr(DATA_FROM_API.parsed["ABC999111"], "device_on", True)
mock_data.return_value = DATA_FROM_API
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("climate.hallway")
assert state.state == "heat"
mock_data.reset_mock()
mock_data.side_effect = SensiboError("info")
async_fire_time_changed(hass, dt.utcnow() + timedelta(minutes=1))
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("climate.hallway")
assert state.state == STATE_UNAVAILABLE
mock_data.reset_mock()
mock_data.return_value = SensiboData(raw={}, parsed={})
mock_data.side_effect = None
async_fire_time_changed(hass, dt.utcnow() + timedelta(minutes=3))
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("climate.hallway")
assert state.state == STATE_UNAVAILABLE
mock_data.reset_mock()
monkeypatch.setattr(DATA_FROM_API.parsed["ABC999111"], "hvac_mode", "heat")
monkeypatch.setattr(DATA_FROM_API.parsed["ABC999111"], "device_on", True)
mock_data.return_value = DATA_FROM_API
mock_data.side_effect = None
async_fire_time_changed(hass, dt.utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("climate.hallway")
assert state.state == "heat"
mock_data.reset_mock()
mock_data.side_effect = AuthenticationError("info")
async_fire_time_changed(hass, dt.utcnow() + timedelta(minutes=7))
await hass.async_block_till_done()
mock_data.assert_called_once()
state = hass.states.get("climate.hallway")
assert state.state == STATE_UNAVAILABLE

View File

@ -0,0 +1,48 @@
"""Test Sensibo diagnostics."""
from __future__ import annotations
import aiohttp
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from tests.components.diagnostics import get_diagnostics_for_config_entry
async def test_diagnostics(
hass: HomeAssistant, hass_client: aiohttp.client, load_int: ConfigEntry
):
"""Test generating diagnostics for a config entry."""
entry = load_int
diag = await get_diagnostics_for_config_entry(hass, hass_client, entry)
assert diag == {
"status": "success",
"result": [
{
"id": "**REDACTED**",
"qrId": "**REDACTED**",
"room": {"uid": "**REDACTED**", "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": "**REDACTED**",
"accessPoint": {"ssid": "**REDACTED**", "password": None},
"macAddress": "**REDACTED**",
"autoOffMinutes": None,
"autoOffEnabled": False,
"antiMoldTimer": None,
"antiMoldConfig": None,
}
],
}

View File

@ -0,0 +1,132 @@
"""The test for the sensibo entity."""
from __future__ import annotations
from datetime import timedelta
from unittest.mock import patch
import pytest
from homeassistant.components.climate.const import (
ATTR_FAN_MODE,
DOMAIN as CLIMATE_DOMAIN,
SERVICE_SET_FAN_MODE,
)
from homeassistant.components.number.const import (
ATTR_VALUE,
DOMAIN as NUMBER_DOMAIN,
SERVICE_SET_VALUE,
)
from homeassistant.components.sensibo.const import SENSIBO_ERRORS
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.helpers import device_registry as dr, entity_registry as er
from homeassistant.util import dt
from .response import DATA_FROM_API
from tests.common import async_fire_time_changed
async def test_entity(hass: HomeAssistant, load_int: ConfigEntry) -> None:
"""Test the Sensibo climate."""
state1 = hass.states.get("climate.hallway")
assert state1
dr_reg = dr.async_get(hass)
dr_entries = dr.async_entries_for_config_entry(dr_reg, load_int.entry_id)
dr_entry: dr.DeviceEntry
for dr_entry in dr_entries:
if dr_entry.name == "Hallway":
assert dr_entry.identifiers == {("sensibo", "ABC999111")}
device_id = dr_entry.id
er_reg = er.async_get(hass)
er_entries = er.async_entries_for_device(
er_reg, device_id, include_disabled_entities=True
)
er_entry: er.RegistryEntry
for er_entry in er_entries:
if er_entry.name == "Hallway":
assert er_entry.unique_id == "Hallway"
@pytest.mark.parametrize("p_error", SENSIBO_ERRORS)
async def test_entity_send_command(
hass: HomeAssistant, p_error: Exception, load_int: ConfigEntry
) -> None:
"""Test the Sensibo send command with error."""
state = hass.states.get("climate.hallway")
assert state
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
return_value={"result": {"status": "Success"}},
):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_FAN_MODE,
{ATTR_ENTITY_ID: state.entity_id, ATTR_FAN_MODE: "low"},
blocking=True,
)
await hass.async_block_till_done()
state = hass.states.get("climate.hallway")
assert state.attributes["fan_mode"] == "low"
with patch(
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
side_effect=p_error,
):
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_FAN_MODE,
{ATTR_ENTITY_ID: state.entity_id, ATTR_FAN_MODE: "low"},
blocking=True,
)
state = hass.states.get("climate.hallway")
assert state.attributes["fan_mode"] == "low"
async def test_entity_send_command_calibration(
hass: HomeAssistant, load_int: ConfigEntry
) -> 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=DATA_FROM_API,
):
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"
with 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: state.entity_id, ATTR_VALUE: 0.2},
blocking=True,
)
state = hass.states.get("number.hallway_temperature_calibration")
assert state.state == "0.2"

View File

@ -0,0 +1,132 @@
"""Test for Sensibo component Init."""
from __future__ import annotations
from unittest.mock import patch
from homeassistant import config_entries
from homeassistant.components.sensibo.const import DOMAIN
from homeassistant.components.sensibo.util import NoUsernameError
from homeassistant.config_entries import SOURCE_USER
from homeassistant.core import HomeAssistant
from . import ENTRY_CONFIG
from .response import DATA_FROM_API
from tests.common import MockConfigEntry
async def test_setup_entry(hass: HomeAssistant) -> None:
"""Test setup entry."""
entry = MockConfigEntry(
domain=DOMAIN,
source=SOURCE_USER,
data=ENTRY_CONFIG,
entry_id="1",
unique_id="12",
version=2,
)
entry.add_to_hass(hass)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state == config_entries.ConfigEntryState.LOADED
async def test_migrate_entry(hass: HomeAssistant) -> None:
"""Test migrate entry unique id."""
entry = MockConfigEntry(
domain=DOMAIN,
source=SOURCE_USER,
data=ENTRY_CONFIG,
entry_id="1",
unique_id="12",
version=1,
)
entry.add_to_hass(hass)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state == config_entries.ConfigEntryState.LOADED
assert entry.version == 2
assert entry.unique_id == "username"
async def test_migrate_entry_fails(hass: HomeAssistant) -> None:
"""Test migrate entry unique id."""
entry = MockConfigEntry(
domain=DOMAIN,
source=SOURCE_USER,
data=ENTRY_CONFIG,
entry_id="1",
unique_id="12",
version=1,
)
entry.add_to_hass(hass)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
side_effect=NoUsernameError("No username returned"),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state == config_entries.ConfigEntryState.MIGRATION_ERROR
assert entry.version == 1
assert entry.unique_id == "12"
async def test_unload_entry(hass: HomeAssistant) -> None:
"""Test unload an entry."""
entry = MockConfigEntry(
domain=DOMAIN,
source=SOURCE_USER,
data=ENTRY_CONFIG,
entry_id="1",
unique_id="12",
version="2",
)
entry.add_to_hass(hass)
with patch(
"homeassistant.components.sensibo.coordinator.SensiboClient.async_get_devices_data",
return_value=DATA_FROM_API,
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_devices",
return_value={"result": [{"id": "xyzxyz"}, {"id": "abcabc"}]},
), patch(
"homeassistant.components.sensibo.util.SensiboClient.async_get_me",
return_value={"result": {"username": "username"}},
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state == config_entries.ConfigEntryState.LOADED
assert await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done()
assert entry.state is config_entries.ConfigEntryState.NOT_LOADED