mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Add support for room sensors in ViCare integration (#125243)
* Add room sensors * set humidity device class * add labels * Create RoomSensor2.json * Create RoomSensor1.json * Update conftest.py * Create test_sensor.py * enable E3_RoomSensor * use setup_integration * fix ruff findings * add test case * fix entity id * Apply suggestions from code review * update * fix findings * reuse labels * Apply suggestions from code review Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Apply suggestions from code review * fix test snapshot --------- Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
parent
e1db5f3cac
commit
404b3fcd03
@ -23,7 +23,6 @@ UNSUPPORTED_DEVICES = [
|
||||
"E3_FloorHeatingCircuitChannel",
|
||||
"E3_FloorHeatingCircuitDistributorBox",
|
||||
"E3_RoomControl_One_522",
|
||||
"E3_RoomSensor",
|
||||
]
|
||||
|
||||
DEVICE_LIST = "device_list"
|
||||
|
@ -29,7 +29,7 @@ class ViCareEntity(Entity):
|
||||
gateway_serial = device_config.getConfig().serial
|
||||
device_id = device_config.getId()
|
||||
|
||||
identifier = f"{gateway_serial}_{device_serial if device_serial is not None else device_id}"
|
||||
identifier = f"{gateway_serial}_{device_serial.replace("zigbee-", "zigbee_") if device_serial is not None else device_id}"
|
||||
|
||||
self._api: PyViCareDevice | PyViCareHeatingDeviceComponent = (
|
||||
component if component else device
|
||||
|
@ -751,6 +751,20 @@ GLOBAL_SENSORS: tuple[ViCareSensorEntityDescription, ...] = (
|
||||
options=["ready", "production"],
|
||||
value_getter=lambda api: _filter_pv_states(api.getPhotovoltaicStatus()),
|
||||
),
|
||||
ViCareSensorEntityDescription(
|
||||
key="room_temperature",
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_getter=lambda api: api.getTemperature(),
|
||||
),
|
||||
ViCareSensorEntityDescription(
|
||||
key="room_humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_getter=lambda api: api.getHumidity(),
|
||||
),
|
||||
)
|
||||
|
||||
CIRCUIT_SENSORS: tuple[ViCareSensorEntityDescription, ...] = (
|
||||
|
@ -92,6 +92,24 @@ async def mock_vicare_gas_boiler(
|
||||
yield mock_config_entry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def mock_vicare_room_sensors(
|
||||
hass: HomeAssistant, mock_config_entry: MockConfigEntry
|
||||
) -> AsyncGenerator[MockConfigEntry]:
|
||||
"""Return a mocked ViCare API representing multiple room sensor devices."""
|
||||
fixtures: list[Fixture] = [
|
||||
Fixture({"type:climateSensor"}, "vicare/RoomSensor1.json"),
|
||||
Fixture({"type:climateSensor"}, "vicare/RoomSensor2.json"),
|
||||
]
|
||||
with patch(
|
||||
f"{MODULE}.vicare_login",
|
||||
return_value=MockPyViCare(fixtures),
|
||||
):
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
yield mock_config_entry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_setup_entry() -> Generator[AsyncMock]:
|
||||
"""Mock setting up a config entry."""
|
||||
|
99
tests/components/vicare/fixtures/RoomSensor1.json
Normal file
99
tests/components/vicare/fixtures/RoomSensor1.json
Normal file
@ -0,0 +1,99 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"apiVersion": 1,
|
||||
"commands": {},
|
||||
"deviceId": "zigbee-d87a3bfffe5d844a",
|
||||
"feature": "device.messages.errors.raw",
|
||||
"gatewayId": "################",
|
||||
"isEnabled": true,
|
||||
"isReady": true,
|
||||
"properties": {
|
||||
"entries": {
|
||||
"type": "array",
|
||||
"value": []
|
||||
}
|
||||
},
|
||||
"timestamp": "2024-03-01T04:40:59.911Z",
|
||||
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/zigbee-d87a3bfffe5d844a/features/device.messages.errors.raw"
|
||||
},
|
||||
{
|
||||
"apiVersion": 1,
|
||||
"commands": {
|
||||
"setName": {
|
||||
"isExecutable": true,
|
||||
"name": "setName",
|
||||
"params": {
|
||||
"name": {
|
||||
"constraints": {
|
||||
"maxLength": 40,
|
||||
"minLength": 1,
|
||||
"regEx": "^[\\p{L}0-9]+( [\\p{L}0-9]+)*$"
|
||||
},
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/zigbee-d87a3bfffe5d844a/features/device.name/commands/setName"
|
||||
}
|
||||
},
|
||||
"deviceId": "zigbee-d87a3bfffe5d844a",
|
||||
"feature": "device.name",
|
||||
"gatewayId": "################",
|
||||
"isEnabled": true,
|
||||
"isReady": true,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"value": "Office"
|
||||
}
|
||||
},
|
||||
"timestamp": "2024-03-01T04:40:59.911Z",
|
||||
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/zigbee-d87a3bfffe5d844a/features/device.name"
|
||||
},
|
||||
{
|
||||
"apiVersion": 1,
|
||||
"commands": {},
|
||||
"deviceId": "zigbee-d87a3bfffe5d844a",
|
||||
"feature": "device.sensors.humidity",
|
||||
"gatewayId": "################",
|
||||
"isEnabled": true,
|
||||
"isReady": true,
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"value": "connected"
|
||||
},
|
||||
"value": {
|
||||
"type": "number",
|
||||
"unit": "percent",
|
||||
"value": 53
|
||||
}
|
||||
},
|
||||
"timestamp": "2024-03-02T07:51:07.303Z",
|
||||
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/zigbee-d87a3bfffe5d844a/features/device.sensors.humidity"
|
||||
},
|
||||
{
|
||||
"apiVersion": 1,
|
||||
"commands": {},
|
||||
"deviceId": "zigbee-d87a3bfffe5d844a",
|
||||
"feature": "device.sensors.temperature",
|
||||
"gatewayId": "################",
|
||||
"isEnabled": true,
|
||||
"isReady": true,
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"value": "connected"
|
||||
},
|
||||
"value": {
|
||||
"type": "number",
|
||||
"unit": "celsius",
|
||||
"value": 17.5
|
||||
}
|
||||
},
|
||||
"timestamp": "2024-03-02T07:52:42.043Z",
|
||||
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/zigbee-d87a3bfffe5d844a/features/device.sensors.temperature"
|
||||
}
|
||||
]
|
||||
}
|
99
tests/components/vicare/fixtures/RoomSensor2.json
Normal file
99
tests/components/vicare/fixtures/RoomSensor2.json
Normal file
@ -0,0 +1,99 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"apiVersion": 1,
|
||||
"commands": {},
|
||||
"deviceId": "zigbee-5cc7c1fffea33a3b",
|
||||
"feature": "device.messages.errors.raw",
|
||||
"gatewayId": "################",
|
||||
"isEnabled": true,
|
||||
"isReady": true,
|
||||
"properties": {
|
||||
"entries": {
|
||||
"type": "array",
|
||||
"value": []
|
||||
}
|
||||
},
|
||||
"timestamp": "2024-03-01T04:40:59.911Z",
|
||||
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/zigbee-5cc7c1fffea33a3b/features/device.messages.errors.raw"
|
||||
},
|
||||
{
|
||||
"apiVersion": 1,
|
||||
"commands": {
|
||||
"setName": {
|
||||
"isExecutable": true,
|
||||
"name": "setName",
|
||||
"params": {
|
||||
"name": {
|
||||
"constraints": {
|
||||
"maxLength": 40,
|
||||
"minLength": 1,
|
||||
"regEx": "^[\\p{L}0-9]+( [\\p{L}0-9]+)*$"
|
||||
},
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/zigbee-5cc7c1fffea33a3b/features/device.name/commands/setName"
|
||||
}
|
||||
},
|
||||
"deviceId": "zigbee-5cc7c1fffea33a3b",
|
||||
"feature": "device.name",
|
||||
"gatewayId": "################",
|
||||
"isEnabled": true,
|
||||
"isReady": true,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"value": ""
|
||||
}
|
||||
},
|
||||
"timestamp": "2024-03-01T04:40:59.911Z",
|
||||
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/zigbee-5cc7c1fffea33a3b/features/device.name"
|
||||
},
|
||||
{
|
||||
"apiVersion": 1,
|
||||
"commands": {},
|
||||
"deviceId": "zigbee-5cc7c1fffea33a3b",
|
||||
"feature": "device.sensors.humidity",
|
||||
"gatewayId": "################",
|
||||
"isEnabled": true,
|
||||
"isReady": true,
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"value": "connected"
|
||||
},
|
||||
"value": {
|
||||
"type": "number",
|
||||
"unit": "percent",
|
||||
"value": 52
|
||||
}
|
||||
},
|
||||
"timestamp": "2024-03-02T07:42:06.922Z",
|
||||
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/zigbee-5cc7c1fffea33a3b/features/device.sensors.humidity"
|
||||
},
|
||||
{
|
||||
"apiVersion": 1,
|
||||
"commands": {},
|
||||
"deviceId": "zigbee-5cc7c1fffea33a3b",
|
||||
"feature": "device.sensors.temperature",
|
||||
"gatewayId": "################",
|
||||
"isEnabled": true,
|
||||
"isReady": true,
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"value": "connected"
|
||||
},
|
||||
"value": {
|
||||
"type": "number",
|
||||
"unit": "celsius",
|
||||
"value": 16.9
|
||||
}
|
||||
},
|
||||
"timestamp": "2024-03-02T07:24:48.056Z",
|
||||
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/devices/zigbee-5cc7c1fffea33a3b/features/device.sensors.temperature"
|
||||
}
|
||||
]
|
||||
}
|
@ -1050,3 +1050,207 @@
|
||||
'state': '25.5',
|
||||
})
|
||||
# ---
|
||||
# name: test_room_sensors[sensor.model0_humidity-entry]
|
||||
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.model0_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': 'vicare',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'gateway0_zigbee_d87a3bfffe5d844a-room_humidity',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_room_sensors[sensor.model0_humidity-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'humidity',
|
||||
'friendly_name': 'model0 Humidity',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': '%',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.model0_humidity',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '53',
|
||||
})
|
||||
# ---
|
||||
# name: test_room_sensors[sensor.model0_temperature-entry]
|
||||
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.model0_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': 'vicare',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'gateway0_zigbee_d87a3bfffe5d844a-room_temperature',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_room_sensors[sensor.model0_temperature-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': 'model0 Temperature',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.model0_temperature',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '17.5',
|
||||
})
|
||||
# ---
|
||||
# name: test_room_sensors[sensor.model1_humidity-entry]
|
||||
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.model1_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': 'vicare',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'gateway1_zigbee_5cc7c1fffea33a3b-room_humidity',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_room_sensors[sensor.model1_humidity-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'humidity',
|
||||
'friendly_name': 'model1 Humidity',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': '%',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.model1_humidity',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '52',
|
||||
})
|
||||
# ---
|
||||
# name: test_room_sensors[sensor.model1_temperature-entry]
|
||||
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.model1_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': 'vicare',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'gateway1_zigbee_5cc7c1fffea33a3b-room_temperature',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_room_sensors[sensor.model1_temperature-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': 'model1 Temperature',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.model1_temperature',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '16.9',
|
||||
})
|
||||
# ---
|
||||
|
@ -23,7 +23,30 @@ async def test_all_entities(
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test all entities."""
|
||||
fixtures: list[Fixture] = [Fixture({"type:boiler"}, "vicare/Vitodens300W.json")]
|
||||
fixtures: list[Fixture] = [
|
||||
Fixture({"type:boiler"}, "vicare/Vitodens300W.json"),
|
||||
]
|
||||
with (
|
||||
patch(f"{MODULE}.vicare_login", return_value=MockPyViCare(fixtures)),
|
||||
patch(f"{MODULE}.PLATFORMS", [Platform.SENSOR]),
|
||||
):
|
||||
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_room_sensors(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test all entities."""
|
||||
fixtures: list[Fixture] = [
|
||||
Fixture({"type:climateSensor"}, "vicare/RoomSensor1.json"),
|
||||
Fixture({"type:climateSensor"}, "vicare/RoomSensor2.json"),
|
||||
]
|
||||
with (
|
||||
patch(f"{MODULE}.vicare_login", return_value=MockPyViCare(fixtures)),
|
||||
patch(f"{MODULE}.PLATFORMS", [Platform.SENSOR]),
|
||||
|
Loading…
x
Reference in New Issue
Block a user