Add select entities to AirGradient (#117136)

This commit is contained in:
Joost Lekkerkerker
2024-05-29 20:12:51 +02:00
committed by GitHub
parent 6382cb9134
commit c80718628e
12 changed files with 549 additions and 33 deletions
+6 -2
View File
@@ -3,7 +3,7 @@
from collections.abc import Generator
from unittest.mock import patch
from airgradient import Measures
from airgradient import Config, Measures
import pytest
from homeassistant.components.airgradient.const import DOMAIN
@@ -28,7 +28,7 @@ def mock_airgradient_client() -> Generator[AsyncMock, None, None]:
"""Mock an AirGradient client."""
with (
patch(
"homeassistant.components.airgradient.coordinator.AirGradientClient",
"homeassistant.components.airgradient.AirGradientClient",
autospec=True,
) as mock_client,
patch(
@@ -37,9 +37,13 @@ def mock_airgradient_client() -> Generator[AsyncMock, None, None]:
),
):
client = mock_client.return_value
client.host = "10.0.0.131"
client.get_current_measures.return_value = Measures.from_json(
load_fixture("current_measures.json", DOMAIN)
)
client.get_config.return_value = Config.from_json(
load_fixture("get_config.json", DOMAIN)
)
yield client
@@ -0,0 +1,24 @@
{
"wifi": -64,
"serialno": "84fce60bec38",
"channels": {
"1": {
"pm01": 3,
"pm02": 5,
"pm10": 5,
"pm003Count": 753,
"atmp": 18.8,
"rhum": 68,
"atmpCompensated": 17.09,
"rhumCompensated": 92
}
},
"tvocIndex": 49,
"tvocRaw": 30802,
"noxIndex": 1,
"noxRaw": 16359,
"bootCount": 1,
"ledMode": "co2",
"firmware": "3.1.1",
"model": "O-1PPT"
}
@@ -0,0 +1,13 @@
{
"country": "DE",
"pmStandard": "ugm3",
"ledBarMode": "co2",
"displayMode": "on",
"abcDays": 8,
"tvocLearningOffset": 12,
"noxLearningOffset": 12,
"mqttBrokerUrl": "",
"temperatureUnit": "c",
"configurationControl": "both",
"postDataToAirGradient": true
}
@@ -0,0 +1,170 @@
# serializer version: 1
# name: test_all_entities[select.airgradient_configuration_source-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'cloud',
'local',
'both',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'select',
'entity_category': None,
'entity_id': 'select.airgradient_configuration_source',
'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': 'Configuration source',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'configuration_control',
'unique_id': '84fce612f5b8-configuration_control',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[select.airgradient_configuration_source-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Airgradient Configuration source',
'options': list([
'cloud',
'local',
'both',
]),
}),
'context': <ANY>,
'entity_id': 'select.airgradient_configuration_source',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'both',
})
# ---
# name: test_all_entities[select.airgradient_display_temperature_unit-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'c',
'f',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'select',
'entity_category': None,
'entity_id': 'select.airgradient_display_temperature_unit',
'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': 'Display temperature unit',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'display_temperature_unit',
'unique_id': '84fce612f5b8-display_temperature_unit',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[select.airgradient_display_temperature_unit-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Airgradient Display temperature unit',
'options': list([
'c',
'f',
]),
}),
'context': <ANY>,
'entity_id': 'select.airgradient_display_temperature_unit',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'c',
})
# ---
# name: test_all_entities_outdoor[select.airgradient_configuration_source-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'cloud',
'local',
'both',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'select',
'entity_category': None,
'entity_id': 'select.airgradient_configuration_source',
'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': 'Configuration source',
'platform': 'airgradient',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'configuration_control',
'unique_id': '84fce612f5b8-configuration_control',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities_outdoor[select.airgradient_configuration_source-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Airgradient Configuration source',
'options': list([
'cloud',
'local',
'both',
]),
}),
'context': <ANY>,
'entity_id': 'select.airgradient_configuration_source',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'both',
})
# ---
+115
View File
@@ -0,0 +1,115 @@
"""Tests for the AirGradient select platform."""
from unittest.mock import AsyncMock, patch
from airgradient import ConfigurationControl, Measures
import pytest
from syrupy import SnapshotAssertion
from homeassistant.components.airgradient import DOMAIN
from homeassistant.components.select import (
DOMAIN as SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
)
from homeassistant.const import ATTR_ENTITY_ID, ATTR_OPTION, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import entity_registry as er
from . import setup_integration
from tests.common import MockConfigEntry, load_fixture, snapshot_platform
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_all_entities(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_airgradient_client: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test all entities."""
with patch("homeassistant.components.airgradient.PLATFORMS", [Platform.SELECT]):
await setup_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_all_entities_outdoor(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_airgradient_client: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test all entities."""
mock_airgradient_client.get_current_measures.return_value = Measures.from_json(
load_fixture("current_measures_outdoor.json", DOMAIN)
)
with patch("homeassistant.components.airgradient.PLATFORMS", [Platform.SELECT]):
await setup_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
async def test_setting_value(
hass: HomeAssistant,
mock_airgradient_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test setting value."""
await setup_integration(hass, mock_config_entry)
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: "select.airgradient_configuration_source",
ATTR_OPTION: "local",
},
blocking=True,
)
mock_airgradient_client.set_configuration_control.assert_called_once_with("local")
assert mock_airgradient_client.get_config.call_count == 2
async def test_setting_protected_value(
hass: HomeAssistant,
mock_airgradient_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test setting protected value."""
await setup_integration(hass, mock_config_entry)
mock_airgradient_client.get_config.return_value.configuration_control = (
ConfigurationControl.CLOUD
)
with pytest.raises(ServiceValidationError):
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: "select.airgradient_display_temperature_unit",
ATTR_OPTION: "c",
},
blocking=True,
)
mock_airgradient_client.set_temperature_unit.assert_not_called()
mock_airgradient_client.get_config.return_value.configuration_control = (
ConfigurationControl.LOCAL
)
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: "select.airgradient_display_temperature_unit",
ATTR_OPTION: "c",
},
blocking=True,
)
mock_airgradient_client.set_temperature_unit.assert_called_once_with("c")
+6 -4
View File
@@ -1,7 +1,7 @@
"""Tests for the AirGradient sensor platform."""
from datetime import timedelta
from unittest.mock import AsyncMock
from unittest.mock import AsyncMock, patch
from airgradient import AirGradientError, Measures
from freezegun.api import FrozenDateTimeFactory
@@ -9,7 +9,7 @@ import pytest
from syrupy import SnapshotAssertion
from homeassistant.components.airgradient import DOMAIN
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.const import STATE_UNAVAILABLE, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
@@ -32,7 +32,8 @@ async def test_all_entities(
entity_registry: er.EntityRegistry,
) -> None:
"""Test all entities."""
await setup_integration(hass, mock_config_entry)
with patch("homeassistant.components.airgradient.PLATFORMS", [Platform.SENSOR]):
await setup_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
@@ -47,7 +48,8 @@ async def test_create_entities(
mock_airgradient_client.get_current_measures.return_value = Measures.from_json(
load_fixture("measures_after_boot.json", DOMAIN)
)
await setup_integration(hass, mock_config_entry)
with patch("homeassistant.components.airgradient.PLATFORMS", [Platform.SENSOR]):
await setup_integration(hass, mock_config_entry)
assert len(hass.states.async_all()) == 0
mock_airgradient_client.get_current_measures.return_value = Measures.from_json(