mirror of
https://github.com/home-assistant/core.git
synced 2025-09-11 07:41:35 +02:00
ruuvitag_ble: add new sensors (#150435)
Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
@@ -4,7 +4,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from sensor_state_data import (
|
from sensor_state_data import (
|
||||||
DeviceKey,
|
DeviceKey,
|
||||||
SensorDescription,
|
|
||||||
SensorDeviceClass as SSDSensorDeviceClass,
|
SensorDeviceClass as SSDSensorDeviceClass,
|
||||||
SensorUpdate,
|
SensorUpdate,
|
||||||
Units,
|
Units,
|
||||||
@@ -32,53 +31,108 @@ from homeassistant.const import (
|
|||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import EntityDescription
|
||||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||||
from homeassistant.helpers.sensor import sensor_device_info_to_hass_device_info
|
from homeassistant.helpers.sensor import sensor_device_info_to_hass_device_info
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
|
||||||
SENSOR_DESCRIPTIONS = {
|
SENSOR_DESCRIPTIONS = {
|
||||||
(SSDSensorDeviceClass.TEMPERATURE, Units.TEMP_CELSIUS): SensorEntityDescription(
|
"temperature": SensorEntityDescription(
|
||||||
key=f"{SSDSensorDeviceClass.TEMPERATURE}_{Units.TEMP_CELSIUS}",
|
key=f"{SSDSensorDeviceClass.TEMPERATURE}_{Units.TEMP_CELSIUS}",
|
||||||
device_class=SensorDeviceClass.TEMPERATURE,
|
device_class=SensorDeviceClass.TEMPERATURE,
|
||||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
(SSDSensorDeviceClass.HUMIDITY, Units.PERCENTAGE): SensorEntityDescription(
|
"humidity": SensorEntityDescription(
|
||||||
key=f"{SSDSensorDeviceClass.HUMIDITY}_{Units.PERCENTAGE}",
|
key=f"{SSDSensorDeviceClass.HUMIDITY}_{Units.PERCENTAGE}",
|
||||||
device_class=SensorDeviceClass.HUMIDITY,
|
device_class=SensorDeviceClass.HUMIDITY,
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
(SSDSensorDeviceClass.PRESSURE, Units.PRESSURE_HPA): SensorEntityDescription(
|
"pressure": SensorEntityDescription(
|
||||||
key=f"{SSDSensorDeviceClass.PRESSURE}_{Units.PRESSURE_HPA}",
|
key=f"{SSDSensorDeviceClass.PRESSURE}_{Units.PRESSURE_HPA}",
|
||||||
device_class=SensorDeviceClass.PRESSURE,
|
device_class=SensorDeviceClass.PRESSURE,
|
||||||
native_unit_of_measurement=UnitOfPressure.HPA,
|
native_unit_of_measurement=UnitOfPressure.HPA,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
(
|
"voltage": SensorEntityDescription(
|
||||||
SSDSensorDeviceClass.VOLTAGE,
|
|
||||||
Units.ELECTRIC_POTENTIAL_MILLIVOLT,
|
|
||||||
): SensorEntityDescription(
|
|
||||||
key=f"{SSDSensorDeviceClass.VOLTAGE}_{Units.ELECTRIC_POTENTIAL_MILLIVOLT}",
|
key=f"{SSDSensorDeviceClass.VOLTAGE}_{Units.ELECTRIC_POTENTIAL_MILLIVOLT}",
|
||||||
native_unit_of_measurement=UnitOfElectricPotential.MILLIVOLT,
|
native_unit_of_measurement=UnitOfElectricPotential.MILLIVOLT,
|
||||||
|
device_class=SensorDeviceClass.VOLTAGE,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
(
|
"signal_strength": SensorEntityDescription(
|
||||||
SSDSensorDeviceClass.SIGNAL_STRENGTH,
|
|
||||||
Units.SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
|
||||||
): SensorEntityDescription(
|
|
||||||
key=f"{SSDSensorDeviceClass.SIGNAL_STRENGTH}_{Units.SIGNAL_STRENGTH_DECIBELS_MILLIWATT}",
|
key=f"{SSDSensorDeviceClass.SIGNAL_STRENGTH}_{Units.SIGNAL_STRENGTH_DECIBELS_MILLIWATT}",
|
||||||
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
|
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
|
||||||
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
(SSDSensorDeviceClass.COUNT, None): SensorEntityDescription(
|
"movement_counter": SensorEntityDescription(
|
||||||
key="movement_counter",
|
key="movement_counter",
|
||||||
|
translation_key="movement_counter",
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
|
# Acceleration keys exported in newer versions of ruuvitag-ble
|
||||||
|
"acceleration_x": SensorEntityDescription(
|
||||||
|
key=f"acceleration_x_{Units.ACCELERATION_METERS_PER_SQUARE_SECOND}",
|
||||||
|
translation_key="acceleration_x",
|
||||||
|
native_unit_of_measurement=Units.ACCELERATION_METERS_PER_SQUARE_SECOND,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
"acceleration_y": SensorEntityDescription(
|
||||||
|
key=f"acceleration_y_{Units.ACCELERATION_METERS_PER_SQUARE_SECOND}",
|
||||||
|
translation_key="acceleration_y",
|
||||||
|
native_unit_of_measurement=Units.ACCELERATION_METERS_PER_SQUARE_SECOND,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
"acceleration_z": SensorEntityDescription(
|
||||||
|
key=f"acceleration_z_{Units.ACCELERATION_METERS_PER_SQUARE_SECOND}",
|
||||||
|
translation_key="acceleration_z",
|
||||||
|
native_unit_of_measurement=Units.ACCELERATION_METERS_PER_SQUARE_SECOND,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
"acceleration_total": SensorEntityDescription(
|
||||||
|
key=f"acceleration_total_{Units.ACCELERATION_METERS_PER_SQUARE_SECOND}",
|
||||||
|
translation_key="acceleration_total",
|
||||||
|
native_unit_of_measurement=Units.ACCELERATION_METERS_PER_SQUARE_SECOND,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
# Keys exported for dataformat 06 sensors in newer versions of ruuvitag-ble
|
||||||
|
"pm25": SensorEntityDescription(
|
||||||
|
key=f"{SSDSensorDeviceClass.PM25}_{Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}",
|
||||||
|
device_class=SensorDeviceClass.PM25,
|
||||||
|
native_unit_of_measurement=Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
),
|
||||||
|
"carbon_dioxide": SensorEntityDescription(
|
||||||
|
key=f"{SSDSensorDeviceClass.CO2}_{Units.CONCENTRATION_PARTS_PER_MILLION}",
|
||||||
|
device_class=SensorDeviceClass.CO2,
|
||||||
|
native_unit_of_measurement=Units.CONCENTRATION_PARTS_PER_MILLION,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
),
|
||||||
|
"illuminance": SensorEntityDescription(
|
||||||
|
key=f"{SSDSensorDeviceClass.ILLUMINANCE}_{Units.LIGHT_LUX}",
|
||||||
|
device_class=SensorDeviceClass.ILLUMINANCE,
|
||||||
|
native_unit_of_measurement=Units.LIGHT_LUX,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
),
|
||||||
|
"voc_index": SensorEntityDescription(
|
||||||
|
key="voc_index",
|
||||||
|
translation_key="voc_index",
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
),
|
||||||
|
"nox_index": SensorEntityDescription(
|
||||||
|
key="nox_index",
|
||||||
|
translation_key="nox_index",
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -89,37 +143,28 @@ def _device_key_to_bluetooth_entity_key(
|
|||||||
return PassiveBluetoothEntityKey(device_key.key, device_key.device_id)
|
return PassiveBluetoothEntityKey(device_key.key, device_key.device_id)
|
||||||
|
|
||||||
|
|
||||||
def _to_sensor_key(
|
|
||||||
description: SensorDescription,
|
|
||||||
) -> tuple[SSDSensorDeviceClass, Units | None]:
|
|
||||||
assert description.device_class is not None
|
|
||||||
return (description.device_class, description.native_unit_of_measurement)
|
|
||||||
|
|
||||||
|
|
||||||
def sensor_update_to_bluetooth_data_update(
|
def sensor_update_to_bluetooth_data_update(
|
||||||
sensor_update: SensorUpdate,
|
sensor_update: SensorUpdate,
|
||||||
) -> PassiveBluetoothDataUpdate:
|
) -> PassiveBluetoothDataUpdate:
|
||||||
"""Convert a sensor update to a bluetooth data update."""
|
"""Convert a sensor update to a bluetooth data update."""
|
||||||
|
entity_descriptions: dict[PassiveBluetoothEntityKey, EntityDescription] = {}
|
||||||
|
entity_data = {}
|
||||||
|
for device_key, sensor_values in sensor_update.entity_values.items():
|
||||||
|
bek = _device_key_to_bluetooth_entity_key(device_key)
|
||||||
|
entity_data[bek] = sensor_values.native_value
|
||||||
|
for device_key in sensor_update.entity_descriptions:
|
||||||
|
bek = _device_key_to_bluetooth_entity_key(device_key)
|
||||||
|
if sk_description := SENSOR_DESCRIPTIONS.get(device_key.key):
|
||||||
|
entity_descriptions[bek] = sk_description
|
||||||
|
|
||||||
return PassiveBluetoothDataUpdate(
|
return PassiveBluetoothDataUpdate(
|
||||||
devices={
|
devices={
|
||||||
device_id: sensor_device_info_to_hass_device_info(device_info)
|
device_id: sensor_device_info_to_hass_device_info(device_info)
|
||||||
for device_id, device_info in sensor_update.devices.items()
|
for device_id, device_info in sensor_update.devices.items()
|
||||||
},
|
},
|
||||||
entity_descriptions={
|
entity_descriptions=entity_descriptions,
|
||||||
_device_key_to_bluetooth_entity_key(device_key): SENSOR_DESCRIPTIONS[
|
entity_data=entity_data,
|
||||||
_to_sensor_key(description)
|
entity_names={},
|
||||||
]
|
|
||||||
for device_key, description in sensor_update.entity_descriptions.items()
|
|
||||||
if _to_sensor_key(description) in SENSOR_DESCRIPTIONS
|
|
||||||
},
|
|
||||||
entity_data={
|
|
||||||
_device_key_to_bluetooth_entity_key(device_key): sensor_values.native_value
|
|
||||||
for device_key, sensor_values in sensor_update.entity_values.items()
|
|
||||||
},
|
|
||||||
entity_names={
|
|
||||||
_device_key_to_bluetooth_entity_key(device_key): sensor_values.name
|
|
||||||
for device_key, sensor_values in sensor_update.entity_values.items()
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -18,5 +18,30 @@
|
|||||||
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
|
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
|
||||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"entity": {
|
||||||
|
"sensor": {
|
||||||
|
"acceleration_total": {
|
||||||
|
"name": "Acceleration total"
|
||||||
|
},
|
||||||
|
"acceleration_x": {
|
||||||
|
"name": "Acceleration X"
|
||||||
|
},
|
||||||
|
"acceleration_y": {
|
||||||
|
"name": "Acceleration Y"
|
||||||
|
},
|
||||||
|
"acceleration_z": {
|
||||||
|
"name": "Acceleration Z"
|
||||||
|
},
|
||||||
|
"movement_counter": {
|
||||||
|
"name": "Movement counter"
|
||||||
|
},
|
||||||
|
"nox_index": {
|
||||||
|
"name": "NOx index"
|
||||||
|
},
|
||||||
|
"voc_index": {
|
||||||
|
"name": "VOC index"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,7 @@ NOT_RUUVITAG_SERVICE_INFO = BluetoothServiceInfo(
|
|||||||
source="local",
|
source="local",
|
||||||
)
|
)
|
||||||
|
|
||||||
RUUVITAG_SERVICE_INFO = BluetoothServiceInfo(
|
RUUVI_V5_SERVICE_INFO = BluetoothServiceInfo(
|
||||||
name="RuuviTag 0911",
|
name="RuuviTag 0911",
|
||||||
address="01:03:05:07:09:11", # Ignored (the payload encodes the correct MAC)
|
address="01:03:05:07:09:11", # Ignored (the payload encodes the correct MAC)
|
||||||
rssi=-60,
|
rssi=-60,
|
||||||
@@ -23,5 +23,16 @@ RUUVITAG_SERVICE_INFO = BluetoothServiceInfo(
|
|||||||
service_uuids=[],
|
service_uuids=[],
|
||||||
source="local",
|
source="local",
|
||||||
)
|
)
|
||||||
|
RUUVI_V6_SERVICE_INFO = BluetoothServiceInfo(
|
||||||
|
name="Ruuvi 1234",
|
||||||
|
address="01:03:05:07:12:34", # Ignored (the payload encodes the correct MAC)
|
||||||
|
rssi=-60,
|
||||||
|
manufacturer_data={
|
||||||
|
1177: b"\x06\x17\x0cVh\xc7\x9e\x00p\x00\xc9\x05\x01\xd9J\xcd\x00L\x88O",
|
||||||
|
},
|
||||||
|
service_data={},
|
||||||
|
service_uuids=[],
|
||||||
|
source="local",
|
||||||
|
)
|
||||||
CONFIGURED_NAME = "RuuviTag EFAF"
|
CONFIGURED_NAME = "RuuviTag EFAF"
|
||||||
CONFIGURED_PREFIX = "ruuvitag_efaf"
|
CONFIGURED_PREFIX = "ruuvitag_efaf"
|
||||||
|
1013
tests/components/ruuvitag_ble/snapshots/test_sensor.ambr
Normal file
1013
tests/components/ruuvitag_ble/snapshots/test_sensor.ambr
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ from homeassistant.components.ruuvitag_ble.const import DOMAIN
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
|
|
||||||
from .fixtures import CONFIGURED_NAME, NOT_RUUVITAG_SERVICE_INFO, RUUVITAG_SERVICE_INFO
|
from .fixtures import CONFIGURED_NAME, NOT_RUUVITAG_SERVICE_INFO, RUUVI_V5_SERVICE_INFO
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ async def test_async_step_bluetooth_valid_device(hass: HomeAssistant) -> None:
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_BLUETOOTH},
|
context={"source": config_entries.SOURCE_BLUETOOTH},
|
||||||
data=RUUVITAG_SERVICE_INFO,
|
data=RUUVI_V5_SERVICE_INFO,
|
||||||
)
|
)
|
||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
assert result["step_id"] == "bluetooth_confirm"
|
assert result["step_id"] == "bluetooth_confirm"
|
||||||
@@ -36,7 +36,7 @@ async def test_async_step_bluetooth_valid_device(hass: HomeAssistant) -> None:
|
|||||||
)
|
)
|
||||||
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
||||||
assert result2["title"] == CONFIGURED_NAME
|
assert result2["title"] == CONFIGURED_NAME
|
||||||
assert result2["result"].unique_id == RUUVITAG_SERVICE_INFO.address
|
assert result2["result"].unique_id == RUUVI_V5_SERVICE_INFO.address
|
||||||
|
|
||||||
|
|
||||||
async def test_async_step_bluetooth_not_ruuvitag(hass: HomeAssistant) -> None:
|
async def test_async_step_bluetooth_not_ruuvitag(hass: HomeAssistant) -> None:
|
||||||
@@ -64,7 +64,7 @@ async def test_async_step_user_with_found_devices(hass: HomeAssistant) -> None:
|
|||||||
"""Test setup from service info cache with devices found."""
|
"""Test setup from service info cache with devices found."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.ruuvitag_ble.config_flow.async_discovered_service_info",
|
"homeassistant.components.ruuvitag_ble.config_flow.async_discovered_service_info",
|
||||||
return_value=[RUUVITAG_SERVICE_INFO],
|
return_value=[RUUVI_V5_SERVICE_INFO],
|
||||||
):
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@@ -77,18 +77,18 @@ async def test_async_step_user_with_found_devices(hass: HomeAssistant) -> None:
|
|||||||
):
|
):
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={"address": RUUVITAG_SERVICE_INFO.address},
|
user_input={"address": RUUVI_V5_SERVICE_INFO.address},
|
||||||
)
|
)
|
||||||
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
||||||
assert result2["title"] == CONFIGURED_NAME
|
assert result2["title"] == CONFIGURED_NAME
|
||||||
assert result2["result"].unique_id == RUUVITAG_SERVICE_INFO.address
|
assert result2["result"].unique_id == RUUVI_V5_SERVICE_INFO.address
|
||||||
|
|
||||||
|
|
||||||
async def test_async_step_user_device_added_between_steps(hass: HomeAssistant) -> None:
|
async def test_async_step_user_device_added_between_steps(hass: HomeAssistant) -> None:
|
||||||
"""Test the device gets added via another flow between steps."""
|
"""Test the device gets added via another flow between steps."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.ruuvitag_ble.config_flow.async_discovered_service_info",
|
"homeassistant.components.ruuvitag_ble.config_flow.async_discovered_service_info",
|
||||||
return_value=[RUUVITAG_SERVICE_INFO],
|
return_value=[RUUVI_V5_SERVICE_INFO],
|
||||||
):
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@@ -99,7 +99,7 @@ async def test_async_step_user_device_added_between_steps(hass: HomeAssistant) -
|
|||||||
|
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
unique_id=RUUVITAG_SERVICE_INFO.address,
|
unique_id=RUUVI_V5_SERVICE_INFO.address,
|
||||||
)
|
)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ async def test_async_step_user_device_added_between_steps(hass: HomeAssistant) -
|
|||||||
):
|
):
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={"address": RUUVITAG_SERVICE_INFO.address},
|
user_input={"address": RUUVI_V5_SERVICE_INFO.address},
|
||||||
)
|
)
|
||||||
assert result2["type"] is FlowResultType.ABORT
|
assert result2["type"] is FlowResultType.ABORT
|
||||||
assert result2["reason"] == "already_configured"
|
assert result2["reason"] == "already_configured"
|
||||||
@@ -120,13 +120,13 @@ async def test_async_step_user_with_found_devices_already_setup(
|
|||||||
"""Test setup from service info cache with devices found."""
|
"""Test setup from service info cache with devices found."""
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
unique_id=RUUVITAG_SERVICE_INFO.address,
|
unique_id=RUUVI_V5_SERVICE_INFO.address,
|
||||||
)
|
)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.ruuvitag_ble.config_flow.async_discovered_service_info",
|
"homeassistant.components.ruuvitag_ble.config_flow.async_discovered_service_info",
|
||||||
return_value=[RUUVITAG_SERVICE_INFO],
|
return_value=[RUUVI_V5_SERVICE_INFO],
|
||||||
):
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@@ -140,14 +140,14 @@ async def test_async_step_bluetooth_devices_already_setup(hass: HomeAssistant) -
|
|||||||
"""Test we can't start a flow if there is already a config entry."""
|
"""Test we can't start a flow if there is already a config entry."""
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
unique_id=RUUVITAG_SERVICE_INFO.address,
|
unique_id=RUUVI_V5_SERVICE_INFO.address,
|
||||||
)
|
)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_BLUETOOTH},
|
context={"source": config_entries.SOURCE_BLUETOOTH},
|
||||||
data=RUUVITAG_SERVICE_INFO,
|
data=RUUVI_V5_SERVICE_INFO,
|
||||||
)
|
)
|
||||||
assert result["type"] is FlowResultType.ABORT
|
assert result["type"] is FlowResultType.ABORT
|
||||||
assert result["reason"] == "already_configured"
|
assert result["reason"] == "already_configured"
|
||||||
@@ -158,7 +158,7 @@ async def test_async_step_bluetooth_already_in_progress(hass: HomeAssistant) ->
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_BLUETOOTH},
|
context={"source": config_entries.SOURCE_BLUETOOTH},
|
||||||
data=RUUVITAG_SERVICE_INFO,
|
data=RUUVI_V5_SERVICE_INFO,
|
||||||
)
|
)
|
||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
assert result["step_id"] == "bluetooth_confirm"
|
assert result["step_id"] == "bluetooth_confirm"
|
||||||
@@ -166,7 +166,7 @@ async def test_async_step_bluetooth_already_in_progress(hass: HomeAssistant) ->
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_BLUETOOTH},
|
context={"source": config_entries.SOURCE_BLUETOOTH},
|
||||||
data=RUUVITAG_SERVICE_INFO,
|
data=RUUVI_V5_SERVICE_INFO,
|
||||||
)
|
)
|
||||||
assert result["type"] is FlowResultType.ABORT
|
assert result["type"] is FlowResultType.ABORT
|
||||||
assert result["reason"] == "already_in_progress"
|
assert result["reason"] == "already_in_progress"
|
||||||
@@ -179,14 +179,14 @@ async def test_async_step_user_takes_precedence_over_discovery(
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_BLUETOOTH},
|
context={"source": config_entries.SOURCE_BLUETOOTH},
|
||||||
data=RUUVITAG_SERVICE_INFO,
|
data=RUUVI_V5_SERVICE_INFO,
|
||||||
)
|
)
|
||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
assert result["step_id"] == "bluetooth_confirm"
|
assert result["step_id"] == "bluetooth_confirm"
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.ruuvitag_ble.config_flow.async_discovered_service_info",
|
"homeassistant.components.ruuvitag_ble.config_flow.async_discovered_service_info",
|
||||||
return_value=[RUUVITAG_SERVICE_INFO],
|
return_value=[RUUVI_V5_SERVICE_INFO],
|
||||||
):
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@@ -199,9 +199,9 @@ async def test_async_step_user_takes_precedence_over_discovery(
|
|||||||
):
|
):
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={"address": RUUVITAG_SERVICE_INFO.address},
|
user_input={"address": RUUVI_V5_SERVICE_INFO.address},
|
||||||
)
|
)
|
||||||
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
||||||
assert result2["title"] == CONFIGURED_NAME
|
assert result2["title"] == CONFIGURED_NAME
|
||||||
assert result2["data"] == {}
|
assert result2["data"] == {}
|
||||||
assert result2["result"].unique_id == RUUVITAG_SERVICE_INFO.address
|
assert result2["result"].unique_id == RUUVI_V5_SERVICE_INFO.address
|
||||||
|
@@ -3,47 +3,37 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
from homeassistant.components.ruuvitag_ble.const import DOMAIN
|
from homeassistant.components.ruuvitag_ble.const import DOMAIN
|
||||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
|
||||||
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_registry import EntityRegistry
|
||||||
|
from homeassistant.helpers.service_info.bluetooth import BluetoothServiceInfo
|
||||||
|
|
||||||
from .fixtures import CONFIGURED_NAME, CONFIGURED_PREFIX, RUUVITAG_SERVICE_INFO
|
from .fixtures import RUUVI_V5_SERVICE_INFO, RUUVI_V6_SERVICE_INFO
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry, snapshot_platform
|
||||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("enable_bluetooth")
|
@pytest.mark.usefixtures("enable_bluetooth", "entity_registry_enabled_by_default")
|
||||||
async def test_sensors(hass: HomeAssistant) -> None:
|
@pytest.mark.parametrize(
|
||||||
|
"service_info", [RUUVI_V5_SERVICE_INFO, RUUVI_V6_SERVICE_INFO], ids=("v5", "v6")
|
||||||
|
)
|
||||||
|
async def test_sensors(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entity_registry: EntityRegistry,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
service_info: BluetoothServiceInfo,
|
||||||
|
) -> None:
|
||||||
"""Test the RuuviTag BLE sensors."""
|
"""Test the RuuviTag BLE sensors."""
|
||||||
entry = MockConfigEntry(domain=DOMAIN, unique_id=RUUVITAG_SERVICE_INFO.address)
|
entry = MockConfigEntry(domain=DOMAIN, unique_id=service_info.address)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
inject_bluetooth_service_info(hass, service_info)
|
||||||
assert len(hass.states.async_all()) == 0
|
|
||||||
inject_bluetooth_service_info(
|
|
||||||
hass,
|
|
||||||
RUUVITAG_SERVICE_INFO,
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(hass.states.async_all()) >= 4
|
await snapshot_platform(hass, entity_registry, snapshot, entry.entry_id)
|
||||||
|
|
||||||
for sensor, value, unit, state_class in (
|
|
||||||
("temperature", "7.2", "°C", "measurement"),
|
|
||||||
("humidity", "61.84", "%", "measurement"),
|
|
||||||
("pressure", "1013.54", "hPa", "measurement"),
|
|
||||||
("voltage", "2395", "mV", "measurement"),
|
|
||||||
):
|
|
||||||
state = hass.states.get(f"sensor.{CONFIGURED_PREFIX}_{sensor}")
|
|
||||||
assert state is not None
|
|
||||||
assert state.state == value
|
|
||||||
name_lower = state.attributes[ATTR_FRIENDLY_NAME].lower()
|
|
||||||
assert name_lower == f"{CONFIGURED_NAME} {sensor}".lower()
|
|
||||||
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == unit
|
|
||||||
assert state.attributes[ATTR_STATE_CLASS] == state_class
|
|
||||||
assert await hass.config_entries.async_unload(entry.entry_id)
|
assert await hass.config_entries.async_unload(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
Reference in New Issue
Block a user