1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-25 05:26:47 +00:00

Add Arve integration (#113156)

* add Arve integration

* Update homeassistant/components/arve/config_flow.py

Co-authored-by: Josef Zweck <24647999+zweckj@users.noreply.github.com>

* Various fixes, changed scan interval to one minute

* coordinator implementation

* Code cleanup

* Moved device info to the entity.py, ArveDeviceEntityDescription to sensor.py

* delete refresh before adding entities

Co-authored-by: Josef Zweck <24647999+zweckj@users.noreply.github.com>

* Update tests/components/arve/test_config_flow.py

Co-authored-by: Josef Zweck <24647999+zweckj@users.noreply.github.com>

* Update tests/components/arve/conftest.py

Co-authored-by: Josef Zweck <24647999+zweckj@users.noreply.github.com>

* Changed value_fn in sensors.py, added typing to description

* Code cleanups, platfrom test implementation

* New code cleanups, first two working tests

* Created platform test, generated snapshots

* Reworked integration to get all of the customer devices

* new fixes

* Added customer id, small cleanups

* Logic of setting unique_id to the config flow

* Added test of abortion on duplicate config_flow id

* Added "available" and "device" properties fro ArveDeviceEntity

* small _attr_unique_id fix

* Added new test, improved mocking, various fixes

* Various cleanups and fixes

* microfix

* Update homeassistant/components/arve/strings.json

* ruff fix

---------

Co-authored-by: Josef Zweck <24647999+zweckj@users.noreply.github.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
Illia
2024-04-08 17:24:32 +02:00
committed by GitHub
parent 376aafc83e
commit cbaef096fa
19 changed files with 1348 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
"""Tests for the Arve integration."""
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_CLIENT_SECRET
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
USER_INPUT = {
CONF_ACCESS_TOKEN: "test-access-token",
CONF_CLIENT_SECRET: "test-customer-token",
}
async def async_init_integration(
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Set up the Arve integration for testing."""
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()

View File

@@ -0,0 +1,56 @@
"""Common fixtures for the Arve tests."""
from collections.abc import Generator
from unittest.mock import AsyncMock, MagicMock, patch
from asyncarve import ArveCustomer, ArveDevices, ArveSensPro, ArveSensProData
import pytest
from homeassistant.components.arve.const import DOMAIN
from homeassistant.core import HomeAssistant
from . import USER_INPUT
from tests.common import MockConfigEntry
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock, None, None]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.arve.async_setup_entry", return_value=True
) as mock_setup_entry:
yield mock_setup_entry
@pytest.fixture
def mock_config_entry(hass: HomeAssistant, mock_arve: MagicMock) -> MockConfigEntry:
"""Return the default mocked config entry."""
return MockConfigEntry(
title="Arve", domain=DOMAIN, data=USER_INPUT, unique_id=mock_arve.customer_id
)
@pytest.fixture
def mock_arve():
"""Return a mocked Arve client."""
with (
patch(
"homeassistant.components.arve.coordinator.Arve", autospec=True
) as arve_mock,
patch("homeassistant.components.arve.config_flow.Arve", new=arve_mock),
):
arve = arve_mock.return_value
arve.customer_id = 12345
arve.get_customer_id.return_value = ArveCustomer(12345)
arve.get_devices.return_value = ArveDevices(["test-serial-number"])
arve.get_sensor_info.return_value = ArveSensPro("Test Sensor", "1.0", "prov1")
arve.device_sensor_data.return_value = ArveSensProData(
14, 595.75, 28.71, 0.16, 0.19, 26.02, 7
)
yield arve

View File

@@ -0,0 +1,773 @@
# serializer version: 1
# name: test_sensors[entry_air_quality_index]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_air_quality_index',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.AQI: 'aqi'>,
'original_icon': None,
'original_name': 'Air quality index',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_AQI',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[entry_carbon_dioxide]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_carbon_dioxide',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.CO2: 'carbon_dioxide'>,
'original_icon': None,
'original_name': 'Carbon dioxide',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_CO2',
'unit_of_measurement': 'ppm',
})
# ---
# name: test_sensors[entry_humidity]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_humidity',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.HUMIDITY: 'humidity'>,
'original_icon': None,
'original_name': 'Humidity',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_Humidity',
'unit_of_measurement': '%',
})
# ---
# name: test_sensors[entry_pm10]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_pm10',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.PM10: 'pm10'>,
'original_icon': None,
'original_name': 'PM10',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_PM10',
'unit_of_measurement': 'µg/m³',
})
# ---
# name: test_sensors[entry_pm2_5]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_pm2_5',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.PM25: 'pm25'>,
'original_icon': None,
'original_name': 'PM2.5',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_PM25',
'unit_of_measurement': 'µg/m³',
})
# ---
# name: test_sensors[entry_temperature]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Temperature',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_Temperature',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_sensors[entry_test-serial-number_air_quality_index]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_air_quality_index',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.AQI: 'aqi'>,
'original_icon': None,
'original_name': 'Air quality index',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_AQI',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[entry_test-serial-number_carbon_dioxide]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_carbon_dioxide',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.CO2: 'carbon_dioxide'>,
'original_icon': None,
'original_name': 'Carbon dioxide',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_CO2',
'unit_of_measurement': 'ppm',
})
# ---
# name: test_sensors[entry_test-serial-number_humidity]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_humidity',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.HUMIDITY: 'humidity'>,
'original_icon': None,
'original_name': 'Humidity',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_Humidity',
'unit_of_measurement': '%',
})
# ---
# name: test_sensors[entry_test-serial-number_none]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.my_arve_none',
'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': 'TVOC',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'tvoc',
'unique_id': 'test-serial-number_tvoc',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[entry_test-serial-number_pm10]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_pm10',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.PM10: 'pm10'>,
'original_icon': None,
'original_name': 'PM10',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_PM10',
'unit_of_measurement': 'µg/m³',
})
# ---
# name: test_sensors[entry_test-serial-number_pm2_5]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_pm2_5',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.PM25: 'pm25'>,
'original_icon': None,
'original_name': 'PM2.5',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_PM25',
'unit_of_measurement': 'µg/m³',
})
# ---
# name: test_sensors[entry_test-serial-number_temperature]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Temperature',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'test-serial-number_Temperature',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_sensors[entry_test-serial-number_total_volatile_organic_compounds]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_total_volatile_organic_compounds',
'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': 'Total volatile organic compounds',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'tvoc',
'unique_id': 'test-serial-number_TVOC',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[entry_test-serial-number_tvoc]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.my_arve_tvoc',
'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': 'TVOC',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'tvoc',
'unique_id': 'test-serial-number_tvoc',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[entry_total_volatile_organic_compounds]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.test_sensor_total_volatile_organic_compounds',
'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': 'Total volatile organic compounds',
'platform': 'arve',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'tvoc',
'unique_id': 'test-serial-number_TVOC',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[my_arve_air_quality_index]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'aqi',
'friendly_name': 'My Arve AQI',
}),
'context': <ANY>,
'entity_id': 'sensor.my_arve_air_quality_index',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': "<AsyncMock name='Arve().device_sensor_data().aqi' id='4673889600'>",
})
# ---
# name: test_sensors[my_arve_carbon_dioxide]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'carbon_dioxide',
'friendly_name': 'My Arve CO2',
'unit_of_measurement': 'ppm',
}),
'context': <ANY>,
'entity_id': 'sensor.my_arve_carbon_dioxide',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': "<AsyncMock name='Arve().device_sensor_data().co2' id='4683517632'>",
})
# ---
# name: test_sensors[my_arve_humidity]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'humidity',
'friendly_name': 'My Arve Humidity',
'unit_of_measurement': '%',
}),
'context': <ANY>,
'entity_id': 'sensor.my_arve_humidity',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': "<AsyncMock name='Arve().device_sensor_data().humidity' id='4674090384'>",
})
# ---
# name: test_sensors[my_arve_none]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'My Arve TVOC',
}),
'context': <ANY>,
'entity_id': 'sensor.my_arve_none',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': "<AsyncMock name='Arve().device_sensor_data().tvoc' id='4430967152'>",
})
# ---
# name: test_sensors[my_arve_pm10]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'pm10',
'friendly_name': 'My Arve PM10',
'unit_of_measurement': 'µg/m³',
}),
'context': <ANY>,
'entity_id': 'sensor.my_arve_pm10',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': "<AsyncMock name='Arve().device_sensor_data().pm10' id='4683800288'>",
})
# ---
# name: test_sensors[my_arve_pm2_5]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'pm25',
'friendly_name': 'My Arve PM25',
'unit_of_measurement': 'µg/m³',
}),
'context': <ANY>,
'entity_id': 'sensor.my_arve_pm2_5',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': "<AsyncMock name='Arve().device_sensor_data().pm25' id='4683861792'>",
})
# ---
# name: test_sensors[my_arve_temperature]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'My Arve Temperature',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.my_arve_temperature',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': "<AsyncMock name='Arve().device_sensor_data().temperature' id='4683873744'>",
})
# ---
# name: test_sensors[my_arve_tvoc]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'My Arve TVOC',
}),
'context': <ANY>,
'entity_id': 'sensor.my_arve_tvoc',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': "<AsyncMock name='Arve().device_sensor_data().tvoc' id='4683902432'>",
})
# ---
# name: test_sensors[test_sensor_air_quality_index]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'aqi',
'friendly_name': 'Test Sensor Air quality index',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_sensor_air_quality_index',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '14',
})
# ---
# name: test_sensors[test_sensor_carbon_dioxide]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'carbon_dioxide',
'friendly_name': 'Test Sensor Carbon dioxide',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': 'ppm',
}),
'context': <ANY>,
'entity_id': 'sensor.test_sensor_carbon_dioxide',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '595.75',
})
# ---
# name: test_sensors[test_sensor_humidity]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'humidity',
'friendly_name': 'Test Sensor Humidity',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'context': <ANY>,
'entity_id': 'sensor.test_sensor_humidity',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '28.71',
})
# ---
# name: test_sensors[test_sensor_pm10]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'pm10',
'friendly_name': 'Test Sensor PM10',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': 'µg/m³',
}),
'context': <ANY>,
'entity_id': 'sensor.test_sensor_pm10',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.16',
})
# ---
# name: test_sensors[test_sensor_pm2_5]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'pm25',
'friendly_name': 'Test Sensor PM2.5',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': 'µg/m³',
}),
'context': <ANY>,
'entity_id': 'sensor.test_sensor_pm2_5',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0.19',
})
# ---
# name: test_sensors[test_sensor_temperature]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Test Sensor Temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_sensor_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '26.02',
})
# ---
# name: test_sensors[test_sensor_total_volatile_organic_compounds]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Test Sensor Total volatile organic compounds',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'context': <ANY>,
'entity_id': 'sensor.test_sensor_total_volatile_organic_compounds',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '7',
})
# ---

View File

@@ -0,0 +1,79 @@
"""Test the Arve config flow."""
from unittest.mock import AsyncMock
from homeassistant.components.arve.config_flow import ArveConnectionError
from homeassistant.components.arve.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_CLIENT_SECRET
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from . import USER_INPUT, async_init_integration
from tests.common import MockConfigEntry
async def test_correct_flow(
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_arve: AsyncMock
) -> None:
"""Test the whole flow."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {}
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], USER_INPUT
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["data"] == USER_INPUT
assert len(mock_setup_entry.mock_calls) == 1
assert result2["result"].unique_id == 12345
async def test_form_cannot_connect(
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_arve: AsyncMock
) -> None:
"""Test we handle cannot connect error."""
mock_arve.get_customer_id.side_effect = ArveConnectionError
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
USER_INPUT,
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {"base": "cannot_connect"}
async def test_form_abort_already_configured(
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test form aborts if already configured."""
await async_init_integration(hass, mock_config_entry)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {}
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_ACCESS_TOKEN: "test-access-token",
CONF_CLIENT_SECRET: "test-customer-token",
},
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.ABORT
assert result2["reason"] == "already_configured"

View File

@@ -0,0 +1,43 @@
"""Test for Arve sensors."""
from unittest.mock import MagicMock
from syrupy import SnapshotAssertion
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import async_init_integration
from tests.common import MockConfigEntry
SENSORS = (
"air_quality_index",
"carbon_dioxide",
"humidity",
"pm10",
"pm2_5",
"temperature",
"total_volatile_organic_compounds",
)
async def test_sensors(
hass: HomeAssistant,
mock_arve: MagicMock,
entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
) -> None:
"""Test the Arve sensors."""
await async_init_integration(hass, mock_config_entry)
for sensor in SENSORS:
state = hass.states.get(f"sensor.test_sensor_{sensor}")
assert state
assert state == snapshot(name=f"test_sensor_{sensor}")
entry = entity_registry.async_get(state.entity_id)
assert entry
assert entry.device_id
assert entry == snapshot(name=f"entry_{sensor}")