mirror of
https://github.com/home-assistant/core.git
synced 2026-08-28 10:16:02 -05:00
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
313 lines
12 KiB
Python
313 lines
12 KiB
Python
"""Tests for the nexia sensor platform."""
|
|
|
|
from datetime import timedelta
|
|
import inspect
|
|
from unittest.mock import NonCallableMock
|
|
|
|
from freezegun.api import FrozenDateTimeFactory
|
|
from nexia.home import NexiaHome
|
|
from nexia.sensor import NexiaSensor
|
|
import pytest
|
|
|
|
from homeassistant.components.nexia.coordinator import (
|
|
DEFAULT_UPDATE_RATE as COORDINATOR_UPDATE_RATE,
|
|
)
|
|
from homeassistant.components.sensor import SensorDeviceClass
|
|
from homeassistant.config_entries import ConfigEntryState
|
|
from homeassistant.const import PERCENTAGE, UnitOfTemperature
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.device_registry import DeviceRegistry
|
|
from homeassistant.helpers.entity_registry import EntityRegistry
|
|
|
|
from .conftest import setup_integration
|
|
|
|
from tests.common import async_fire_time_changed
|
|
|
|
|
|
async def test_create_sensors(hass: HomeAssistant, patch_nexia_home: NexiaHome) -> None:
|
|
"""Test creation of sensors."""
|
|
|
|
await setup_integration(hass, patch_nexia_home)
|
|
|
|
state = hass.states.get("sensor.nick_office_nick_office_temperature")
|
|
assert state is not None
|
|
assert round(float(state.state)) == 23
|
|
|
|
expected_attributes = {
|
|
"attribution": "Data provided by Trane Technologies",
|
|
"device_class": "temperature",
|
|
"friendly_name": "Nick Office Temperature",
|
|
"unit_of_measurement": UnitOfTemperature.CELSIUS,
|
|
}
|
|
# Only test for a subset of attributes in case
|
|
# HA changes the implementation and a new one appears
|
|
assert all(
|
|
state.attributes[key] == value for key, value in expected_attributes.items()
|
|
)
|
|
|
|
state = hass.states.get("sensor.nick_office_nick_office_zone_setpoint_status")
|
|
assert state is not None
|
|
assert state.state == "Permanent Hold"
|
|
expected_attributes = {
|
|
"attribution": "Data provided by Trane Technologies",
|
|
"friendly_name": "Nick Office Zone setpoint status",
|
|
}
|
|
# Only test for a subset of attributes in case
|
|
# HA changes the implementation and a new one appears
|
|
assert all(
|
|
state.attributes[key] == value for key, value in expected_attributes.items()
|
|
)
|
|
|
|
state = hass.states.get("sensor.nick_office_nick_office_zone_status")
|
|
assert state is not None
|
|
assert state.state == "Relieving Air"
|
|
|
|
expected_attributes = {
|
|
"attribution": "Data provided by Trane Technologies",
|
|
"friendly_name": "Nick Office Zone status",
|
|
}
|
|
# Only test for a subset of attributes in case
|
|
# HA changes the implementation and a new one appears
|
|
assert all(
|
|
state.attributes[key] == value for key, value in expected_attributes.items()
|
|
)
|
|
|
|
state = hass.states.get("sensor.master_suite_air_cleaner_mode")
|
|
assert state is not None
|
|
assert state.state == "auto"
|
|
|
|
expected_attributes = {
|
|
"attribution": "Data provided by Trane Technologies",
|
|
"friendly_name": "Master Suite Air cleaner mode",
|
|
}
|
|
# Only test for a subset of attributes in case
|
|
# HA changes the implementation and a new one appears
|
|
assert all(
|
|
state.attributes[key] == value for key, value in expected_attributes.items()
|
|
)
|
|
|
|
state = hass.states.get("sensor.master_suite_current_compressor_speed")
|
|
assert state is not None
|
|
assert round(float(state.state)) == 69
|
|
|
|
expected_attributes = {
|
|
"attribution": "Data provided by Trane Technologies",
|
|
"friendly_name": "Master Suite Current compressor speed",
|
|
"unit_of_measurement": PERCENTAGE,
|
|
}
|
|
# Only test for a subset of attributes in case
|
|
# HA changes the implementation and a new one appears
|
|
assert all(
|
|
state.attributes[key] == value for key, value in expected_attributes.items()
|
|
)
|
|
|
|
state = hass.states.get("sensor.master_suite_outdoor_temperature")
|
|
assert state is not None
|
|
assert round(float(state.state), 1) == 30.6
|
|
|
|
expected_attributes = {
|
|
"attribution": "Data provided by Trane Technologies",
|
|
"device_class": "temperature",
|
|
"friendly_name": "Master Suite Outdoor temperature",
|
|
"unit_of_measurement": UnitOfTemperature.CELSIUS,
|
|
}
|
|
# Only test for a subset of attributes in case
|
|
# HA changes the implementation and a new one appears
|
|
assert all(
|
|
state.attributes[key] == value for key, value in expected_attributes.items()
|
|
)
|
|
|
|
state = hass.states.get("sensor.master_suite_humidity")
|
|
assert state is not None
|
|
assert state.state == "52.0"
|
|
|
|
expected_attributes = {
|
|
"attribution": "Data provided by Trane Technologies",
|
|
"device_class": "humidity",
|
|
"friendly_name": "Master Suite Humidity",
|
|
"unit_of_measurement": PERCENTAGE,
|
|
}
|
|
# Only test for a subset of attributes in case
|
|
# HA changes the implementation and a new one appears
|
|
assert all(
|
|
state.attributes[key] == value for key, value in expected_attributes.items()
|
|
)
|
|
|
|
state = hass.states.get("sensor.master_suite_requested_compressor_speed")
|
|
assert state is not None
|
|
assert state.state == "69.0"
|
|
|
|
expected_attributes = {
|
|
"attribution": "Data provided by Trane Technologies",
|
|
"friendly_name": "Master Suite Requested compressor speed",
|
|
"unit_of_measurement": PERCENTAGE,
|
|
}
|
|
# Only test for a subset of attributes in case
|
|
# HA changes the implementation and a new one appears
|
|
assert all(
|
|
state.attributes[key] == value for key, value in expected_attributes.items()
|
|
)
|
|
|
|
state = hass.states.get("sensor.master_suite_system_status")
|
|
assert state is not None
|
|
assert state.state == "Cooling"
|
|
|
|
expected_attributes = {
|
|
"attribution": "Data provided by Trane Technologies",
|
|
"friendly_name": "Master Suite System status",
|
|
}
|
|
# Only test for a subset of attributes in case
|
|
# HA changes the implementation and a new one appears
|
|
assert all(
|
|
state.attributes[key] == value for key, value in expected_attributes.items()
|
|
)
|
|
|
|
|
|
async def test_room_iq_sensor_disabled_by_default(
|
|
hass: HomeAssistant, patch_nexia_home: NonCallableMock[NexiaHome]
|
|
) -> None:
|
|
"""Test NexiaRoomIQSensor is disabled by default."""
|
|
|
|
await setup_integration(hass, patch_nexia_home)
|
|
|
|
assert patch_nexia_home.any_room_iq_monitors() is False
|
|
assert patch_nexia_home.update.await_count == 1
|
|
state = hass.states.get("sensor.zone3_zone3_roomiq_temperature")
|
|
assert state is None
|
|
|
|
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_room_iq_sensors(
|
|
hass: HomeAssistant,
|
|
patch_nexia_home: NonCallableMock[NexiaHome],
|
|
entity_registry: EntityRegistry,
|
|
device_registry: DeviceRegistry,
|
|
) -> None:
|
|
"""Test NexiaRoomIQSensor."""
|
|
|
|
await setup_integration(hass, patch_nexia_home)
|
|
|
|
assert patch_nexia_home.any_room_iq_monitors() is True
|
|
assert patch_nexia_home.update.await_count == 2
|
|
state = hass.states.get("sensor.zone3_zone3_roomiq_temperature")
|
|
assert state is not None
|
|
|
|
entry = entity_registry.async_get(state.entity_id)
|
|
device = device_registry.async_get(entry.device_id)
|
|
assert device is not None
|
|
assert device.model == "XL1050"
|
|
assert device.sw_version == "5.9.1"
|
|
|
|
assert state.state == "25.0"
|
|
assert state.attributes["device_class"] == SensorDeviceClass.TEMPERATURE
|
|
assert state.attributes["friendly_name"] == "Zone3 RoomIQ temperature"
|
|
assert state.attributes["unit_of_measurement"] == UnitOfTemperature.CELSIUS
|
|
|
|
state = hass.states.get("sensor.zone3_zone3_roomiq_humidity")
|
|
assert state is not None
|
|
assert state.state == "45"
|
|
assert state.attributes["device_class"] == SensorDeviceClass.HUMIDITY
|
|
assert state.attributes["friendly_name"] == "Zone3 RoomIQ humidity"
|
|
assert state.attributes["unit_of_measurement"] == PERCENTAGE
|
|
|
|
state = hass.states.get("sensor.zone3_zone3_roomiq_battery")
|
|
assert state is None
|
|
|
|
state = hass.states.get("sensor.upstairs_upstairs_roomiq_temperature")
|
|
assert state is not None
|
|
|
|
entry = entity_registry.async_get(state.entity_id)
|
|
device = device_registry.async_get(entry.device_id)
|
|
assert device is not None
|
|
assert device.model is None
|
|
assert device.sw_version is None
|
|
|
|
assert state.state == "22.5"
|
|
assert state.attributes["device_class"] == SensorDeviceClass.TEMPERATURE
|
|
assert state.attributes["friendly_name"] == "Upstairs RoomIQ temperature"
|
|
assert state.attributes["unit_of_measurement"] == UnitOfTemperature.CELSIUS
|
|
|
|
state = hass.states.get("sensor.upstairs_upstairs_roomiq_humidity")
|
|
assert state is not None
|
|
assert state.state == "45"
|
|
assert state.attributes["device_class"] == SensorDeviceClass.HUMIDITY
|
|
assert state.attributes["friendly_name"] == "Upstairs RoomIQ humidity"
|
|
assert state.attributes["unit_of_measurement"] == PERCENTAGE
|
|
|
|
state = hass.states.get("sensor.upstairs_upstairs_roomiq_battery")
|
|
assert state is not None
|
|
assert state.state == "93"
|
|
assert state.attributes["device_class"] == SensorDeviceClass.BATTERY
|
|
assert state.attributes["friendly_name"] == "Upstairs RoomIQ battery"
|
|
assert state.attributes["unit_of_measurement"] == PERCENTAGE
|
|
|
|
state = hass.states.get("sensor.downstairs_downstairs_roomiq_temperature")
|
|
assert state is not None
|
|
assert state.state == "unavailable"
|
|
|
|
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_any_room_iq_monitors(
|
|
hass: HomeAssistant, patch_nexia_home: NexiaHome
|
|
) -> None:
|
|
"""Test any_room_iq_monitors after unload."""
|
|
|
|
config_entry = await setup_integration(hass, patch_nexia_home)
|
|
|
|
assert patch_nexia_home.any_room_iq_monitors() is True
|
|
|
|
await hass.config_entries.async_unload(config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
assert config_entry.state is ConfigEntryState.NOT_LOADED
|
|
assert patch_nexia_home.any_room_iq_monitors() is False
|
|
|
|
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_room_iq_sensor_no_longer_present(
|
|
hass: HomeAssistant, patch_nexia_home: NexiaHome, freezer: FrozenDateTimeFactory
|
|
) -> None:
|
|
"""Test RoomIQ sensor no longer present."""
|
|
zone = patch_nexia_home.get_thermostat_by_id(2000004).get_zone_by_id(500)
|
|
get_item = zone.get_sensor_by_id.side_effect
|
|
zone.get_sensor_by_id.side_effect = KeyError
|
|
|
|
await setup_integration(hass, patch_nexia_home)
|
|
|
|
state = hass.states.get("sensor.upstairs_upstairs_roomiq_humidity")
|
|
assert state is not None
|
|
assert state.state == "unavailable"
|
|
|
|
def get_sensor_raise_from_native_value(sensor_id: int) -> NexiaSensor:
|
|
for caller_frame in inspect.stack():
|
|
if caller_frame.function == "native_value":
|
|
raise KeyError
|
|
|
|
return get_item(sensor_id)
|
|
|
|
# The state machine won't call NexiaRoomIQSensor.native_value() when unavailable, so only
|
|
# raise when called from native_value() & return something new to coordinator so it updates
|
|
zone.get_sensor_by_id.side_effect = get_sensor_raise_from_native_value
|
|
patch_nexia_home.update.return_value = {"key": "different value"}
|
|
|
|
freezer.tick(timedelta(seconds=COORDINATOR_UPDATE_RATE))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("sensor.upstairs_upstairs_roomiq_humidity")
|
|
assert state is not None
|
|
assert state.state == "unknown"
|
|
|
|
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_1_room_iq_sensor(
|
|
hass: HomeAssistant, patch_nexia_home: NexiaHome
|
|
) -> None:
|
|
"""Test one-RoomIQ sensor case."""
|
|
zone = patch_nexia_home.get_thermostat_by_id(2000003).get_zone_by_id(400)
|
|
assert len(zone.get_sensors()) == 1
|
|
|
|
await setup_integration(hass, patch_nexia_home)
|
|
|
|
state = hass.states.get("sensor.kitchen_kitchen_roomiq_temperature")
|
|
assert state is None
|