Compare commits

..

1 Commits

Author SHA1 Message Date
Bram Kragten
1e8ed749ae Update frontend to 20260107.1 2026-01-09 23:30:48 +01:00
18 changed files with 347 additions and 470 deletions

View File

@@ -43,13 +43,6 @@ BUTTON_TYPES: tuple[AirobotButtonEntityDescription, ...] = (
entity_category=EntityCategory.CONFIG,
press_fn=lambda coordinator: coordinator.client.reboot_thermostat(),
),
AirobotButtonEntityDescription(
key="recalibrate_co2",
translation_key="recalibrate_co2",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
press_fn=lambda coordinator: coordinator.client.recalibrate_co2_sensor(),
),
)

View File

@@ -1,10 +1,5 @@
{
"entity": {
"button": {
"recalibrate_co2": {
"default": "mdi:molecule-co2"
}
},
"number": {
"hysteresis_band": {
"default": "mdi:delta"

View File

@@ -59,11 +59,6 @@
}
},
"entity": {
"button": {
"recalibrate_co2": {
"name": "Recalibrate CO2 sensor"
}
},
"number": {
"hysteresis_band": {
"name": "Hysteresis band"

View File

@@ -23,5 +23,5 @@
"winter_mode": {}
},
"quality_scale": "internal",
"requirements": ["home-assistant-frontend==20260107.0"]
"requirements": ["home-assistant-frontend==20260107.1"]
}

View File

@@ -8,5 +8,5 @@
"iot_class": "local_push",
"loggers": ["pyhik"],
"quality_scale": "legacy",
"requirements": ["pyHik==0.4.0"]
"requirements": ["pyHik==0.3.4"]
}

View File

@@ -50,6 +50,7 @@ rules:
Use load_json_object_fixture in tests
Patch the library instead of the HTTP requests
Create a shared fixture for the mock config entry
Use snapshots for binary sensor tests
Use init_integration in tests
Evaluate the need of test_config_entry_not_ready

View File

@@ -13,5 +13,5 @@
"integration_type": "hub",
"iot_class": "cloud_polling",
"loggers": ["switchbot_api"],
"requirements": ["switchbot-api==2.10.0"]
"requirements": ["switchbot-api==2.9.0"]
}

View File

@@ -654,7 +654,6 @@ DISCOVERY_SCHEMAS: list[NewZWaveDiscoverySchema] = [
key=NOTIFICATION_SMOKE_ALARM,
entity_category=EntityCategory.DIAGNOSTIC,
not_states={
0,
SmokeAlarmNotificationEvent.SENSOR_STATUS_SMOKE_DETECTED_LOCATION_PROVIDED,
SmokeAlarmNotificationEvent.SENSOR_STATUS_SMOKE_DETECTED,
SmokeAlarmNotificationEvent.MAINTENANCE_STATUS_REPLACEMENT_REQUIRED,

View File

@@ -39,7 +39,7 @@ habluetooth==5.8.0
hass-nabucasa==1.7.0
hassil==3.5.0
home-assistant-bluetooth==1.13.1
home-assistant-frontend==20260107.0
home-assistant-frontend==20260107.1
home-assistant-intents==2026.1.6
httpx==0.28.1
ifaddr==0.2.0

6
requirements_all.txt generated
View File

@@ -1216,7 +1216,7 @@ hole==0.9.0
holidays==0.84
# homeassistant.components.frontend
home-assistant-frontend==20260107.0
home-assistant-frontend==20260107.1
# homeassistant.components.conversation
home-assistant-intents==2026.1.6
@@ -1855,7 +1855,7 @@ pyElectra==1.2.4
pyEmby==1.10
# homeassistant.components.hikvision
pyHik==0.4.0
pyHik==0.3.4
# homeassistant.components.homee
pyHomee==1.3.8
@@ -2956,7 +2956,7 @@ surepy==0.9.0
swisshydrodata==0.1.0
# homeassistant.components.switchbot_cloud
switchbot-api==2.10.0
switchbot-api==2.9.0
# homeassistant.components.synology_srm
synology-srm==0.2.0

View File

@@ -1074,7 +1074,7 @@ hole==0.9.0
holidays==0.84
# homeassistant.components.frontend
home-assistant-frontend==20260107.0
home-assistant-frontend==20260107.1
# homeassistant.components.conversation
home-assistant-intents==2026.1.6
@@ -1589,7 +1589,7 @@ pyDuotecno==2024.10.1
pyElectra==1.2.4
# homeassistant.components.hikvision
pyHik==0.4.0
pyHik==0.3.4
# homeassistant.components.homee
pyHomee==1.3.8
@@ -2477,7 +2477,7 @@ subarulink==0.7.15
surepy==0.9.0
# homeassistant.components.switchbot_cloud
switchbot-api==2.10.0
switchbot-api==2.9.0
# homeassistant.components.system_bridge
systembridgeconnector==5.3.1

View File

@@ -1,52 +1,4 @@
# serializer version: 1
# name: test_buttons[button.test_thermostat_recalibrate_co2_sensor-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'button.test_thermostat_recalibrate_co2_sensor',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Recalibrate CO2 sensor',
'platform': 'airobot',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'recalibrate_co2',
'unique_id': 'T01A1B2C3_recalibrate_co2',
'unit_of_measurement': None,
})
# ---
# name: test_buttons[button.test_thermostat_recalibrate_co2_sensor-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Test Thermostat Recalibrate CO2 sensor',
}),
'context': <ANY>,
'entity_id': 'button.test_thermostat_recalibrate_co2_sensor',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_buttons[button.test_thermostat_restart-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@@ -25,7 +25,7 @@ def platforms() -> list[Platform]:
return [Platform.BUTTON]
@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration")
@pytest.mark.usefixtures("init_integration")
async def test_buttons(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
@@ -93,38 +93,3 @@ async def test_restart_button_connection_errors(
)
mock_airobot_client.reboot_thermostat.assert_called_once()
@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration")
async def test_recalibrate_co2_button(
hass: HomeAssistant,
mock_airobot_client: AsyncMock,
) -> None:
"""Test recalibrate CO2 sensor button."""
await hass.services.async_call(
BUTTON_DOMAIN,
SERVICE_PRESS,
{ATTR_ENTITY_ID: "button.test_thermostat_recalibrate_co2_sensor"},
blocking=True,
)
mock_airobot_client.recalibrate_co2_sensor.assert_called_once()
@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration")
async def test_recalibrate_co2_button_error(
hass: HomeAssistant,
mock_airobot_client: AsyncMock,
) -> None:
"""Test recalibrate CO2 sensor button error handling."""
mock_airobot_client.recalibrate_co2_sensor.side_effect = AirobotError("Test error")
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
BUTTON_DOMAIN,
SERVICE_PRESS,
{ATTR_ENTITY_ID: "button.test_thermostat_recalibrate_co2_sensor"},
blocking=True,
)
mock_airobot_client.recalibrate_co2_sensor.assert_called_once()

View File

@@ -2,24 +2,8 @@
import json
from typing import Any
from unittest.mock import patch
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture
async def setup_platform(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
"""Set up the NINA platform."""
with patch(
"pynina.baseApi.BaseAPI._makeRequest",
wraps=mocked_request_function,
):
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
from tests.common import load_fixture
def mocked_request_function(url: str) -> dict[str, Any]:

View File

@@ -1,257 +0,0 @@
# serializer version: 1
# name: test_sensors[binary_sensor.nina_warning_aach_1-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.nina_warning_aach_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.SAFETY: 'safety'>,
'original_icon': None,
'original_name': 'Warning: Aach 1',
'platform': 'nina',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '095760000000-1',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[binary_sensor.nina_warning_aach_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'affected_areas': 'Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere.',
'description': 'Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden.',
'device_class': 'safety',
'expires': '3021-11-22T05:19:00+01:00',
'friendly_name': 'NINA Warning: Aach 1',
'headline': 'Ausfall Notruf 112',
'id': 'mow.DE-NW-BN-SE030-20201014-30-000',
'recommended_actions': '',
'sender': 'Deutscher Wetterdienst',
'sent': '2021-10-11T05:20:00+01:00',
'severity': 'Minor',
'start': '2021-11-01T05:20:00+01:00',
'web': 'https://www.wettergefahren.de',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.nina_warning_aach_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_sensors[binary_sensor.nina_warning_aach_2-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.nina_warning_aach_2',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.SAFETY: 'safety'>,
'original_icon': None,
'original_name': 'Warning: Aach 2',
'platform': 'nina',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '095760000000-2',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[binary_sensor.nina_warning_aach_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'safety',
'friendly_name': 'NINA Warning: Aach 2',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.nina_warning_aach_2',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_sensors[binary_sensor.nina_warning_aach_3-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.nina_warning_aach_3',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.SAFETY: 'safety'>,
'original_icon': None,
'original_name': 'Warning: Aach 3',
'platform': 'nina',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '095760000000-3',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[binary_sensor.nina_warning_aach_3-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'safety',
'friendly_name': 'NINA Warning: Aach 3',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.nina_warning_aach_3',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_sensors[binary_sensor.nina_warning_aach_4-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.nina_warning_aach_4',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.SAFETY: 'safety'>,
'original_icon': None,
'original_name': 'Warning: Aach 4',
'platform': 'nina',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '095760000000-4',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[binary_sensor.nina_warning_aach_4-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'safety',
'friendly_name': 'NINA Warning: Aach 4',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.nina_warning_aach_4',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_sensors[binary_sensor.nina_warning_aach_5-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.nina_warning_aach_5',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.SAFETY: 'safety'>,
'original_icon': None,
'original_name': 'Warning: Aach 5',
'platform': 'nina',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '095760000000-5',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[binary_sensor.nina_warning_aach_5-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'safety',
'friendly_name': 'NINA Warning: Aach 5',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.nina_warning_aach_5',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---

View File

@@ -3,17 +3,40 @@
from __future__ import annotations
from typing import Any
from unittest.mock import patch
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.nina.const import ATTR_HEADLINE, DOMAIN
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
from homeassistant.components.nina.const import (
ATTR_AFFECTED_AREAS,
ATTR_DESCRIPTION,
ATTR_EXPIRES,
ATTR_HEADLINE,
ATTR_ID,
ATTR_RECOMMENDED_ACTIONS,
ATTR_SENDER,
ATTR_SENT,
ATTR_SEVERITY,
ATTR_START,
ATTR_WEB,
DOMAIN,
)
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import setup_platform
from . import mocked_request_function
from tests.common import MockConfigEntry, snapshot_platform
from tests.common import MockConfigEntry
ENTRY_DATA: dict[str, Any] = {
"slots": 5,
"regions": {"083350000000": "Aach, Stadt"},
"filters": {
"headline_filter": ".*corona.*",
"area_filter": ".*",
},
}
ENTRY_DATA_NO_CORONA: dict[str, Any] = {
"slots": 5,
@@ -24,7 +47,7 @@ ENTRY_DATA_NO_CORONA: dict[str, Any] = {
},
}
ENTRY_DATA_SPECIFIC_AREA: dict[str, Any] = {
ENTRY_DATA_NO_AREA: dict[str, Any] = {
"slots": 5,
"regions": {"083350000000": "Aach, Stadt"},
"filters": {
@@ -34,93 +57,321 @@ ENTRY_DATA_SPECIFIC_AREA: dict[str, Any] = {
}
async def test_sensors(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
) -> None:
async def test_sensors(hass: HomeAssistant, entity_registry: er.EntityRegistry) -> None:
"""Test the creation and values of the NINA sensors."""
await setup_platform(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
with patch(
"pynina.baseApi.BaseAPI._makeRequest",
wraps=mocked_request_function,
):
conf_entry: MockConfigEntry = MockConfigEntry(
domain=DOMAIN, title="NINA", data=ENTRY_DATA, version=1, minor_version=3
)
conf_entry.add_to_hass(hass)
await hass.config_entries.async_setup(conf_entry.entry_id)
await hass.async_block_till_done()
assert conf_entry.state is ConfigEntryState.LOADED
state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1")
entry_w1 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_1")
assert state_w1.state == STATE_ON
assert state_w1.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112"
assert (
state_w1.attributes.get(ATTR_DESCRIPTION)
== "Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden."
)
assert state_w1.attributes.get(ATTR_SENDER) == "Deutscher Wetterdienst"
assert state_w1.attributes.get(ATTR_SEVERITY) == "Minor"
assert state_w1.attributes.get(ATTR_RECOMMENDED_ACTIONS) == ""
assert state_w1.attributes.get(ATTR_WEB) == "https://www.wettergefahren.de"
assert (
state_w1.attributes.get(ATTR_AFFECTED_AREAS)
== "Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere."
)
assert state_w1.attributes.get(ATTR_ID) == "mow.DE-NW-BN-SE030-20201014-30-000"
assert state_w1.attributes.get(ATTR_SENT) == "2021-10-11T05:20:00+01:00"
assert state_w1.attributes.get(ATTR_START) == "2021-11-01T05:20:00+01:00"
assert state_w1.attributes.get(ATTR_EXPIRES) == "3021-11-22T05:19:00+01:00"
assert entry_w1.unique_id == "083350000000-1"
assert state_w1.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2")
entry_w2 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_2")
assert state_w2.state == STATE_OFF
assert state_w2.attributes.get(ATTR_HEADLINE) is None
assert state_w2.attributes.get(ATTR_DESCRIPTION) is None
assert state_w2.attributes.get(ATTR_SENDER) is None
assert state_w2.attributes.get(ATTR_SEVERITY) is None
assert state_w2.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
assert state_w2.attributes.get(ATTR_WEB) is None
assert state_w2.attributes.get(ATTR_AFFECTED_AREAS) is None
assert state_w2.attributes.get(ATTR_ID) is None
assert state_w2.attributes.get(ATTR_SENT) is None
assert state_w2.attributes.get(ATTR_START) is None
assert state_w2.attributes.get(ATTR_EXPIRES) is None
assert entry_w2.unique_id == "083350000000-2"
assert state_w2.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3")
entry_w3 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_3")
assert state_w3.state == STATE_OFF
assert state_w3.attributes.get(ATTR_HEADLINE) is None
assert state_w3.attributes.get(ATTR_DESCRIPTION) is None
assert state_w3.attributes.get(ATTR_SENDER) is None
assert state_w3.attributes.get(ATTR_SEVERITY) is None
assert state_w3.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
assert state_w3.attributes.get(ATTR_WEB) is None
assert state_w3.attributes.get(ATTR_AFFECTED_AREAS) is None
assert state_w3.attributes.get(ATTR_ID) is None
assert state_w3.attributes.get(ATTR_SENT) is None
assert state_w3.attributes.get(ATTR_START) is None
assert state_w3.attributes.get(ATTR_EXPIRES) is None
assert entry_w3.unique_id == "083350000000-3"
assert state_w3.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4")
entry_w4 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_4")
assert state_w4.state == STATE_OFF
assert state_w4.attributes.get(ATTR_HEADLINE) is None
assert state_w4.attributes.get(ATTR_DESCRIPTION) is None
assert state_w4.attributes.get(ATTR_SENDER) is None
assert state_w4.attributes.get(ATTR_SEVERITY) is None
assert state_w4.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
assert state_w4.attributes.get(ATTR_WEB) is None
assert state_w4.attributes.get(ATTR_AFFECTED_AREAS) is None
assert state_w4.attributes.get(ATTR_ID) is None
assert state_w4.attributes.get(ATTR_SENT) is None
assert state_w4.attributes.get(ATTR_START) is None
assert state_w4.attributes.get(ATTR_EXPIRES) is None
assert entry_w4.unique_id == "083350000000-4"
assert state_w4.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5")
entry_w5 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_5")
assert state_w5.state == STATE_OFF
assert state_w5.attributes.get(ATTR_HEADLINE) is None
assert state_w5.attributes.get(ATTR_DESCRIPTION) is None
assert state_w5.attributes.get(ATTR_SENDER) is None
assert state_w5.attributes.get(ATTR_SEVERITY) is None
assert state_w5.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
assert state_w5.attributes.get(ATTR_WEB) is None
assert state_w5.attributes.get(ATTR_AFFECTED_AREAS) is None
assert state_w5.attributes.get(ATTR_ID) is None
assert state_w5.attributes.get(ATTR_SENT) is None
assert state_w5.attributes.get(ATTR_START) is None
assert state_w5.attributes.get(ATTR_EXPIRES) is None
assert entry_w5.unique_id == "083350000000-5"
assert state_w5.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
async def test_sensors_without_corona_filter(
hass: HomeAssistant, entity_registry: er.EntityRegistry, snapshot: SnapshotAssertion
hass: HomeAssistant, entity_registry: er.EntityRegistry
) -> None:
"""Test the creation and values of the NINA sensors without the corona filter."""
conf_entry: MockConfigEntry = MockConfigEntry(
domain=DOMAIN,
title="NINA",
data=ENTRY_DATA_NO_CORONA,
version=1,
minor_version=3,
)
conf_entry.add_to_hass(hass)
with patch(
"pynina.baseApi.BaseAPI._makeRequest",
wraps=mocked_request_function,
):
conf_entry: MockConfigEntry = MockConfigEntry(
domain=DOMAIN,
title="NINA",
data=ENTRY_DATA_NO_CORONA,
version=1,
minor_version=3,
)
conf_entry.add_to_hass(hass)
await setup_platform(hass, conf_entry)
await hass.config_entries.async_setup(conf_entry.entry_id)
await hass.async_block_till_done()
state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1")
assert conf_entry.state is ConfigEntryState.LOADED
assert state_w1.state == STATE_ON
assert (
state_w1.attributes.get(ATTR_HEADLINE)
== "Corona-Verordnung des Landes: Warnstufe durch Landesgesundheitsamt ausgerufen"
)
state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1")
entry_w1 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_1")
state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2")
assert state_w1.state == STATE_ON
assert (
state_w1.attributes.get(ATTR_HEADLINE)
== "Corona-Verordnung des Landes: Warnstufe durch Landesgesundheitsamt ausgerufen"
)
assert (
state_w1.attributes.get(ATTR_DESCRIPTION)
== "Die Zahl der mit dem Corona-Virus infizierten Menschen steigt gegenwärtig stark an. Es wächst daher die Gefahr einer weiteren Verbreitung der Infektion und - je nach Einzelfall - auch von schweren Erkrankungen."
)
assert state_w1.attributes.get(ATTR_SENDER) == ""
assert state_w1.attributes.get(ATTR_SEVERITY) == "Minor"
assert (
state_w1.attributes.get(ATTR_RECOMMENDED_ACTIONS)
== "Waschen sich regelmäßig und gründlich die Hände."
)
assert state_w1.attributes.get(ATTR_WEB) == ""
assert (
state_w1.attributes.get(ATTR_AFFECTED_AREAS)
== "Bundesland: Freie Hansestadt Bremen, Land Berlin, Land Hessen, Land Nordrhein-Westfalen, Land Brandenburg, Freistaat Bayern, Land Mecklenburg-Vorpommern, Land Rheinland-Pfalz, Freistaat Sachsen, Land Schleswig-Holstein, Freie und Hansestadt Hamburg, Freistaat Thüringen, Land Niedersachsen, Land Saarland, Land Sachsen-Anhalt, Land Baden-Württemberg"
)
assert state_w1.attributes.get(ATTR_ID) == "mow.DE-BW-S-SE018-20211102-18-001"
assert state_w1.attributes.get(ATTR_SENT) == "2021-11-02T20:07:16+01:00"
assert state_w1.attributes.get(ATTR_START) == ""
assert state_w1.attributes.get(ATTR_EXPIRES) == ""
assert state_w2.state == STATE_ON
assert state_w2.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112"
assert entry_w1.unique_id == "083350000000-1"
assert state_w1.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3")
state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2")
entry_w2 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_2")
assert state_w3.state == STATE_OFF
assert state_w2.state == STATE_ON
assert state_w2.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112"
assert (
state_w2.attributes.get(ATTR_DESCRIPTION)
== "Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden."
)
assert (
state_w2.attributes.get(ATTR_AFFECTED_AREAS)
== "Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere."
)
assert state_w2.attributes.get(ATTR_SENDER) == "Deutscher Wetterdienst"
assert state_w2.attributes.get(ATTR_SEVERITY) == "Minor"
assert state_w2.attributes.get(ATTR_RECOMMENDED_ACTIONS) == ""
assert state_w2.attributes.get(ATTR_WEB) == "https://www.wettergefahren.de"
assert state_w2.attributes.get(ATTR_ID) == "mow.DE-NW-BN-SE030-20201014-30-000"
assert state_w2.attributes.get(ATTR_SENT) == "2021-10-11T05:20:00+01:00"
assert state_w2.attributes.get(ATTR_START) == "2021-11-01T05:20:00+01:00"
assert state_w2.attributes.get(ATTR_EXPIRES) == "3021-11-22T05:19:00+01:00"
state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4")
assert entry_w2.unique_id == "083350000000-2"
assert state_w2.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
assert state_w4.state == STATE_OFF
state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3")
entry_w3 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_3")
state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5")
assert state_w3.state == STATE_OFF
assert state_w3.attributes.get(ATTR_HEADLINE) is None
assert state_w3.attributes.get(ATTR_DESCRIPTION) is None
assert state_w3.attributes.get(ATTR_SENDER) is None
assert state_w3.attributes.get(ATTR_SEVERITY) is None
assert state_w3.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
assert state_w3.attributes.get(ATTR_WEB) is None
assert state_w3.attributes.get(ATTR_AFFECTED_AREAS) is None
assert state_w3.attributes.get(ATTR_ID) is None
assert state_w3.attributes.get(ATTR_SENT) is None
assert state_w3.attributes.get(ATTR_START) is None
assert state_w3.attributes.get(ATTR_EXPIRES) is None
assert state_w5.state == STATE_OFF
assert entry_w3.unique_id == "083350000000-3"
assert state_w3.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4")
entry_w4 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_4")
assert state_w4.state == STATE_OFF
assert state_w4.attributes.get(ATTR_HEADLINE) is None
assert state_w4.attributes.get(ATTR_DESCRIPTION) is None
assert state_w4.attributes.get(ATTR_SENDER) is None
assert state_w4.attributes.get(ATTR_SEVERITY) is None
assert state_w4.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
assert state_w4.attributes.get(ATTR_WEB) is None
assert state_w4.attributes.get(ATTR_AFFECTED_AREAS) is None
assert state_w4.attributes.get(ATTR_ID) is None
assert state_w4.attributes.get(ATTR_SENT) is None
assert state_w4.attributes.get(ATTR_START) is None
assert state_w4.attributes.get(ATTR_EXPIRES) is None
assert entry_w4.unique_id == "083350000000-4"
assert state_w4.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5")
entry_w5 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_5")
assert state_w5.state == STATE_OFF
assert state_w5.attributes.get(ATTR_HEADLINE) is None
assert state_w5.attributes.get(ATTR_DESCRIPTION) is None
assert state_w5.attributes.get(ATTR_SENDER) is None
assert state_w5.attributes.get(ATTR_SEVERITY) is None
assert state_w5.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
assert state_w5.attributes.get(ATTR_WEB) is None
assert state_w5.attributes.get(ATTR_AFFECTED_AREAS) is None
assert state_w5.attributes.get(ATTR_ID) is None
assert state_w5.attributes.get(ATTR_SENT) is None
assert state_w5.attributes.get(ATTR_START) is None
assert state_w5.attributes.get(ATTR_EXPIRES) is None
assert entry_w5.unique_id == "083350000000-5"
assert state_w5.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
async def test_sensors_with_area_filter(
hass: HomeAssistant, entity_registry: er.EntityRegistry, snapshot: SnapshotAssertion
hass: HomeAssistant, entity_registry: er.EntityRegistry
) -> None:
"""Test the creation and values of the NINA sensors with a restrictive area filter."""
"""Test the creation and values of the NINA sensors with an area filter."""
conf_entry: MockConfigEntry = MockConfigEntry(
domain=DOMAIN,
title="NINA",
data=ENTRY_DATA_SPECIFIC_AREA,
version=1,
minor_version=3,
)
conf_entry.add_to_hass(hass)
with patch(
"pynina.baseApi.BaseAPI._makeRequest",
wraps=mocked_request_function,
):
conf_entry: MockConfigEntry = MockConfigEntry(
domain=DOMAIN,
title="NINA",
data=ENTRY_DATA_NO_AREA,
version=1,
minor_version=3,
)
conf_entry.add_to_hass(hass)
await setup_platform(hass, conf_entry)
await hass.config_entries.async_setup(conf_entry.entry_id)
await hass.async_block_till_done()
state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1")
assert conf_entry.state is ConfigEntryState.LOADED
assert state_w1.state == STATE_ON
assert state_w1.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112"
state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1")
entry_w1 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_1")
state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2")
assert state_w1.state == STATE_ON
assert state_w2.state == STATE_OFF
assert entry_w1.unique_id == "083350000000-1"
assert state_w1.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3")
state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2")
entry_w2 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_2")
assert state_w3.state == STATE_OFF
assert state_w2.state == STATE_OFF
state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4")
assert entry_w2.unique_id == "083350000000-2"
assert state_w2.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
assert state_w4.state == STATE_OFF
state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3")
entry_w3 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_3")
state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5")
assert state_w3.state == STATE_OFF
assert state_w5.state == STATE_OFF
assert entry_w3.unique_id == "083350000000-3"
assert state_w3.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4")
entry_w4 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_4")
assert state_w4.state == STATE_OFF
assert entry_w4.unique_id == "083350000000-4"
assert state_w4.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5")
entry_w5 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_5")
assert state_w5.state == STATE_OFF
assert entry_w5.unique_id == "083350000000-5"
assert state_w5.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY

View File

@@ -3,6 +3,7 @@
from __future__ import annotations
from copy import deepcopy
import json
from typing import Any
from unittest.mock import AsyncMock, patch
@@ -27,10 +28,14 @@ from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers import entity_registry as er
from . import mocked_request_function, setup_platform
from . import mocked_request_function
from .const import DUMMY_CONFIG_ENTRY, DUMMY_USER_INPUT
from tests.common import MockConfigEntry
from tests.common import MockConfigEntry, load_fixture
DUMMY_RESPONSE_REGIONS: dict[str, Any] = json.loads(
load_fixture("sample_regions.json", "nina")
)
def assert_dummy_entry_created(result: dict[str, Any]) -> None:
@@ -136,15 +141,15 @@ async def test_options_flow_init(
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry
) -> None:
"""Test config flow options."""
await setup_platform(hass, mock_config_entry)
with (
patch(
"pynina.baseApi.BaseAPI._makeRequest",
wraps=mocked_request_function,
),
):
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
result = await hass.config_entries.options.async_init(
mock_config_entry.entry_id
)
@@ -190,15 +195,15 @@ async def test_options_flow_with_no_selection(
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry
) -> None:
"""Test config flow options with no selection."""
await setup_platform(hass, mock_config_entry)
with (
patch(
"pynina.baseApi.BaseAPI._makeRequest",
wraps=mocked_request_function,
),
):
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
result = await hass.config_entries.options.async_init(
mock_config_entry.entry_id
)
@@ -259,13 +264,13 @@ async def test_options_flow_connection_error(
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry
) -> None:
"""Test config flow options but no connection."""
await setup_platform(hass, mock_config_entry)
with patch(
"pynina.baseApi.BaseAPI._makeRequest",
side_effect=ApiError("Could not connect to Api"),
):
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
result = await hass.config_entries.options.async_init(
mock_config_entry.entry_id
)
@@ -278,15 +283,15 @@ async def test_options_flow_unexpected_exception(
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry
) -> None:
"""Test config flow options but with an unexpected exception."""
await setup_platform(hass, mock_config_entry)
with (
patch(
"pynina.baseApi.BaseAPI._makeRequest",
side_effect=Exception("DUMMY"),
),
):
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
result = await hass.config_entries.options.async_init(
mock_config_entry.entry_id
)
@@ -308,14 +313,15 @@ async def test_options_flow_entity_removal(
)
config_entry.add_to_hass(hass)
await setup_platform(hass, config_entry)
with (
patch(
"pynina.baseApi.BaseAPI._makeRequest",
wraps=mocked_request_function,
),
):
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
result = await hass.config_entries.options.async_init(config_entry.entry_id)
result = await hass.config_entries.options.async_configure(

View File

@@ -383,13 +383,6 @@ async def test_smoke_co_notification_sensors(
assert entity_entry
assert entity_entry.entity_category == EntityCategory.DIAGNOSTIC
# Test that no idle states are created as entities
entity_id = "binary_sensor.zcombo_g_smoke_co_alarm_idle"
state = hass.states.get(entity_id)
assert state is None
entity_entry = entity_registry.async_get(entity_id)
assert entity_entry is None
# Test state updates for smoke alarm
event = Event(
type="value updated",