mirror of
https://github.com/home-assistant/core.git
synced 2025-08-03 18:48:22 +00:00
Merge branch 'dev' into block_pyserial_asyncio
This commit is contained in:
commit
dba07ac90d
@ -51,8 +51,9 @@ from homeassistant.helpers.event import async_call_later
|
|||||||
from homeassistant.helpers.issue_registry import async_delete_issue
|
from homeassistant.helpers.issue_registry import async_delete_issue
|
||||||
from homeassistant.loader import async_get_bluetooth
|
from homeassistant.loader import async_get_bluetooth
|
||||||
|
|
||||||
from . import models, passive_update_processor
|
from . import passive_update_processor
|
||||||
from .api import (
|
from .api import (
|
||||||
|
_get_manager,
|
||||||
async_address_present,
|
async_address_present,
|
||||||
async_ble_device_from_address,
|
async_ble_device_from_address,
|
||||||
async_discovered_service_info,
|
async_discovered_service_info,
|
||||||
@ -76,7 +77,6 @@ from .const import (
|
|||||||
CONF_ADAPTER,
|
CONF_ADAPTER,
|
||||||
CONF_DETAILS,
|
CONF_DETAILS,
|
||||||
CONF_PASSIVE,
|
CONF_PASSIVE,
|
||||||
DATA_MANAGER,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
||||||
LINUX_FIRMWARE_LOAD_FALLBACK_SECONDS,
|
LINUX_FIRMWARE_LOAD_FALLBACK_SECONDS,
|
||||||
@ -230,10 +230,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
hass, integration_matcher, bluetooth_adapters, bluetooth_storage, slot_manager
|
hass, integration_matcher, bluetooth_adapters, bluetooth_storage, slot_manager
|
||||||
)
|
)
|
||||||
set_manager(manager)
|
set_manager(manager)
|
||||||
|
|
||||||
await storage_setup_task
|
await storage_setup_task
|
||||||
await manager.async_setup()
|
await manager.async_setup()
|
||||||
hass.data[DATA_MANAGER] = models.MANAGER = manager
|
|
||||||
|
|
||||||
hass.async_create_background_task(
|
hass.async_create_background_task(
|
||||||
_async_start_adapter_discovery(hass, manager, bluetooth_adapters),
|
_async_start_adapter_discovery(hass, manager, bluetooth_adapters),
|
||||||
@ -314,7 +312,7 @@ async def async_update_device(
|
|||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Set up a config entry for a bluetooth scanner."""
|
"""Set up a config entry for a bluetooth scanner."""
|
||||||
manager: HomeAssistantBluetoothManager = hass.data[DATA_MANAGER]
|
manager = _get_manager(hass)
|
||||||
address = entry.unique_id
|
address = entry.unique_id
|
||||||
assert address is not None
|
assert address is not None
|
||||||
adapter = await manager.async_get_adapter_from_address_or_recover(address)
|
adapter = await manager.async_get_adapter_from_address_or_recover(address)
|
||||||
|
@ -15,10 +15,12 @@ from habluetooth import (
|
|||||||
BluetoothScannerDevice,
|
BluetoothScannerDevice,
|
||||||
BluetoothScanningMode,
|
BluetoothScanningMode,
|
||||||
HaBleakScannerWrapper,
|
HaBleakScannerWrapper,
|
||||||
|
get_manager,
|
||||||
)
|
)
|
||||||
from home_assistant_bluetooth import BluetoothServiceInfoBleak
|
from home_assistant_bluetooth import BluetoothServiceInfoBleak
|
||||||
|
|
||||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback as hass_callback
|
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback as hass_callback
|
||||||
|
from homeassistant.helpers.singleton import singleton
|
||||||
|
|
||||||
from .const import DATA_MANAGER
|
from .const import DATA_MANAGER
|
||||||
from .manager import HomeAssistantBluetoothManager
|
from .manager import HomeAssistantBluetoothManager
|
||||||
@ -29,9 +31,10 @@ if TYPE_CHECKING:
|
|||||||
from bleak.backends.device import BLEDevice
|
from bleak.backends.device import BLEDevice
|
||||||
|
|
||||||
|
|
||||||
|
@singleton(DATA_MANAGER)
|
||||||
def _get_manager(hass: HomeAssistant) -> HomeAssistantBluetoothManager:
|
def _get_manager(hass: HomeAssistant) -> HomeAssistantBluetoothManager:
|
||||||
"""Get the bluetooth manager."""
|
"""Get the bluetooth manager."""
|
||||||
return cast(HomeAssistantBluetoothManager, hass.data[DATA_MANAGER])
|
return cast(HomeAssistantBluetoothManager, get_manager())
|
||||||
|
|
||||||
|
|
||||||
@hass_callback
|
@hass_callback
|
||||||
@ -68,8 +71,6 @@ def async_discovered_service_info(
|
|||||||
hass: HomeAssistant, connectable: bool = True
|
hass: HomeAssistant, connectable: bool = True
|
||||||
) -> Iterable[BluetoothServiceInfoBleak]:
|
) -> Iterable[BluetoothServiceInfoBleak]:
|
||||||
"""Return the discovered devices list."""
|
"""Return the discovered devices list."""
|
||||||
if DATA_MANAGER not in hass.data:
|
|
||||||
return []
|
|
||||||
return _get_manager(hass).async_discovered_service_info(connectable)
|
return _get_manager(hass).async_discovered_service_info(connectable)
|
||||||
|
|
||||||
|
|
||||||
@ -78,8 +79,6 @@ def async_last_service_info(
|
|||||||
hass: HomeAssistant, address: str, connectable: bool = True
|
hass: HomeAssistant, address: str, connectable: bool = True
|
||||||
) -> BluetoothServiceInfoBleak | None:
|
) -> BluetoothServiceInfoBleak | None:
|
||||||
"""Return the last service info for an address."""
|
"""Return the last service info for an address."""
|
||||||
if DATA_MANAGER not in hass.data:
|
|
||||||
return None
|
|
||||||
return _get_manager(hass).async_last_service_info(address, connectable)
|
return _get_manager(hass).async_last_service_info(address, connectable)
|
||||||
|
|
||||||
|
|
||||||
@ -88,8 +87,6 @@ def async_ble_device_from_address(
|
|||||||
hass: HomeAssistant, address: str, connectable: bool = True
|
hass: HomeAssistant, address: str, connectable: bool = True
|
||||||
) -> BLEDevice | None:
|
) -> BLEDevice | None:
|
||||||
"""Return BLEDevice for an address if its present."""
|
"""Return BLEDevice for an address if its present."""
|
||||||
if DATA_MANAGER not in hass.data:
|
|
||||||
return None
|
|
||||||
return _get_manager(hass).async_ble_device_from_address(address, connectable)
|
return _get_manager(hass).async_ble_device_from_address(address, connectable)
|
||||||
|
|
||||||
|
|
||||||
@ -106,8 +103,6 @@ def async_address_present(
|
|||||||
hass: HomeAssistant, address: str, connectable: bool = True
|
hass: HomeAssistant, address: str, connectable: bool = True
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Check if an address is present in the bluetooth device list."""
|
"""Check if an address is present in the bluetooth device list."""
|
||||||
if DATA_MANAGER not in hass.data:
|
|
||||||
return False
|
|
||||||
return _get_manager(hass).async_address_present(address, connectable)
|
return _get_manager(hass).async_address_present(address, connectable)
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ from bluetooth_adapters import (
|
|||||||
adapter_model,
|
adapter_model,
|
||||||
get_adapters,
|
get_adapters,
|
||||||
)
|
)
|
||||||
|
from habluetooth import get_manager
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import onboarding
|
from homeassistant.components import onboarding
|
||||||
@ -25,7 +26,6 @@ from homeassistant.helpers.schema_config_entry_flow import (
|
|||||||
)
|
)
|
||||||
from homeassistant.helpers.typing import DiscoveryInfoType
|
from homeassistant.helpers.typing import DiscoveryInfoType
|
||||||
|
|
||||||
from . import models
|
|
||||||
from .const import CONF_ADAPTER, CONF_DETAILS, CONF_PASSIVE, DOMAIN
|
from .const import CONF_ADAPTER, CONF_DETAILS, CONF_PASSIVE, DOMAIN
|
||||||
from .util import adapter_title
|
from .util import adapter_title
|
||||||
|
|
||||||
@ -185,4 +185,4 @@ class BluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
@callback
|
@callback
|
||||||
def async_supports_options_flow(cls, config_entry: ConfigEntry) -> bool:
|
def async_supports_options_flow(cls, config_entry: ConfigEntry) -> bool:
|
||||||
"""Return options flow support for this handler."""
|
"""Return options flow support for this handler."""
|
||||||
return bool(models.MANAGER and models.MANAGER.supports_passive_scan)
|
return bool((manager := get_manager()) and manager.supports_passive_scan)
|
||||||
|
@ -20,6 +20,6 @@
|
|||||||
"bluetooth-auto-recovery==1.4.2",
|
"bluetooth-auto-recovery==1.4.2",
|
||||||
"bluetooth-data-tools==1.19.0",
|
"bluetooth-data-tools==1.19.0",
|
||||||
"dbus-fast==2.21.1",
|
"dbus-fast==2.21.1",
|
||||||
"habluetooth==2.8.0"
|
"habluetooth==2.8.1"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -4,17 +4,9 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
from home_assistant_bluetooth import BluetoothServiceInfoBleak
|
from home_assistant_bluetooth import BluetoothServiceInfoBleak
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from .manager import HomeAssistantBluetoothManager
|
|
||||||
|
|
||||||
|
|
||||||
MANAGER: HomeAssistantBluetoothManager | None = None
|
|
||||||
|
|
||||||
|
|
||||||
BluetoothChange = Enum("BluetoothChange", "ADVERTISEMENT")
|
BluetoothChange = Enum("BluetoothChange", "ADVERTISEMENT")
|
||||||
BluetoothCallback = Callable[[BluetoothServiceInfoBleak, BluetoothChange], None]
|
BluetoothCallback = Callable[[BluetoothServiceInfoBleak, BluetoothChange], None]
|
||||||
ProcessAdvertisementCallback = Callable[[BluetoothServiceInfoBleak], bool]
|
ProcessAdvertisementCallback = Callable[[BluetoothServiceInfoBleak], bool]
|
||||||
|
@ -49,6 +49,7 @@ PLATFORMS = [
|
|||||||
Platform.NOTIFY,
|
Platform.NOTIFY,
|
||||||
Platform.NUMBER,
|
Platform.NUMBER,
|
||||||
Platform.SENSOR,
|
Platform.SENSOR,
|
||||||
|
Platform.SWITCH,
|
||||||
Platform.WEATHER,
|
Platform.WEATHER,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["pyecobee"],
|
"loggers": ["pyecobee"],
|
||||||
"requirements": ["python-ecobee-api==0.2.17"],
|
"requirements": ["python-ecobee-api==0.2.18"],
|
||||||
"zeroconf": [
|
"zeroconf": [
|
||||||
{
|
{
|
||||||
"type": "_ecobee._tcp.local."
|
"type": "_ecobee._tcp.local."
|
||||||
|
90
homeassistant/components/ecobee/switch.py
Normal file
90
homeassistant/components/ecobee/switch.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
"""Support for using switch with ecobee thermostats."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from homeassistant.components.switch import SwitchEntity
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
|
from . import EcobeeData
|
||||||
|
from .const import DOMAIN
|
||||||
|
from .entity import EcobeeBaseEntity
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up the ecobee thermostat switch entity."""
|
||||||
|
data: EcobeeData = hass.data[DOMAIN]
|
||||||
|
|
||||||
|
async_add_entities(
|
||||||
|
(
|
||||||
|
EcobeeVentilator20MinSwitch(data, index)
|
||||||
|
for index, thermostat in enumerate(data.ecobee.thermostats)
|
||||||
|
if thermostat["settings"]["ventilatorType"] != "none"
|
||||||
|
),
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class EcobeeVentilator20MinSwitch(EcobeeBaseEntity, SwitchEntity):
|
||||||
|
"""A Switch class, representing 20 min timer for an ecobee thermostat with ventilator attached."""
|
||||||
|
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
_attr_name = "Ventilator 20m Timer"
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
data: EcobeeData,
|
||||||
|
thermostat_index: int,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize ecobee ventilator platform."""
|
||||||
|
super().__init__(data, thermostat_index)
|
||||||
|
self._attr_unique_id = f"{self.base_unique_id}_ventilator_20m_timer"
|
||||||
|
self._attr_is_on = False
|
||||||
|
self.update_without_throttle = False
|
||||||
|
self._operating_timezone = dt_util.get_time_zone(
|
||||||
|
self.thermostat["location"]["timeZone"]
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_update(self) -> None:
|
||||||
|
"""Get the latest state from the thermostat."""
|
||||||
|
|
||||||
|
if self.update_without_throttle:
|
||||||
|
await self.data.update(no_throttle=True)
|
||||||
|
self.update_without_throttle = False
|
||||||
|
else:
|
||||||
|
await self.data.update()
|
||||||
|
|
||||||
|
ventilator_off_date_time = self.thermostat["settings"]["ventilatorOffDateTime"]
|
||||||
|
|
||||||
|
self._attr_is_on = ventilator_off_date_time and dt_util.parse_datetime(
|
||||||
|
ventilator_off_date_time, raise_on_error=True
|
||||||
|
).replace(tzinfo=self._operating_timezone) >= dt_util.now(
|
||||||
|
self._operating_timezone
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
|
"""Set ventilator 20 min timer on."""
|
||||||
|
await self.hass.async_add_executor_job(
|
||||||
|
self.data.ecobee.set_ventilator_timer, self.thermostat_index, True
|
||||||
|
)
|
||||||
|
self.update_without_throttle = True
|
||||||
|
|
||||||
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
|
"""Set ventilator 20 min timer off."""
|
||||||
|
await self.hass.async_add_executor_job(
|
||||||
|
self.data.ecobee.set_ventilator_timer, self.thermostat_index, False
|
||||||
|
)
|
||||||
|
self.update_without_throttle = True
|
@ -6,5 +6,5 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/environment_canada",
|
"documentation": "https://www.home-assistant.io/integrations/environment_canada",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["env_canada"],
|
"loggers": ["env_canada"],
|
||||||
"requirements": ["env-canada==0.6.0"]
|
"requirements": ["env-canada==0.6.2"]
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,6 @@ ABBREVIATIONS = {
|
|||||||
"json_attr": "json_attributes",
|
"json_attr": "json_attributes",
|
||||||
"json_attr_t": "json_attributes_topic",
|
"json_attr_t": "json_attributes_topic",
|
||||||
"json_attr_tpl": "json_attributes_template",
|
"json_attr_tpl": "json_attributes_template",
|
||||||
"lrst_t": "last_reset_topic",
|
|
||||||
"lrst_val_tpl": "last_reset_value_template",
|
"lrst_val_tpl": "last_reset_value_template",
|
||||||
"max": "max",
|
"max": "max",
|
||||||
"min": "min",
|
"min": "min",
|
||||||
|
@ -58,7 +58,6 @@ from .models import (
|
|||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
CONF_EXPIRE_AFTER = "expire_after"
|
CONF_EXPIRE_AFTER = "expire_after"
|
||||||
CONF_LAST_RESET_TOPIC = "last_reset_topic"
|
|
||||||
CONF_LAST_RESET_VALUE_TEMPLATE = "last_reset_value_template"
|
CONF_LAST_RESET_VALUE_TEMPLATE = "last_reset_value_template"
|
||||||
CONF_SUGGESTED_DISPLAY_PRECISION = "suggested_display_precision"
|
CONF_SUGGESTED_DISPLAY_PRECISION = "suggested_display_precision"
|
||||||
|
|
||||||
@ -101,17 +100,11 @@ def validate_sensor_state_class_config(config: ConfigType) -> ConfigType:
|
|||||||
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA_MODERN = vol.All(
|
PLATFORM_SCHEMA_MODERN = vol.All(
|
||||||
# Deprecated in HA Core 2021.11.0 https://github.com/home-assistant/core/pull/54840
|
|
||||||
# Removed in HA Core 2023.6.0
|
|
||||||
cv.removed(CONF_LAST_RESET_TOPIC),
|
|
||||||
_PLATFORM_SCHEMA_BASE,
|
_PLATFORM_SCHEMA_BASE,
|
||||||
validate_sensor_state_class_config,
|
validate_sensor_state_class_config,
|
||||||
)
|
)
|
||||||
|
|
||||||
DISCOVERY_SCHEMA = vol.All(
|
DISCOVERY_SCHEMA = vol.All(
|
||||||
# Deprecated in HA Core 2021.11.0 https://github.com/home-assistant/core/pull/54840
|
|
||||||
# Removed in HA Core 2023.6.0
|
|
||||||
cv.removed(CONF_LAST_RESET_TOPIC),
|
|
||||||
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
||||||
validate_sensor_state_class_config,
|
validate_sensor_state_class_config,
|
||||||
)
|
)
|
||||||
|
@ -5,7 +5,6 @@ from __future__ import annotations
|
|||||||
import openai
|
import openai
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import conversation
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_API_KEY, Platform
|
from homeassistant.const import CONF_API_KEY, Platform
|
||||||
from homeassistant.core import (
|
from homeassistant.core import (
|
||||||
@ -115,5 +114,4 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
hass.data[DOMAIN].pop(entry.entry_id)
|
hass.data[DOMAIN].pop(entry.entry_id)
|
||||||
conversation.async_unset_agent(hass, entry)
|
|
||||||
return True
|
return True
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
DOMAIN = "openai_conversation"
|
DOMAIN = "openai_conversation"
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__package__)
|
||||||
CONF_PROMPT = "prompt"
|
CONF_PROMPT = "prompt"
|
||||||
DEFAULT_PROMPT = """This smart home is controlled by Home Assistant.
|
DEFAULT_PROMPT = """This smart home is controlled by Home Assistant.
|
||||||
|
|
||||||
|
@ -44,6 +44,8 @@ class OpenAIConversationEntity(
|
|||||||
):
|
):
|
||||||
"""OpenAI conversation agent."""
|
"""OpenAI conversation agent."""
|
||||||
|
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
|
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||||
"""Initialize the agent."""
|
"""Initialize the agent."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
"universal_silabs_flasher"
|
"universal_silabs_flasher"
|
||||||
],
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"bellows==0.38.3",
|
"bellows==0.38.4",
|
||||||
"pyserial==3.5",
|
"pyserial==3.5",
|
||||||
"zha-quirks==0.0.115",
|
"zha-quirks==0.0.115",
|
||||||
"zigpy-deconz==0.23.1",
|
"zigpy-deconz==0.23.1",
|
||||||
|
@ -28,7 +28,7 @@ dbus-fast==2.21.1
|
|||||||
fnv-hash-fast==0.5.0
|
fnv-hash-fast==0.5.0
|
||||||
ha-av==10.1.1
|
ha-av==10.1.1
|
||||||
ha-ffmpeg==3.2.0
|
ha-ffmpeg==3.2.0
|
||||||
habluetooth==2.8.0
|
habluetooth==2.8.1
|
||||||
hass-nabucasa==0.78.0
|
hass-nabucasa==0.78.0
|
||||||
hassil==1.6.1
|
hassil==1.6.1
|
||||||
home-assistant-bluetooth==1.12.0
|
home-assistant-bluetooth==1.12.0
|
||||||
|
@ -541,7 +541,7 @@ beautifulsoup4==4.12.3
|
|||||||
# beewi-smartclim==0.0.10
|
# beewi-smartclim==0.0.10
|
||||||
|
|
||||||
# homeassistant.components.zha
|
# homeassistant.components.zha
|
||||||
bellows==0.38.3
|
bellows==0.38.4
|
||||||
|
|
||||||
# homeassistant.components.bmw_connected_drive
|
# homeassistant.components.bmw_connected_drive
|
||||||
bimmer-connected[china]==0.15.2
|
bimmer-connected[china]==0.15.2
|
||||||
@ -804,7 +804,7 @@ enocean==0.50
|
|||||||
enturclient==0.2.4
|
enturclient==0.2.4
|
||||||
|
|
||||||
# homeassistant.components.environment_canada
|
# homeassistant.components.environment_canada
|
||||||
env-canada==0.6.0
|
env-canada==0.6.2
|
||||||
|
|
||||||
# homeassistant.components.season
|
# homeassistant.components.season
|
||||||
ephem==4.1.5
|
ephem==4.1.5
|
||||||
@ -1035,7 +1035,7 @@ ha-philipsjs==3.1.1
|
|||||||
habitipy==0.2.0
|
habitipy==0.2.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
habluetooth==2.8.0
|
habluetooth==2.8.1
|
||||||
|
|
||||||
# homeassistant.components.cloud
|
# homeassistant.components.cloud
|
||||||
hass-nabucasa==0.78.0
|
hass-nabucasa==0.78.0
|
||||||
@ -2212,7 +2212,7 @@ python-clementine-remote==1.0.1
|
|||||||
python-digitalocean==1.13.2
|
python-digitalocean==1.13.2
|
||||||
|
|
||||||
# homeassistant.components.ecobee
|
# homeassistant.components.ecobee
|
||||||
python-ecobee-api==0.2.17
|
python-ecobee-api==0.2.18
|
||||||
|
|
||||||
# homeassistant.components.etherscan
|
# homeassistant.components.etherscan
|
||||||
python-etherscan-api==0.0.3
|
python-etherscan-api==0.0.3
|
||||||
|
@ -466,7 +466,7 @@ base36==0.1.1
|
|||||||
beautifulsoup4==4.12.3
|
beautifulsoup4==4.12.3
|
||||||
|
|
||||||
# homeassistant.components.zha
|
# homeassistant.components.zha
|
||||||
bellows==0.38.3
|
bellows==0.38.4
|
||||||
|
|
||||||
# homeassistant.components.bmw_connected_drive
|
# homeassistant.components.bmw_connected_drive
|
||||||
bimmer-connected[china]==0.15.2
|
bimmer-connected[china]==0.15.2
|
||||||
@ -658,7 +658,7 @@ energyzero==2.1.0
|
|||||||
enocean==0.50
|
enocean==0.50
|
||||||
|
|
||||||
# homeassistant.components.environment_canada
|
# homeassistant.components.environment_canada
|
||||||
env-canada==0.6.0
|
env-canada==0.6.2
|
||||||
|
|
||||||
# homeassistant.components.season
|
# homeassistant.components.season
|
||||||
ephem==4.1.5
|
ephem==4.1.5
|
||||||
@ -849,7 +849,7 @@ ha-philipsjs==3.1.1
|
|||||||
habitipy==0.2.0
|
habitipy==0.2.0
|
||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
habluetooth==2.8.0
|
habluetooth==2.8.1
|
||||||
|
|
||||||
# homeassistant.components.cloud
|
# homeassistant.components.cloud
|
||||||
hass-nabucasa==0.78.0
|
hass-nabucasa==0.78.0
|
||||||
@ -1727,7 +1727,7 @@ python-awair==0.2.4
|
|||||||
python-bsblan==0.5.18
|
python-bsblan==0.5.18
|
||||||
|
|
||||||
# homeassistant.components.ecobee
|
# homeassistant.components.ecobee
|
||||||
python-ecobee-api==0.2.17
|
python-ecobee-api==0.2.18
|
||||||
|
|
||||||
# homeassistant.components.fully_kiosk
|
# homeassistant.components.fully_kiosk
|
||||||
python-fullykiosk==0.0.12
|
python-fullykiosk==0.0.12
|
||||||
|
@ -8,7 +8,7 @@ from unittest.mock import ANY, AsyncMock, MagicMock, Mock, patch
|
|||||||
from bleak import BleakError
|
from bleak import BleakError
|
||||||
from bleak.backends.scanner import AdvertisementData, BLEDevice
|
from bleak.backends.scanner import AdvertisementData, BLEDevice
|
||||||
from bluetooth_adapters import DEFAULT_ADDRESS
|
from bluetooth_adapters import DEFAULT_ADDRESS
|
||||||
from habluetooth import scanner
|
from habluetooth import scanner, set_manager
|
||||||
from habluetooth.wrappers import HaBleakScannerWrapper
|
from habluetooth.wrappers import HaBleakScannerWrapper
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -1154,6 +1154,7 @@ async def test_async_discovered_device_api(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test the async_discovered_device API."""
|
"""Test the async_discovered_device API."""
|
||||||
mock_bt = []
|
mock_bt = []
|
||||||
|
set_manager(None)
|
||||||
with (
|
with (
|
||||||
patch(
|
patch(
|
||||||
"homeassistant.components.bluetooth.async_get_bluetooth",
|
"homeassistant.components.bluetooth.async_get_bluetooth",
|
||||||
@ -1169,8 +1170,10 @@ async def test_async_discovered_device_api(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
assert not bluetooth.async_discovered_service_info(hass)
|
with pytest.raises(RuntimeError, match="BluetoothManager has not been set"):
|
||||||
assert not bluetooth.async_address_present(hass, "44:44:22:22:11:22")
|
assert not bluetooth.async_discovered_service_info(hass)
|
||||||
|
with pytest.raises(RuntimeError, match="BluetoothManager has not been set"):
|
||||||
|
assert not bluetooth.async_address_present(hass, "44:44:22:22:11:22")
|
||||||
await async_setup_with_default_adapter(hass)
|
await async_setup_with_default_adapter(hass)
|
||||||
|
|
||||||
with patch.object(hass.config_entries.flow, "async_init"):
|
with patch.object(hass.config_entries.flow, "async_init"):
|
||||||
@ -2744,6 +2747,7 @@ async def test_async_ble_device_from_address(
|
|||||||
hass: HomeAssistant, mock_bleak_scanner_start: MagicMock, macos_adapter: None
|
hass: HomeAssistant, mock_bleak_scanner_start: MagicMock, macos_adapter: None
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the async_ble_device_from_address api."""
|
"""Test the async_ble_device_from_address api."""
|
||||||
|
set_manager(None)
|
||||||
mock_bt = []
|
mock_bt = []
|
||||||
with (
|
with (
|
||||||
patch(
|
patch(
|
||||||
@ -2760,11 +2764,15 @@ async def test_async_ble_device_from_address(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
assert not bluetooth.async_discovered_service_info(hass)
|
with pytest.raises(RuntimeError, match="BluetoothManager has not been set"):
|
||||||
assert not bluetooth.async_address_present(hass, "44:44:22:22:11:22")
|
assert not bluetooth.async_discovered_service_info(hass)
|
||||||
assert (
|
with pytest.raises(RuntimeError, match="BluetoothManager has not been set"):
|
||||||
bluetooth.async_ble_device_from_address(hass, "44:44:33:11:23:45") is None
|
assert not bluetooth.async_address_present(hass, "44:44:22:22:11:22")
|
||||||
)
|
with pytest.raises(RuntimeError, match="BluetoothManager has not been set"):
|
||||||
|
assert (
|
||||||
|
bluetooth.async_ble_device_from_address(hass, "44:44:33:11:23:45")
|
||||||
|
is None
|
||||||
|
)
|
||||||
|
|
||||||
await async_setup_with_default_adapter(hass)
|
await async_setup_with_default_adapter(hass)
|
||||||
|
|
||||||
|
@ -65,6 +65,9 @@ GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP = {
|
|||||||
"identifier": 8675309,
|
"identifier": 8675309,
|
||||||
"name": "ecobee",
|
"name": "ecobee",
|
||||||
"modelNumber": "athenaSmart",
|
"modelNumber": "athenaSmart",
|
||||||
|
"utcTime": "2022-01-01 10:00:00",
|
||||||
|
"thermostatTime": "2022-01-01 6:00:00",
|
||||||
|
"location": {"timeZone": "America/Toronto"},
|
||||||
"program": {
|
"program": {
|
||||||
"climates": [
|
"climates": [
|
||||||
{"name": "Climate1", "climateRef": "c1"},
|
{"name": "Climate1", "climateRef": "c1"},
|
||||||
@ -92,7 +95,8 @@ GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP = {
|
|||||||
"humidifierMode": "manual",
|
"humidifierMode": "manual",
|
||||||
"humidity": "30",
|
"humidity": "30",
|
||||||
"hasHeatPump": True,
|
"hasHeatPump": True,
|
||||||
"ventilatorType": "none",
|
"ventilatorType": "hrv",
|
||||||
|
"ventilatorOffDateTime": "2022-01-01 6:00:00",
|
||||||
},
|
},
|
||||||
"equipmentStatus": "fan",
|
"equipmentStatus": "fan",
|
||||||
"events": [
|
"events": [
|
||||||
|
@ -4,6 +4,11 @@
|
|||||||
"identifier": 8675309,
|
"identifier": 8675309,
|
||||||
"name": "ecobee",
|
"name": "ecobee",
|
||||||
"modelNumber": "athenaSmart",
|
"modelNumber": "athenaSmart",
|
||||||
|
"utcTime": "2022-01-01 10:00:00",
|
||||||
|
"thermostatTime": "2022-01-01 6:00:00",
|
||||||
|
"location": {
|
||||||
|
"timeZone": "America/Toronto"
|
||||||
|
},
|
||||||
"program": {
|
"program": {
|
||||||
"climates": [
|
"climates": [
|
||||||
{ "name": "Climate1", "climateRef": "c1" },
|
{ "name": "Climate1", "climateRef": "c1" },
|
||||||
@ -30,6 +35,7 @@
|
|||||||
"ventilatorType": "hrv",
|
"ventilatorType": "hrv",
|
||||||
"ventilatorMinOnTimeHome": 20,
|
"ventilatorMinOnTimeHome": 20,
|
||||||
"ventilatorMinOnTimeAway": 10,
|
"ventilatorMinOnTimeAway": 10,
|
||||||
|
"ventilatorOffDateTime": "2022-01-01 6:00:00",
|
||||||
"isVentilatorTimerOn": false,
|
"isVentilatorTimerOn": false,
|
||||||
"hasHumidifier": true,
|
"hasHumidifier": true,
|
||||||
"humidifierMode": "manual",
|
"humidifierMode": "manual",
|
||||||
|
115
tests/components/ecobee/test_switch.py
Normal file
115
tests/components/ecobee/test_switch.py
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
"""The test for the ecobee thermostat switch module."""
|
||||||
|
|
||||||
|
import copy
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from unittest import mock
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.ecobee.switch import DATE_FORMAT
|
||||||
|
from homeassistant.components.switch import DOMAIN, SERVICE_TURN_OFF, SERVICE_TURN_ON
|
||||||
|
from homeassistant.const import ATTR_ENTITY_ID
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from .common import setup_platform
|
||||||
|
|
||||||
|
from tests.components.ecobee import GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP
|
||||||
|
|
||||||
|
VENTILATOR_20MIN_ID = "switch.ecobee_ventilator_20m_timer"
|
||||||
|
THERMOSTAT_ID = 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="data")
|
||||||
|
def data_fixture():
|
||||||
|
"""Set up data mock."""
|
||||||
|
data = mock.Mock()
|
||||||
|
data.return_value = copy.deepcopy(GENERIC_THERMOSTAT_INFO_WITH_HEATPUMP)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
async def test_ventilator_20min_attributes(hass: HomeAssistant) -> None:
|
||||||
|
"""Test the ventilator switch on home attributes are correct."""
|
||||||
|
await setup_platform(hass, DOMAIN)
|
||||||
|
|
||||||
|
state = hass.states.get(VENTILATOR_20MIN_ID)
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_ventilator_20min_when_on(hass: HomeAssistant, data) -> None:
|
||||||
|
"""Test the ventilator switch goes on."""
|
||||||
|
|
||||||
|
data.return_value["settings"]["ventilatorOffDateTime"] = (
|
||||||
|
datetime.now() + timedelta(days=1)
|
||||||
|
).strftime(DATE_FORMAT)
|
||||||
|
with mock.patch("pyecobee.Ecobee.get_thermostat", data):
|
||||||
|
await setup_platform(hass, DOMAIN)
|
||||||
|
|
||||||
|
state = hass.states.get(VENTILATOR_20MIN_ID)
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
data.reset_mock()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_ventilator_20min_when_off(hass: HomeAssistant, data) -> None:
|
||||||
|
"""Test the ventilator switch goes on."""
|
||||||
|
|
||||||
|
data.return_value["settings"]["ventilatorOffDateTime"] = (
|
||||||
|
datetime.now() - timedelta(days=1)
|
||||||
|
).strftime(DATE_FORMAT)
|
||||||
|
with mock.patch("pyecobee.Ecobee.get_thermostat", data):
|
||||||
|
await setup_platform(hass, DOMAIN)
|
||||||
|
|
||||||
|
state = hass.states.get(VENTILATOR_20MIN_ID)
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
data.reset_mock()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_ventilator_20min_when_empty(hass: HomeAssistant, data) -> None:
|
||||||
|
"""Test the ventilator switch goes on."""
|
||||||
|
|
||||||
|
data.return_value["settings"]["ventilatorOffDateTime"] = ""
|
||||||
|
with mock.patch("pyecobee.Ecobee.get_thermostat", data):
|
||||||
|
await setup_platform(hass, DOMAIN)
|
||||||
|
|
||||||
|
state = hass.states.get(VENTILATOR_20MIN_ID)
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
data.reset_mock()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_turn_on_20min_ventilator(hass: HomeAssistant) -> None:
|
||||||
|
"""Test the switch 20 min timer (On)."""
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.ecobee.Ecobee.set_ventilator_timer"
|
||||||
|
) as mock_set_20min_ventilator:
|
||||||
|
await setup_platform(hass, DOMAIN)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
{ATTR_ENTITY_ID: VENTILATOR_20MIN_ID},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
mock_set_20min_ventilator.assert_called_once_with(THERMOSTAT_ID, True)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_turn_off_20min_ventilator(hass: HomeAssistant) -> None:
|
||||||
|
"""Test the switch 20 min timer (off)."""
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.ecobee.Ecobee.set_ventilator_timer"
|
||||||
|
) as mock_set_20min_ventilator:
|
||||||
|
await setup_platform(hass, DOMAIN)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
{ATTR_ENTITY_ID: VENTILATOR_20MIN_ID},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
mock_set_20min_ventilator.assert_called_once_with(THERMOSTAT_ID, False)
|
@ -3,15 +3,24 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components import history
|
from homeassistant.components import history
|
||||||
|
from homeassistant.components.recorder import Recorder
|
||||||
from homeassistant.const import CONF_DOMAINS, CONF_ENTITIES, CONF_EXCLUDE, CONF_INCLUDE
|
from homeassistant.const import CONF_DOMAINS, CONF_ENTITIES, CONF_EXCLUDE, CONF_INCLUDE
|
||||||
from homeassistant.setup import setup_component
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from tests.typing import RecorderInstanceGenerator
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def hass_history(hass_recorder):
|
async def mock_recorder_before_hass(
|
||||||
"""Home Assistant fixture with history."""
|
async_setup_recorder_instance: RecorderInstanceGenerator,
|
||||||
hass = hass_recorder()
|
) -> None:
|
||||||
|
"""Set up recorder."""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def hass_history(hass: HomeAssistant, recorder_mock: Recorder) -> None:
|
||||||
|
"""Home Assistant fixture with history."""
|
||||||
config = history.CONFIG_SCHEMA(
|
config = history.CONFIG_SCHEMA(
|
||||||
{
|
{
|
||||||
history.DOMAIN: {
|
history.DOMAIN: {
|
||||||
@ -26,6 +35,4 @@ def hass_history(hass_recorder):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
assert setup_component(hass, history.DOMAIN, config)
|
assert await async_setup_component(hass, history.DOMAIN, config)
|
||||||
|
|
||||||
return hass
|
|
||||||
|
@ -24,7 +24,6 @@ from tests.components.recorder.common import (
|
|||||||
assert_multiple_states_equal_without_context_and_last_changed,
|
assert_multiple_states_equal_without_context_and_last_changed,
|
||||||
assert_states_equal_without_context,
|
assert_states_equal_without_context,
|
||||||
async_wait_recording_done,
|
async_wait_recording_done,
|
||||||
wait_recording_done,
|
|
||||||
)
|
)
|
||||||
from tests.typing import ClientSessionGenerator
|
from tests.typing import ClientSessionGenerator
|
||||||
|
|
||||||
@ -39,25 +38,26 @@ def listeners_without_writes(listeners: dict[str, int]) -> dict[str, int]:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("hass_history")
|
@pytest.mark.usefixtures("hass_history")
|
||||||
def test_setup() -> None:
|
async def test_setup() -> None:
|
||||||
"""Test setup method of history."""
|
"""Test setup method of history."""
|
||||||
# Verification occurs in the fixture
|
# Verification occurs in the fixture
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states(hass_history) -> None:
|
async def test_get_significant_states(hass: HomeAssistant, hass_history) -> None:
|
||||||
"""Test that only significant states are returned.
|
"""Test that only significant states are returned.
|
||||||
|
|
||||||
We should get back every thermostat change that
|
We should get back every thermostat change that
|
||||||
includes an attribute change, but only the state updates for
|
includes an attribute change, but only the state updates for
|
||||||
media player (attribute changes are not significant and not returned).
|
media player (attribute changes are not significant and not returned).
|
||||||
"""
|
"""
|
||||||
hass = hass_history
|
zero, four, states = await async_record_states(hass)
|
||||||
zero, four, states = record_states(hass)
|
|
||||||
hist = get_significant_states(hass, zero, four, entity_ids=list(states))
|
hist = get_significant_states(hass, zero, four, entity_ids=list(states))
|
||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_minimal_response(hass_history) -> None:
|
async def test_get_significant_states_minimal_response(
|
||||||
|
hass: HomeAssistant, hass_history
|
||||||
|
) -> None:
|
||||||
"""Test that only significant states are returned.
|
"""Test that only significant states are returned.
|
||||||
|
|
||||||
When minimal responses is set only the first and
|
When minimal responses is set only the first and
|
||||||
@ -67,8 +67,7 @@ def test_get_significant_states_minimal_response(hass_history) -> None:
|
|||||||
includes an attribute change, but only the state updates for
|
includes an attribute change, but only the state updates for
|
||||||
media player (attribute changes are not significant and not returned).
|
media player (attribute changes are not significant and not returned).
|
||||||
"""
|
"""
|
||||||
hass = hass_history
|
zero, four, states = await async_record_states(hass)
|
||||||
zero, four, states = record_states(hass)
|
|
||||||
hist = get_significant_states(
|
hist = get_significant_states(
|
||||||
hass, zero, four, minimal_response=True, entity_ids=list(states)
|
hass, zero, four, minimal_response=True, entity_ids=list(states)
|
||||||
)
|
)
|
||||||
@ -122,15 +121,16 @@ def test_get_significant_states_minimal_response(hass_history) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_with_initial(hass_history) -> None:
|
async def test_get_significant_states_with_initial(
|
||||||
|
hass: HomeAssistant, hass_history
|
||||||
|
) -> None:
|
||||||
"""Test that only significant states are returned.
|
"""Test that only significant states are returned.
|
||||||
|
|
||||||
We should get back every thermostat change that
|
We should get back every thermostat change that
|
||||||
includes an attribute change, but only the state updates for
|
includes an attribute change, but only the state updates for
|
||||||
media player (attribute changes are not significant and not returned).
|
media player (attribute changes are not significant and not returned).
|
||||||
"""
|
"""
|
||||||
hass = hass_history
|
zero, four, states = await async_record_states(hass)
|
||||||
zero, four, states = record_states(hass)
|
|
||||||
one_and_half = zero + timedelta(seconds=1.5)
|
one_and_half = zero + timedelta(seconds=1.5)
|
||||||
for entity_id in states:
|
for entity_id in states:
|
||||||
if entity_id == "media_player.test":
|
if entity_id == "media_player.test":
|
||||||
@ -149,15 +149,16 @@ def test_get_significant_states_with_initial(hass_history) -> None:
|
|||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_without_initial(hass_history) -> None:
|
async def test_get_significant_states_without_initial(
|
||||||
|
hass: HomeAssistant, hass_history
|
||||||
|
) -> None:
|
||||||
"""Test that only significant states are returned.
|
"""Test that only significant states are returned.
|
||||||
|
|
||||||
We should get back every thermostat change that
|
We should get back every thermostat change that
|
||||||
includes an attribute change, but only the state updates for
|
includes an attribute change, but only the state updates for
|
||||||
media player (attribute changes are not significant and not returned).
|
media player (attribute changes are not significant and not returned).
|
||||||
"""
|
"""
|
||||||
hass = hass_history
|
zero, four, states = await async_record_states(hass)
|
||||||
zero, four, states = record_states(hass)
|
|
||||||
one = zero + timedelta(seconds=1)
|
one = zero + timedelta(seconds=1)
|
||||||
one_with_microsecond = zero + timedelta(seconds=1, microseconds=1)
|
one_with_microsecond = zero + timedelta(seconds=1, microseconds=1)
|
||||||
one_and_half = zero + timedelta(seconds=1.5)
|
one_and_half = zero + timedelta(seconds=1.5)
|
||||||
@ -179,10 +180,11 @@ def test_get_significant_states_without_initial(hass_history) -> None:
|
|||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_entity_id(hass_history) -> None:
|
async def test_get_significant_states_entity_id(
|
||||||
|
hass: HomeAssistant, hass_history
|
||||||
|
) -> None:
|
||||||
"""Test that only significant states are returned for one entity."""
|
"""Test that only significant states are returned for one entity."""
|
||||||
hass = hass_history
|
zero, four, states = await async_record_states(hass)
|
||||||
zero, four, states = record_states(hass)
|
|
||||||
del states["media_player.test2"]
|
del states["media_player.test2"]
|
||||||
del states["media_player.test3"]
|
del states["media_player.test3"]
|
||||||
del states["thermostat.test"]
|
del states["thermostat.test"]
|
||||||
@ -193,10 +195,11 @@ def test_get_significant_states_entity_id(hass_history) -> None:
|
|||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_multiple_entity_ids(hass_history) -> None:
|
async def test_get_significant_states_multiple_entity_ids(
|
||||||
|
hass: HomeAssistant, hass_history
|
||||||
|
) -> None:
|
||||||
"""Test that only significant states are returned for one entity."""
|
"""Test that only significant states are returned for one entity."""
|
||||||
hass = hass_history
|
zero, four, states = await async_record_states(hass)
|
||||||
zero, four, states = record_states(hass)
|
|
||||||
del states["media_player.test2"]
|
del states["media_player.test2"]
|
||||||
del states["media_player.test3"]
|
del states["media_player.test3"]
|
||||||
del states["thermostat.test2"]
|
del states["thermostat.test2"]
|
||||||
@ -211,14 +214,15 @@ def test_get_significant_states_multiple_entity_ids(hass_history) -> None:
|
|||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_are_ordered(hass_history) -> None:
|
async def test_get_significant_states_are_ordered(
|
||||||
|
hass: HomeAssistant, hass_history
|
||||||
|
) -> None:
|
||||||
"""Test order of results from get_significant_states.
|
"""Test order of results from get_significant_states.
|
||||||
|
|
||||||
When entity ids are given, the results should be returned with the data
|
When entity ids are given, the results should be returned with the data
|
||||||
in the same order.
|
in the same order.
|
||||||
"""
|
"""
|
||||||
hass = hass_history
|
zero, four, _states = await async_record_states(hass)
|
||||||
zero, four, _states = record_states(hass)
|
|
||||||
entity_ids = ["media_player.test", "media_player.test2"]
|
entity_ids = ["media_player.test", "media_player.test2"]
|
||||||
hist = get_significant_states(hass, zero, four, entity_ids)
|
hist = get_significant_states(hass, zero, four, entity_ids)
|
||||||
assert list(hist.keys()) == entity_ids
|
assert list(hist.keys()) == entity_ids
|
||||||
@ -227,15 +231,14 @@ def test_get_significant_states_are_ordered(hass_history) -> None:
|
|||||||
assert list(hist.keys()) == entity_ids
|
assert list(hist.keys()) == entity_ids
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_only(hass_history) -> None:
|
async def test_get_significant_states_only(hass: HomeAssistant, hass_history) -> None:
|
||||||
"""Test significant states when significant_states_only is set."""
|
"""Test significant states when significant_states_only is set."""
|
||||||
hass = hass_history
|
|
||||||
entity_id = "sensor.test"
|
entity_id = "sensor.test"
|
||||||
|
|
||||||
def set_state(state, **kwargs):
|
async def set_state(state, **kwargs):
|
||||||
"""Set the state."""
|
"""Set the state."""
|
||||||
hass.states.set(entity_id, state, **kwargs)
|
hass.states.async_set(entity_id, state, **kwargs)
|
||||||
wait_recording_done(hass)
|
await async_wait_recording_done(hass)
|
||||||
return hass.states.get(entity_id)
|
return hass.states.get(entity_id)
|
||||||
|
|
||||||
start = dt_util.utcnow() - timedelta(minutes=4)
|
start = dt_util.utcnow() - timedelta(minutes=4)
|
||||||
@ -243,19 +246,19 @@ def test_get_significant_states_only(hass_history) -> None:
|
|||||||
|
|
||||||
states = []
|
states = []
|
||||||
with freeze_time(start) as freezer:
|
with freeze_time(start) as freezer:
|
||||||
set_state("123", attributes={"attribute": 10.64})
|
await set_state("123", attributes={"attribute": 10.64})
|
||||||
|
|
||||||
freezer.move_to(points[0])
|
freezer.move_to(points[0])
|
||||||
# Attributes are different, state not
|
# Attributes are different, state not
|
||||||
states.append(set_state("123", attributes={"attribute": 21.42}))
|
states.append(await set_state("123", attributes={"attribute": 21.42}))
|
||||||
|
|
||||||
freezer.move_to(points[1])
|
freezer.move_to(points[1])
|
||||||
# state is different, attributes not
|
# state is different, attributes not
|
||||||
states.append(set_state("32", attributes={"attribute": 21.42}))
|
states.append(await set_state("32", attributes={"attribute": 21.42}))
|
||||||
|
|
||||||
freezer.move_to(points[2])
|
freezer.move_to(points[2])
|
||||||
# everything is different
|
# everything is different
|
||||||
states.append(set_state("412", attributes={"attribute": 54.23}))
|
states.append(await set_state("412", attributes={"attribute": 54.23}))
|
||||||
|
|
||||||
hist = get_significant_states(
|
hist = get_significant_states(
|
||||||
hass,
|
hass,
|
||||||
@ -288,13 +291,13 @@ def test_get_significant_states_only(hass_history) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def check_significant_states(hass, zero, four, states, config):
|
async def check_significant_states(hass, zero, four, states, config):
|
||||||
"""Check if significant states are retrieved."""
|
"""Check if significant states are retrieved."""
|
||||||
hist = get_significant_states(hass, zero, four)
|
hist = get_significant_states(hass, zero, four)
|
||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def record_states(hass):
|
async def async_record_states(hass):
|
||||||
"""Record some test states.
|
"""Record some test states.
|
||||||
|
|
||||||
We inject a bunch of state updates from media player, zone and
|
We inject a bunch of state updates from media player, zone and
|
||||||
@ -308,10 +311,10 @@ def record_states(hass):
|
|||||||
zone = "zone.home"
|
zone = "zone.home"
|
||||||
script_c = "script.can_cancel_this_one"
|
script_c = "script.can_cancel_this_one"
|
||||||
|
|
||||||
def set_state(entity_id, state, **kwargs):
|
async def set_state(entity_id, state, **kwargs):
|
||||||
"""Set the state."""
|
"""Set the state."""
|
||||||
hass.states.set(entity_id, state, **kwargs)
|
hass.states.async_set(entity_id, state, **kwargs)
|
||||||
wait_recording_done(hass)
|
await async_wait_recording_done(hass)
|
||||||
return hass.states.get(entity_id)
|
return hass.states.get(entity_id)
|
||||||
|
|
||||||
zero = dt_util.utcnow()
|
zero = dt_util.utcnow()
|
||||||
@ -323,55 +326,63 @@ def record_states(hass):
|
|||||||
states = {therm: [], therm2: [], mp: [], mp2: [], mp3: [], script_c: []}
|
states = {therm: [], therm2: [], mp: [], mp2: [], mp3: [], script_c: []}
|
||||||
with freeze_time(one) as freezer:
|
with freeze_time(one) as freezer:
|
||||||
states[mp].append(
|
states[mp].append(
|
||||||
set_state(mp, "idle", attributes={"media_title": str(sentinel.mt1)})
|
await set_state(mp, "idle", attributes={"media_title": str(sentinel.mt1)})
|
||||||
)
|
)
|
||||||
states[mp2].append(
|
states[mp2].append(
|
||||||
set_state(mp2, "YouTube", attributes={"media_title": str(sentinel.mt2)})
|
await set_state(
|
||||||
|
mp2, "YouTube", attributes={"media_title": str(sentinel.mt2)}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
states[mp3].append(
|
states[mp3].append(
|
||||||
set_state(mp3, "idle", attributes={"media_title": str(sentinel.mt1)})
|
await set_state(mp3, "idle", attributes={"media_title": str(sentinel.mt1)})
|
||||||
)
|
)
|
||||||
states[therm].append(
|
states[therm].append(
|
||||||
set_state(therm, 20, attributes={"current_temperature": 19.5})
|
await set_state(therm, 20, attributes={"current_temperature": 19.5})
|
||||||
)
|
)
|
||||||
|
|
||||||
freezer.move_to(one + timedelta(microseconds=1))
|
freezer.move_to(one + timedelta(microseconds=1))
|
||||||
states[mp].append(
|
states[mp].append(
|
||||||
set_state(mp, "YouTube", attributes={"media_title": str(sentinel.mt2)})
|
await set_state(
|
||||||
|
mp, "YouTube", attributes={"media_title": str(sentinel.mt2)}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
freezer.move_to(two)
|
freezer.move_to(two)
|
||||||
# This state will be skipped only different in time
|
# This state will be skipped only different in time
|
||||||
set_state(mp, "YouTube", attributes={"media_title": str(sentinel.mt3)})
|
await set_state(mp, "YouTube", attributes={"media_title": str(sentinel.mt3)})
|
||||||
# This state will be skipped because domain is excluded
|
# This state will be skipped because domain is excluded
|
||||||
set_state(zone, "zoning")
|
await set_state(zone, "zoning")
|
||||||
states[script_c].append(
|
states[script_c].append(
|
||||||
set_state(script_c, "off", attributes={"can_cancel": True})
|
await set_state(script_c, "off", attributes={"can_cancel": True})
|
||||||
)
|
)
|
||||||
states[therm].append(
|
states[therm].append(
|
||||||
set_state(therm, 21, attributes={"current_temperature": 19.8})
|
await set_state(therm, 21, attributes={"current_temperature": 19.8})
|
||||||
)
|
)
|
||||||
states[therm2].append(
|
states[therm2].append(
|
||||||
set_state(therm2, 20, attributes={"current_temperature": 19})
|
await set_state(therm2, 20, attributes={"current_temperature": 19})
|
||||||
)
|
)
|
||||||
|
|
||||||
freezer.move_to(three)
|
freezer.move_to(three)
|
||||||
states[mp].append(
|
states[mp].append(
|
||||||
set_state(mp, "Netflix", attributes={"media_title": str(sentinel.mt4)})
|
await set_state(
|
||||||
|
mp, "Netflix", attributes={"media_title": str(sentinel.mt4)}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
states[mp3].append(
|
states[mp3].append(
|
||||||
set_state(mp3, "Netflix", attributes={"media_title": str(sentinel.mt3)})
|
await set_state(
|
||||||
|
mp3, "Netflix", attributes={"media_title": str(sentinel.mt3)}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
# Attributes changed even though state is the same
|
# Attributes changed even though state is the same
|
||||||
states[therm].append(
|
states[therm].append(
|
||||||
set_state(therm, 21, attributes={"current_temperature": 20})
|
await set_state(therm, 21, attributes={"current_temperature": 20})
|
||||||
)
|
)
|
||||||
|
|
||||||
return zero, four, states
|
return zero, four, states
|
||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api(
|
async def test_fetch_period_api(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history."""
|
"""Test the fetch period view for history."""
|
||||||
await async_setup_component(hass, "history", {})
|
await async_setup_component(hass, "history", {})
|
||||||
@ -383,8 +394,8 @@ async def test_fetch_period_api(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_with_use_include_order(
|
async def test_fetch_period_api_with_use_include_order(
|
||||||
recorder_mock: Recorder,
|
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
recorder_mock: Recorder,
|
||||||
hass_client: ClientSessionGenerator,
|
hass_client: ClientSessionGenerator,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -402,7 +413,7 @@ async def test_fetch_period_api_with_use_include_order(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_with_minimal_response(
|
async def test_fetch_period_api_with_minimal_response(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history with minimal_response."""
|
"""Test the fetch period view for history with minimal_response."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -444,7 +455,7 @@ async def test_fetch_period_api_with_minimal_response(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_with_no_timestamp(
|
async def test_fetch_period_api_with_no_timestamp(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history with no timestamp."""
|
"""Test the fetch period view for history with no timestamp."""
|
||||||
await async_setup_component(hass, "history", {})
|
await async_setup_component(hass, "history", {})
|
||||||
@ -454,8 +465,8 @@ async def test_fetch_period_api_with_no_timestamp(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_with_include_order(
|
async def test_fetch_period_api_with_include_order(
|
||||||
recorder_mock: Recorder,
|
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
recorder_mock: Recorder,
|
||||||
hass_client: ClientSessionGenerator,
|
hass_client: ClientSessionGenerator,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -482,7 +493,7 @@ async def test_fetch_period_api_with_include_order(
|
|||||||
|
|
||||||
|
|
||||||
async def test_entity_ids_limit_via_api(
|
async def test_entity_ids_limit_via_api(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test limiting history to entity_ids."""
|
"""Test limiting history to entity_ids."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -508,7 +519,7 @@ async def test_entity_ids_limit_via_api(
|
|||||||
|
|
||||||
|
|
||||||
async def test_entity_ids_limit_via_api_with_skip_initial_state(
|
async def test_entity_ids_limit_via_api_with_skip_initial_state(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test limiting history to entity_ids with skip_initial_state."""
|
"""Test limiting history to entity_ids with skip_initial_state."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -542,7 +553,7 @@ async def test_entity_ids_limit_via_api_with_skip_initial_state(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_before_history_started(
|
async def test_fetch_period_api_before_history_started(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history for the far past."""
|
"""Test the fetch period view for history for the far past."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -563,7 +574,7 @@ async def test_fetch_period_api_before_history_started(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_far_future(
|
async def test_fetch_period_api_far_future(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history for the far future."""
|
"""Test the fetch period view for history for the far future."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -584,7 +595,7 @@ async def test_fetch_period_api_far_future(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_with_invalid_datetime(
|
async def test_fetch_period_api_with_invalid_datetime(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history with an invalid date time."""
|
"""Test the fetch period view for history with an invalid date time."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -603,7 +614,7 @@ async def test_fetch_period_api_with_invalid_datetime(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_invalid_end_time(
|
async def test_fetch_period_api_invalid_end_time(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history with an invalid end time."""
|
"""Test the fetch period view for history with an invalid end time."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -625,7 +636,7 @@ async def test_fetch_period_api_invalid_end_time(
|
|||||||
|
|
||||||
|
|
||||||
async def test_entity_ids_limit_via_api_with_end_time(
|
async def test_entity_ids_limit_via_api_with_end_time(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test limiting history to entity_ids with end_time."""
|
"""Test limiting history to entity_ids with end_time."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -671,7 +682,7 @@ async def test_entity_ids_limit_via_api_with_end_time(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_with_no_entity_ids(
|
async def test_fetch_period_api_with_no_entity_ids(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history with minimal_response."""
|
"""Test the fetch period view for history with minimal_response."""
|
||||||
await async_setup_component(hass, "history", {})
|
await async_setup_component(hass, "history", {})
|
||||||
@ -724,13 +735,13 @@ async def test_fetch_period_api_with_no_entity_ids(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_history_with_invalid_entity_ids(
|
async def test_history_with_invalid_entity_ids(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
recorder_mock: Recorder,
|
||||||
|
hass_client: ClientSessionGenerator,
|
||||||
filter_entity_id,
|
filter_entity_id,
|
||||||
status_code,
|
status_code,
|
||||||
response_contains1,
|
response_contains1,
|
||||||
response_contains2,
|
response_contains2,
|
||||||
recorder_mock: Recorder,
|
|
||||||
hass: HomeAssistant,
|
|
||||||
hass_client: ClientSessionGenerator,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test sending valid and invalid entity_ids to the API."""
|
"""Test sending valid and invalid entity_ids to the API."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
|
@ -27,7 +27,6 @@ from tests.components.recorder.common import (
|
|||||||
async_recorder_block_till_done,
|
async_recorder_block_till_done,
|
||||||
async_wait_recording_done,
|
async_wait_recording_done,
|
||||||
old_db_schema,
|
old_db_schema,
|
||||||
wait_recording_done,
|
|
||||||
)
|
)
|
||||||
from tests.typing import ClientSessionGenerator, WebSocketGenerator
|
from tests.typing import ClientSessionGenerator, WebSocketGenerator
|
||||||
|
|
||||||
@ -40,33 +39,34 @@ def db_schema_30():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def legacy_hass_history(hass_history):
|
def legacy_hass_history(hass: HomeAssistant, hass_history):
|
||||||
"""Home Assistant fixture to use legacy history recording."""
|
"""Home Assistant fixture to use legacy history recording."""
|
||||||
instance = recorder.get_instance(hass_history)
|
instance = recorder.get_instance(hass)
|
||||||
with patch.object(instance.states_meta_manager, "active", False):
|
with patch.object(instance.states_meta_manager, "active", False):
|
||||||
yield hass_history
|
yield
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("legacy_hass_history")
|
@pytest.mark.usefixtures("legacy_hass_history")
|
||||||
def test_setup() -> None:
|
async def test_setup() -> None:
|
||||||
"""Test setup method of history."""
|
"""Test setup method of history."""
|
||||||
# Verification occurs in the fixture
|
# Verification occurs in the fixture
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states(legacy_hass_history) -> None:
|
async def test_get_significant_states(hass: HomeAssistant, legacy_hass_history) -> None:
|
||||||
"""Test that only significant states are returned.
|
"""Test that only significant states are returned.
|
||||||
|
|
||||||
We should get back every thermostat change that
|
We should get back every thermostat change that
|
||||||
includes an attribute change, but only the state updates for
|
includes an attribute change, but only the state updates for
|
||||||
media player (attribute changes are not significant and not returned).
|
media player (attribute changes are not significant and not returned).
|
||||||
"""
|
"""
|
||||||
hass = legacy_hass_history
|
zero, four, states = await async_record_states(hass)
|
||||||
zero, four, states = record_states(hass)
|
|
||||||
hist = get_significant_states(hass, zero, four, entity_ids=list(states))
|
hist = get_significant_states(hass, zero, four, entity_ids=list(states))
|
||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_minimal_response(legacy_hass_history) -> None:
|
async def test_get_significant_states_minimal_response(
|
||||||
|
hass: HomeAssistant, legacy_hass_history
|
||||||
|
) -> None:
|
||||||
"""Test that only significant states are returned.
|
"""Test that only significant states are returned.
|
||||||
|
|
||||||
When minimal responses is set only the first and
|
When minimal responses is set only the first and
|
||||||
@ -76,8 +76,7 @@ def test_get_significant_states_minimal_response(legacy_hass_history) -> None:
|
|||||||
includes an attribute change, but only the state updates for
|
includes an attribute change, but only the state updates for
|
||||||
media player (attribute changes are not significant and not returned).
|
media player (attribute changes are not significant and not returned).
|
||||||
"""
|
"""
|
||||||
hass = legacy_hass_history
|
zero, four, states = await async_record_states(hass)
|
||||||
zero, four, states = record_states(hass)
|
|
||||||
hist = get_significant_states(
|
hist = get_significant_states(
|
||||||
hass, zero, four, minimal_response=True, entity_ids=list(states)
|
hass, zero, four, minimal_response=True, entity_ids=list(states)
|
||||||
)
|
)
|
||||||
@ -132,15 +131,16 @@ def test_get_significant_states_minimal_response(legacy_hass_history) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_with_initial(legacy_hass_history) -> None:
|
async def test_get_significant_states_with_initial(
|
||||||
|
hass: HomeAssistant, legacy_hass_history
|
||||||
|
) -> None:
|
||||||
"""Test that only significant states are returned.
|
"""Test that only significant states are returned.
|
||||||
|
|
||||||
We should get back every thermostat change that
|
We should get back every thermostat change that
|
||||||
includes an attribute change, but only the state updates for
|
includes an attribute change, but only the state updates for
|
||||||
media player (attribute changes are not significant and not returned).
|
media player (attribute changes are not significant and not returned).
|
||||||
"""
|
"""
|
||||||
hass = legacy_hass_history
|
zero, four, states = await async_record_states(hass)
|
||||||
zero, four, states = record_states(hass)
|
|
||||||
one = zero + timedelta(seconds=1)
|
one = zero + timedelta(seconds=1)
|
||||||
one_with_microsecond = zero + timedelta(seconds=1, microseconds=1)
|
one_with_microsecond = zero + timedelta(seconds=1, microseconds=1)
|
||||||
one_and_half = zero + timedelta(seconds=1.5)
|
one_and_half = zero + timedelta(seconds=1.5)
|
||||||
@ -162,15 +162,16 @@ def test_get_significant_states_with_initial(legacy_hass_history) -> None:
|
|||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_without_initial(legacy_hass_history) -> None:
|
async def test_get_significant_states_without_initial(
|
||||||
|
hass: HomeAssistant, legacy_hass_history
|
||||||
|
) -> None:
|
||||||
"""Test that only significant states are returned.
|
"""Test that only significant states are returned.
|
||||||
|
|
||||||
We should get back every thermostat change that
|
We should get back every thermostat change that
|
||||||
includes an attribute change, but only the state updates for
|
includes an attribute change, but only the state updates for
|
||||||
media player (attribute changes are not significant and not returned).
|
media player (attribute changes are not significant and not returned).
|
||||||
"""
|
"""
|
||||||
hass = legacy_hass_history
|
zero, four, states = await async_record_states(hass)
|
||||||
zero, four, states = record_states(hass)
|
|
||||||
one = zero + timedelta(seconds=1)
|
one = zero + timedelta(seconds=1)
|
||||||
one_with_microsecond = zero + timedelta(seconds=1, microseconds=1)
|
one_with_microsecond = zero + timedelta(seconds=1, microseconds=1)
|
||||||
one_and_half = zero + timedelta(seconds=1.5)
|
one_and_half = zero + timedelta(seconds=1.5)
|
||||||
@ -193,13 +194,13 @@ def test_get_significant_states_without_initial(legacy_hass_history) -> None:
|
|||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_entity_id(hass_history) -> None:
|
async def test_get_significant_states_entity_id(
|
||||||
|
hass: HomeAssistant, hass_history
|
||||||
|
) -> None:
|
||||||
"""Test that only significant states are returned for one entity."""
|
"""Test that only significant states are returned for one entity."""
|
||||||
hass = hass_history
|
|
||||||
|
|
||||||
instance = recorder.get_instance(hass)
|
instance = recorder.get_instance(hass)
|
||||||
with patch.object(instance.states_meta_manager, "active", False):
|
with patch.object(instance.states_meta_manager, "active", False):
|
||||||
zero, four, states = record_states(hass)
|
zero, four, states = await async_record_states(hass)
|
||||||
del states["media_player.test2"]
|
del states["media_player.test2"]
|
||||||
del states["media_player.test3"]
|
del states["media_player.test3"]
|
||||||
del states["thermostat.test"]
|
del states["thermostat.test"]
|
||||||
@ -210,10 +211,11 @@ def test_get_significant_states_entity_id(hass_history) -> None:
|
|||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_multiple_entity_ids(legacy_hass_history) -> None:
|
async def test_get_significant_states_multiple_entity_ids(
|
||||||
|
hass: HomeAssistant, legacy_hass_history
|
||||||
|
) -> None:
|
||||||
"""Test that only significant states are returned for one entity."""
|
"""Test that only significant states are returned for one entity."""
|
||||||
hass = legacy_hass_history
|
zero, four, states = await async_record_states(hass)
|
||||||
zero, four, states = record_states(hass)
|
|
||||||
del states["media_player.test2"]
|
del states["media_player.test2"]
|
||||||
del states["media_player.test3"]
|
del states["media_player.test3"]
|
||||||
del states["thermostat.test2"]
|
del states["thermostat.test2"]
|
||||||
@ -228,14 +230,15 @@ def test_get_significant_states_multiple_entity_ids(legacy_hass_history) -> None
|
|||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_are_ordered(legacy_hass_history) -> None:
|
async def test_get_significant_states_are_ordered(
|
||||||
|
hass: HomeAssistant, legacy_hass_history
|
||||||
|
) -> None:
|
||||||
"""Test order of results from get_significant_states.
|
"""Test order of results from get_significant_states.
|
||||||
|
|
||||||
When entity ids are given, the results should be returned with the data
|
When entity ids are given, the results should be returned with the data
|
||||||
in the same order.
|
in the same order.
|
||||||
"""
|
"""
|
||||||
hass = legacy_hass_history
|
zero, four, _states = await async_record_states(hass)
|
||||||
zero, four, _states = record_states(hass)
|
|
||||||
entity_ids = ["media_player.test", "media_player.test2"]
|
entity_ids = ["media_player.test", "media_player.test2"]
|
||||||
hist = get_significant_states(hass, zero, four, entity_ids)
|
hist = get_significant_states(hass, zero, four, entity_ids)
|
||||||
assert list(hist.keys()) == entity_ids
|
assert list(hist.keys()) == entity_ids
|
||||||
@ -244,15 +247,16 @@ def test_get_significant_states_are_ordered(legacy_hass_history) -> None:
|
|||||||
assert list(hist.keys()) == entity_ids
|
assert list(hist.keys()) == entity_ids
|
||||||
|
|
||||||
|
|
||||||
def test_get_significant_states_only(legacy_hass_history) -> None:
|
async def test_get_significant_states_only(
|
||||||
|
hass: HomeAssistant, legacy_hass_history
|
||||||
|
) -> None:
|
||||||
"""Test significant states when significant_states_only is set."""
|
"""Test significant states when significant_states_only is set."""
|
||||||
hass = legacy_hass_history
|
|
||||||
entity_id = "sensor.test"
|
entity_id = "sensor.test"
|
||||||
|
|
||||||
def set_state(state, **kwargs):
|
async def set_state(state, **kwargs):
|
||||||
"""Set the state."""
|
"""Set the state."""
|
||||||
hass.states.set(entity_id, state, **kwargs)
|
hass.states.async_set(entity_id, state, **kwargs)
|
||||||
wait_recording_done(hass)
|
await async_wait_recording_done(hass)
|
||||||
return hass.states.get(entity_id)
|
return hass.states.get(entity_id)
|
||||||
|
|
||||||
start = dt_util.utcnow() - timedelta(minutes=4)
|
start = dt_util.utcnow() - timedelta(minutes=4)
|
||||||
@ -260,19 +264,19 @@ def test_get_significant_states_only(legacy_hass_history) -> None:
|
|||||||
|
|
||||||
states = []
|
states = []
|
||||||
with freeze_time(start) as freezer:
|
with freeze_time(start) as freezer:
|
||||||
set_state("123", attributes={"attribute": 10.64})
|
await set_state("123", attributes={"attribute": 10.64})
|
||||||
|
|
||||||
freezer.move_to(points[0])
|
freezer.move_to(points[0])
|
||||||
# Attributes are different, state not
|
# Attributes are different, state not
|
||||||
states.append(set_state("123", attributes={"attribute": 21.42}))
|
states.append(await set_state("123", attributes={"attribute": 21.42}))
|
||||||
|
|
||||||
freezer.move_to(points[1])
|
freezer.move_to(points[1])
|
||||||
# state is different, attributes not
|
# state is different, attributes not
|
||||||
states.append(set_state("32", attributes={"attribute": 21.42}))
|
states.append(await set_state("32", attributes={"attribute": 21.42}))
|
||||||
|
|
||||||
freezer.move_to(points[2])
|
freezer.move_to(points[2])
|
||||||
# everything is different
|
# everything is different
|
||||||
states.append(set_state("412", attributes={"attribute": 54.23}))
|
states.append(await set_state("412", attributes={"attribute": 54.23}))
|
||||||
|
|
||||||
hist = get_significant_states(
|
hist = get_significant_states(
|
||||||
hass,
|
hass,
|
||||||
@ -311,7 +315,7 @@ def check_significant_states(hass, zero, four, states, config):
|
|||||||
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
|
||||||
|
|
||||||
|
|
||||||
def record_states(hass):
|
async def async_record_states(hass):
|
||||||
"""Record some test states.
|
"""Record some test states.
|
||||||
|
|
||||||
We inject a bunch of state updates from media player, zone and
|
We inject a bunch of state updates from media player, zone and
|
||||||
@ -325,10 +329,10 @@ def record_states(hass):
|
|||||||
zone = "zone.home"
|
zone = "zone.home"
|
||||||
script_c = "script.can_cancel_this_one"
|
script_c = "script.can_cancel_this_one"
|
||||||
|
|
||||||
def set_state(entity_id, state, **kwargs):
|
async def async_set_state(entity_id, state, **kwargs):
|
||||||
"""Set the state."""
|
"""Set the state."""
|
||||||
hass.states.set(entity_id, state, **kwargs)
|
hass.states.async_set(entity_id, state, **kwargs)
|
||||||
wait_recording_done(hass)
|
await async_wait_recording_done(hass)
|
||||||
return hass.states.get(entity_id)
|
return hass.states.get(entity_id)
|
||||||
|
|
||||||
zero = dt_util.utcnow()
|
zero = dt_util.utcnow()
|
||||||
@ -340,55 +344,69 @@ def record_states(hass):
|
|||||||
states = {therm: [], therm2: [], mp: [], mp2: [], mp3: [], script_c: []}
|
states = {therm: [], therm2: [], mp: [], mp2: [], mp3: [], script_c: []}
|
||||||
with freeze_time(one) as freezer:
|
with freeze_time(one) as freezer:
|
||||||
states[mp].append(
|
states[mp].append(
|
||||||
set_state(mp, "idle", attributes={"media_title": str(sentinel.mt1)})
|
await async_set_state(
|
||||||
|
mp, "idle", attributes={"media_title": str(sentinel.mt1)}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
states[mp2].append(
|
states[mp2].append(
|
||||||
set_state(mp2, "YouTube", attributes={"media_title": str(sentinel.mt2)})
|
await async_set_state(
|
||||||
|
mp2, "YouTube", attributes={"media_title": str(sentinel.mt2)}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
states[mp3].append(
|
states[mp3].append(
|
||||||
set_state(mp3, "idle", attributes={"media_title": str(sentinel.mt1)})
|
await async_set_state(
|
||||||
|
mp3, "idle", attributes={"media_title": str(sentinel.mt1)}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
states[therm].append(
|
states[therm].append(
|
||||||
set_state(therm, 20, attributes={"current_temperature": 19.5})
|
await async_set_state(therm, 20, attributes={"current_temperature": 19.5})
|
||||||
)
|
)
|
||||||
|
|
||||||
freezer.move_to(one + timedelta(microseconds=1))
|
freezer.move_to(one + timedelta(microseconds=1))
|
||||||
states[mp].append(
|
states[mp].append(
|
||||||
set_state(mp, "YouTube", attributes={"media_title": str(sentinel.mt2)})
|
await async_set_state(
|
||||||
|
mp, "YouTube", attributes={"media_title": str(sentinel.mt2)}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
freezer.move_to(two)
|
freezer.move_to(two)
|
||||||
# This state will be skipped only different in time
|
# This state will be skipped only different in time
|
||||||
set_state(mp, "YouTube", attributes={"media_title": str(sentinel.mt3)})
|
await async_set_state(
|
||||||
|
mp, "YouTube", attributes={"media_title": str(sentinel.mt3)}
|
||||||
|
)
|
||||||
# This state will be skipped because domain is excluded
|
# This state will be skipped because domain is excluded
|
||||||
set_state(zone, "zoning")
|
await async_set_state(zone, "zoning")
|
||||||
states[script_c].append(
|
states[script_c].append(
|
||||||
set_state(script_c, "off", attributes={"can_cancel": True})
|
await async_set_state(script_c, "off", attributes={"can_cancel": True})
|
||||||
)
|
)
|
||||||
states[therm].append(
|
states[therm].append(
|
||||||
set_state(therm, 21, attributes={"current_temperature": 19.8})
|
await async_set_state(therm, 21, attributes={"current_temperature": 19.8})
|
||||||
)
|
)
|
||||||
states[therm2].append(
|
states[therm2].append(
|
||||||
set_state(therm2, 20, attributes={"current_temperature": 19})
|
await async_set_state(therm2, 20, attributes={"current_temperature": 19})
|
||||||
)
|
)
|
||||||
|
|
||||||
freezer.move_to(three)
|
freezer.move_to(three)
|
||||||
states[mp].append(
|
states[mp].append(
|
||||||
set_state(mp, "Netflix", attributes={"media_title": str(sentinel.mt4)})
|
await async_set_state(
|
||||||
|
mp, "Netflix", attributes={"media_title": str(sentinel.mt4)}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
states[mp3].append(
|
states[mp3].append(
|
||||||
set_state(mp3, "Netflix", attributes={"media_title": str(sentinel.mt3)})
|
await async_set_state(
|
||||||
|
mp3, "Netflix", attributes={"media_title": str(sentinel.mt3)}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
# Attributes changed even though state is the same
|
# Attributes changed even though state is the same
|
||||||
states[therm].append(
|
states[therm].append(
|
||||||
set_state(therm, 21, attributes={"current_temperature": 20})
|
await async_set_state(therm, 21, attributes={"current_temperature": 20})
|
||||||
)
|
)
|
||||||
|
|
||||||
return zero, four, states
|
return zero, four, states
|
||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api(
|
async def test_fetch_period_api(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history."""
|
"""Test the fetch period view for history."""
|
||||||
await async_setup_component(hass, "history", {})
|
await async_setup_component(hass, "history", {})
|
||||||
@ -402,7 +420,7 @@ async def test_fetch_period_api(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_with_minimal_response(
|
async def test_fetch_period_api_with_minimal_response(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history with minimal_response."""
|
"""Test the fetch period view for history with minimal_response."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -445,7 +463,7 @@ async def test_fetch_period_api_with_minimal_response(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_with_no_timestamp(
|
async def test_fetch_period_api_with_no_timestamp(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history with no timestamp."""
|
"""Test the fetch period view for history with no timestamp."""
|
||||||
await async_setup_component(hass, "history", {})
|
await async_setup_component(hass, "history", {})
|
||||||
@ -457,7 +475,7 @@ async def test_fetch_period_api_with_no_timestamp(
|
|||||||
|
|
||||||
|
|
||||||
async def test_fetch_period_api_with_include_order(
|
async def test_fetch_period_api_with_include_order(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the fetch period view for history."""
|
"""Test the fetch period view for history."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -481,7 +499,7 @@ async def test_fetch_period_api_with_include_order(
|
|||||||
|
|
||||||
|
|
||||||
async def test_entity_ids_limit_via_api(
|
async def test_entity_ids_limit_via_api(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test limiting history to entity_ids."""
|
"""Test limiting history to entity_ids."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -509,7 +527,7 @@ async def test_entity_ids_limit_via_api(
|
|||||||
|
|
||||||
|
|
||||||
async def test_entity_ids_limit_via_api_with_skip_initial_state(
|
async def test_entity_ids_limit_via_api_with_skip_initial_state(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_client: ClientSessionGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_client: ClientSessionGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test limiting history to entity_ids with skip_initial_state."""
|
"""Test limiting history to entity_ids with skip_initial_state."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -545,7 +563,7 @@ async def test_entity_ids_limit_via_api_with_skip_initial_state(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_during_period(
|
async def test_history_during_period(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period."""
|
"""Test history_during_period."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -693,7 +711,7 @@ async def test_history_during_period(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_during_period_impossible_conditions(
|
async def test_history_during_period_impossible_conditions(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period returns when condition cannot be true."""
|
"""Test history_during_period returns when condition cannot be true."""
|
||||||
await async_setup_component(hass, "history", {})
|
await async_setup_component(hass, "history", {})
|
||||||
@ -757,10 +775,10 @@ async def test_history_during_period_impossible_conditions(
|
|||||||
"time_zone", ["UTC", "Europe/Berlin", "America/Chicago", "US/Hawaii"]
|
"time_zone", ["UTC", "Europe/Berlin", "America/Chicago", "US/Hawaii"]
|
||||||
)
|
)
|
||||||
async def test_history_during_period_significant_domain(
|
async def test_history_during_period_significant_domain(
|
||||||
time_zone,
|
|
||||||
recorder_mock: Recorder,
|
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
recorder_mock: Recorder,
|
||||||
hass_ws_client: WebSocketGenerator,
|
hass_ws_client: WebSocketGenerator,
|
||||||
|
time_zone,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period with climate domain."""
|
"""Test history_during_period with climate domain."""
|
||||||
hass.config.set_time_zone(time_zone)
|
hass.config.set_time_zone(time_zone)
|
||||||
@ -941,7 +959,7 @@ async def test_history_during_period_significant_domain(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_during_period_bad_start_time(
|
async def test_history_during_period_bad_start_time(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period bad state time."""
|
"""Test history_during_period bad state time."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -966,7 +984,7 @@ async def test_history_during_period_bad_start_time(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_during_period_bad_end_time(
|
async def test_history_during_period_bad_end_time(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period bad end time."""
|
"""Test history_during_period bad end time."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
|
@ -39,7 +39,7 @@ def test_setup() -> None:
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_during_period(
|
async def test_history_during_period(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period."""
|
"""Test history_during_period."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -173,7 +173,7 @@ async def test_history_during_period(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_during_period_impossible_conditions(
|
async def test_history_during_period_impossible_conditions(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period returns when condition cannot be true."""
|
"""Test history_during_period returns when condition cannot be true."""
|
||||||
await async_setup_component(hass, "history", {})
|
await async_setup_component(hass, "history", {})
|
||||||
@ -235,10 +235,10 @@ async def test_history_during_period_impossible_conditions(
|
|||||||
"time_zone", ["UTC", "Europe/Berlin", "America/Chicago", "US/Hawaii"]
|
"time_zone", ["UTC", "Europe/Berlin", "America/Chicago", "US/Hawaii"]
|
||||||
)
|
)
|
||||||
async def test_history_during_period_significant_domain(
|
async def test_history_during_period_significant_domain(
|
||||||
time_zone,
|
|
||||||
recorder_mock: Recorder,
|
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
recorder_mock: Recorder,
|
||||||
hass_ws_client: WebSocketGenerator,
|
hass_ws_client: WebSocketGenerator,
|
||||||
|
time_zone,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period with climate domain."""
|
"""Test history_during_period with climate domain."""
|
||||||
hass.config.set_time_zone(time_zone)
|
hass.config.set_time_zone(time_zone)
|
||||||
@ -403,7 +403,7 @@ async def test_history_during_period_significant_domain(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_during_period_bad_start_time(
|
async def test_history_during_period_bad_start_time(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period bad state time."""
|
"""Test history_during_period bad state time."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -427,7 +427,7 @@ async def test_history_during_period_bad_start_time(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_during_period_bad_end_time(
|
async def test_history_during_period_bad_end_time(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period bad end time."""
|
"""Test history_during_period bad end time."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -454,7 +454,7 @@ async def test_history_during_period_bad_end_time(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_historical_only(
|
async def test_history_stream_historical_only(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream."""
|
"""Test history stream."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -525,7 +525,7 @@ async def test_history_stream_historical_only(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_significant_domain_historical_only(
|
async def test_history_stream_significant_domain_historical_only(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the stream with climate domain with historical states only."""
|
"""Test the stream with climate domain with historical states only."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -726,7 +726,7 @@ async def test_history_stream_significant_domain_historical_only(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_bad_start_time(
|
async def test_history_stream_bad_start_time(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream bad state time."""
|
"""Test history stream bad state time."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -750,7 +750,7 @@ async def test_history_stream_bad_start_time(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_end_time_before_start_time(
|
async def test_history_stream_end_time_before_start_time(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream with an end_time before the start_time."""
|
"""Test history stream with an end_time before the start_time."""
|
||||||
end_time = dt_util.utcnow() - timedelta(seconds=2)
|
end_time = dt_util.utcnow() - timedelta(seconds=2)
|
||||||
@ -778,7 +778,7 @@ async def test_history_stream_end_time_before_start_time(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_bad_end_time(
|
async def test_history_stream_bad_end_time(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream bad end time."""
|
"""Test history stream bad end time."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -805,7 +805,7 @@ async def test_history_stream_bad_end_time(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_live_no_attributes_minimal_response(
|
async def test_history_stream_live_no_attributes_minimal_response(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream with history and live data and no_attributes and minimal_response."""
|
"""Test history stream with history and live data and no_attributes and minimal_response."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -882,7 +882,7 @@ async def test_history_stream_live_no_attributes_minimal_response(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_live(
|
async def test_history_stream_live(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream with history and live data."""
|
"""Test history stream with history and live data."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -985,7 +985,7 @@ async def test_history_stream_live(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_live_minimal_response(
|
async def test_history_stream_live_minimal_response(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream with history and live data and minimal_response."""
|
"""Test history stream with history and live data and minimal_response."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -1082,7 +1082,7 @@ async def test_history_stream_live_minimal_response(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_live_no_attributes(
|
async def test_history_stream_live_no_attributes(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream with history and live data and no_attributes."""
|
"""Test history stream with history and live data and no_attributes."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -1163,7 +1163,7 @@ async def test_history_stream_live_no_attributes(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_live_no_attributes_minimal_response_specific_entities(
|
async def test_history_stream_live_no_attributes_minimal_response_specific_entities(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream with history and live data and no_attributes and minimal_response with specific entities."""
|
"""Test history stream with history and live data and no_attributes and minimal_response with specific entities."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -1241,7 +1241,7 @@ async def test_history_stream_live_no_attributes_minimal_response_specific_entit
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_live_with_future_end_time(
|
async def test_history_stream_live_with_future_end_time(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream with history and live data with future end time."""
|
"""Test history stream with history and live data with future end time."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -1334,8 +1334,8 @@ async def test_history_stream_live_with_future_end_time(
|
|||||||
|
|
||||||
@pytest.mark.parametrize("include_start_time_state", [True, False])
|
@pytest.mark.parametrize("include_start_time_state", [True, False])
|
||||||
async def test_history_stream_before_history_starts(
|
async def test_history_stream_before_history_starts(
|
||||||
recorder_mock: Recorder,
|
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
recorder_mock: Recorder,
|
||||||
hass_ws_client: WebSocketGenerator,
|
hass_ws_client: WebSocketGenerator,
|
||||||
include_start_time_state,
|
include_start_time_state,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -1385,7 +1385,7 @@ async def test_history_stream_before_history_starts(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_for_entity_with_no_possible_changes(
|
async def test_history_stream_for_entity_with_no_possible_changes(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream for future with no possible changes where end time is less than or equal to now."""
|
"""Test history stream for future with no possible changes where end time is less than or equal to now."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
@ -1436,7 +1436,7 @@ async def test_history_stream_for_entity_with_no_possible_changes(
|
|||||||
|
|
||||||
|
|
||||||
async def test_overflow_queue(
|
async def test_overflow_queue(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test overflowing the history stream queue."""
|
"""Test overflowing the history stream queue."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -1513,7 +1513,7 @@ async def test_overflow_queue(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_during_period_for_invalid_entity_ids(
|
async def test_history_during_period_for_invalid_entity_ids(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period for valid and invalid entity ids."""
|
"""Test history_during_period for valid and invalid entity ids."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
@ -1656,7 +1656,7 @@ async def test_history_during_period_for_invalid_entity_ids(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_for_invalid_entity_ids(
|
async def test_history_stream_for_invalid_entity_ids(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream for invalid and valid entity ids."""
|
"""Test history stream for invalid and valid entity ids."""
|
||||||
|
|
||||||
@ -1824,7 +1824,7 @@ async def test_history_stream_for_invalid_entity_ids(
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_stream_historical_only_with_start_time_state_past(
|
async def test_history_stream_historical_only_with_start_time_state_past(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history stream."""
|
"""Test history stream."""
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
|
@ -24,7 +24,7 @@ def db_schema_32():
|
|||||||
|
|
||||||
|
|
||||||
async def test_history_during_period(
|
async def test_history_during_period(
|
||||||
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, recorder_mock: Recorder, hass_ws_client: WebSocketGenerator
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test history_during_period."""
|
"""Test history_during_period."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
|
@ -198,7 +198,7 @@ async def test_shutdown_closes_connections(
|
|||||||
|
|
||||||
hass.set_state(CoreState.not_running)
|
hass.set_state(CoreState.not_running)
|
||||||
|
|
||||||
instance = get_instance(hass)
|
instance = recorder.get_instance(hass)
|
||||||
await instance.async_db_ready
|
await instance.async_db_ready
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
pool = instance.engine.pool
|
pool = instance.engine.pool
|
||||||
|
@ -526,6 +526,7 @@ async def hass(
|
|||||||
load_registries: bool,
|
load_registries: bool,
|
||||||
hass_storage: dict[str, Any],
|
hass_storage: dict[str, Any],
|
||||||
request: pytest.FixtureRequest,
|
request: pytest.FixtureRequest,
|
||||||
|
mock_recorder_before_hass: None,
|
||||||
) -> AsyncGenerator[HomeAssistant, None]:
|
) -> AsyncGenerator[HomeAssistant, None]:
|
||||||
"""Create a test instance of Home Assistant."""
|
"""Create a test instance of Home Assistant."""
|
||||||
|
|
||||||
@ -1577,6 +1578,15 @@ async def recorder_mock(
|
|||||||
return await async_setup_recorder_instance(hass, recorder_config)
|
return await async_setup_recorder_instance(hass, recorder_config)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_recorder_before_hass() -> None:
|
||||||
|
"""Mock the recorder.
|
||||||
|
|
||||||
|
Override or parametrize this fixture with a fixture that mocks the recorder,
|
||||||
|
in the tests that need to test the recorder.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="enable_bluetooth")
|
@pytest.fixture(name="enable_bluetooth")
|
||||||
async def mock_enable_bluetooth(
|
async def mock_enable_bluetooth(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user