diff --git a/homeassistant/components/vicare/const.py b/homeassistant/components/vicare/const.py index 8f8ae3c94e3..828a879927d 100644 --- a/homeassistant/components/vicare/const.py +++ b/homeassistant/components/vicare/const.py @@ -23,7 +23,6 @@ UNSUPPORTED_DEVICES = [ "E3_FloorHeatingCircuitChannel", "E3_FloorHeatingCircuitDistributorBox", "E3_RoomControl_One_522", - "E3_RoomSensor", ] DEVICE_LIST = "device_list" diff --git a/homeassistant/components/vicare/entity.py b/homeassistant/components/vicare/entity.py index dfb8c48dfc3..2d858185b9f 100644 --- a/homeassistant/components/vicare/entity.py +++ b/homeassistant/components/vicare/entity.py @@ -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 diff --git a/homeassistant/components/vicare/sensor.py b/homeassistant/components/vicare/sensor.py index 79a93ffa345..feeb1a5b3a3 100644 --- a/homeassistant/components/vicare/sensor.py +++ b/homeassistant/components/vicare/sensor.py @@ -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, ...] = ( diff --git a/tests/components/vicare/conftest.py b/tests/components/vicare/conftest.py index c78669d1c3e..aadf85e7081 100644 --- a/tests/components/vicare/conftest.py +++ b/tests/components/vicare/conftest.py @@ -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.""" diff --git a/tests/components/vicare/fixtures/RoomSensor1.json b/tests/components/vicare/fixtures/RoomSensor1.json new file mode 100644 index 00000000000..b970e54a48c --- /dev/null +++ b/tests/components/vicare/fixtures/RoomSensor1.json @@ -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" + } + ] +} diff --git a/tests/components/vicare/fixtures/RoomSensor2.json b/tests/components/vicare/fixtures/RoomSensor2.json new file mode 100644 index 00000000000..81a1d935700 --- /dev/null +++ b/tests/components/vicare/fixtures/RoomSensor2.json @@ -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" + } + ] +} diff --git a/tests/components/vicare/snapshots/test_sensor.ambr b/tests/components/vicare/snapshots/test_sensor.ambr index 43e5b713293..ed4caf8ea79 100644 --- a/tests/components/vicare/snapshots/test_sensor.ambr +++ b/tests/components/vicare/snapshots/test_sensor.ambr @@ -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': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.model0_humidity', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + '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': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.model0_humidity', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '53', + }) +# --- +# name: test_room_sensors[sensor.model0_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.model0_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + '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': , + }) +# --- +# name: test_room_sensors[sensor.model0_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'model0 Temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.model0_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '17.5', + }) +# --- +# name: test_room_sensors[sensor.model1_humidity-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.model1_humidity', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + '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': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.model1_humidity', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '52', + }) +# --- +# name: test_room_sensors[sensor.model1_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.model1_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + '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': , + }) +# --- +# name: test_room_sensors[sensor.model1_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'model1 Temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.model1_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '16.9', + }) +# --- diff --git a/tests/components/vicare/test_sensor.py b/tests/components/vicare/test_sensor.py index 624fdf2cd5d..06c8b963680 100644 --- a/tests/components/vicare/test_sensor.py +++ b/tests/components/vicare/test_sensor.py @@ -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]),