diff --git a/homeassistant/components/volvo/coordinator.py b/homeassistant/components/volvo/coordinator.py index da23e7875c9..d6c8f349a52 100644 --- a/homeassistant/components/volvo/coordinator.py +++ b/homeassistant/components/volvo/coordinator.py @@ -260,6 +260,8 @@ class VolvoMediumIntervalCoordinator(VolvoBaseCoordinator): "Volvo medium interval coordinator", ) + self._supported_capabilities: list[str] = [] + async def _async_determine_api_calls( self, ) -> list[Callable[[], Coroutine[Any, Any, Any]]]: @@ -267,6 +269,31 @@ class VolvoMediumIntervalCoordinator(VolvoBaseCoordinator): capabilities = await self.api.async_get_energy_capabilities() if capabilities.get("isSupported", False): - return [self.api.async_get_energy_state] + self._supported_capabilities = [ + key + for key, value in capabilities.items() + if isinstance(value, dict) and value.get("isSupported", False) + ] + + return [self._async_get_energy_state] return [] + + async def _async_get_energy_state( + self, + ) -> dict[str, VolvoCarsValueStatusField | None]: + def _mark_ok( + field: VolvoCarsValueStatusField | None, + ) -> VolvoCarsValueStatusField | None: + if field: + field.status = "OK" + + return field + + energy_state = await self.api.async_get_energy_state() + + return { + key: _mark_ok(value) + for key, value in energy_state.items() + if key in self._supported_capabilities + } diff --git a/homeassistant/components/volvo/sensor.py b/homeassistant/components/volvo/sensor.py index 7f37ac42dc8..b9a620d898d 100644 --- a/homeassistant/components/volvo/sensor.py +++ b/homeassistant/components/volvo/sensor.py @@ -67,8 +67,8 @@ def _calculate_time_to_service(field: VolvoCarsValue) -> int: def _charging_power_value(field: VolvoCarsValue) -> int: return ( - int(field.value) - if isinstance(field, VolvoCarsValueStatusField) and field.status == "OK" + field.value + if isinstance(field, VolvoCarsValueStatusField) and isinstance(field.value, int) else 0 ) diff --git a/tests/components/volvo/conftest.py b/tests/components/volvo/conftest.py index edd3f39998e..fedd3a6ec3f 100644 --- a/tests/components/volvo/conftest.py +++ b/tests/components/volvo/conftest.py @@ -9,7 +9,7 @@ from volvocarsapi.auth import TOKEN_URL from volvocarsapi.models import ( VolvoCarsAvailableCommand, VolvoCarsLocation, - VolvoCarsValueField, + VolvoCarsValueStatusField, VolvoCarsVehicle, ) @@ -98,7 +98,7 @@ async def mock_api(hass: HomeAssistant, full_model: str) -> AsyncGenerator[Async hass, "energy_state", full_model ) energy_state = { - key: VolvoCarsValueField.from_dict(value) + key: VolvoCarsValueStatusField.from_dict(value) for key, value in energy_state_data.items() } engine_status = await async_load_fixture_as_value_field( diff --git a/tests/components/volvo/fixtures/ex30_2024/energy_capabilities.json b/tests/components/volvo/fixtures/ex30_2024/energy_capabilities.json index 968c759ab27..f3aff11585d 100644 --- a/tests/components/volvo/fixtures/ex30_2024/energy_capabilities.json +++ b/tests/components/volvo/fixtures/ex30_2024/energy_capabilities.json @@ -9,7 +9,7 @@ "chargerConnectionStatus": { "isSupported": true }, - "chargingSystemStatus": { + "chargingStatus": { "isSupported": true }, "chargingType": { @@ -25,7 +25,7 @@ "isSupported": true }, "chargingCurrentLimit": { - "isSupported": true + "isSupported": false }, "chargingPower": { "isSupported": true diff --git a/tests/components/volvo/fixtures/ex30_2024/energy_state.json b/tests/components/volvo/fixtures/ex30_2024/energy_state.json index 0170d1aa617..5973100d4ea 100644 --- a/tests/components/volvo/fixtures/ex30_2024/energy_state.json +++ b/tests/components/volvo/fixtures/ex30_2024/energy_state.json @@ -50,7 +50,7 @@ }, "chargingPower": { "status": "ERROR", - "code": "NOT_SUPPORTED", - "message": "Resource is not supported for this vehicle" + "code": "PROPERTY_NOT_FOUND", + "message": "No valid value could be found for the requested property" } } diff --git a/tests/components/volvo/fixtures/xc40_electric_2024/energy_capabilities.json b/tests/components/volvo/fixtures/xc40_electric_2024/energy_capabilities.json index 968c759ab27..3523d51e071 100644 --- a/tests/components/volvo/fixtures/xc40_electric_2024/energy_capabilities.json +++ b/tests/components/volvo/fixtures/xc40_electric_2024/energy_capabilities.json @@ -9,7 +9,7 @@ "chargerConnectionStatus": { "isSupported": true }, - "chargingSystemStatus": { + "chargingStatus": { "isSupported": true }, "chargingType": { diff --git a/tests/components/volvo/fixtures/xc60_phev_2020/energy_capabilities.json b/tests/components/volvo/fixtures/xc60_phev_2020/energy_capabilities.json index d8aa07ff0bb..331795f545b 100644 --- a/tests/components/volvo/fixtures/xc60_phev_2020/energy_capabilities.json +++ b/tests/components/volvo/fixtures/xc60_phev_2020/energy_capabilities.json @@ -9,7 +9,7 @@ "chargerConnectionStatus": { "isSupported": true }, - "chargingSystemStatus": { + "chargingStatus": { "isSupported": true }, "chargingType": { diff --git a/tests/components/volvo/fixtures/xc60_phev_2020/energy_state.json b/tests/components/volvo/fixtures/xc60_phev_2020/energy_state.json index e2f0cd13807..e198bfc8330 100644 --- a/tests/components/volvo/fixtures/xc60_phev_2020/energy_state.json +++ b/tests/components/volvo/fixtures/xc60_phev_2020/energy_state.json @@ -40,9 +40,10 @@ "message": "Resource is not supported for this vehicle" }, "targetBatteryChargeLevel": { - "status": "ERROR", - "code": "NOT_SUPPORTED", - "message": "Resource is not supported for this vehicle" + "status": "OK", + "value": 80, + "unit": "percentage", + "updatedAt": "2024-09-22T09:40:12Z" }, "chargingPower": { "status": "ERROR", diff --git a/tests/components/volvo/snapshots/test_sensor.ambr b/tests/components/volvo/snapshots/test_sensor.ambr index e218986517a..9d709a27fc3 100644 --- a/tests/components/volvo/snapshots/test_sensor.ambr +++ b/tests/components/volvo/snapshots/test_sensor.ambr @@ -232,6 +232,62 @@ 'state': 'connected', }) # --- +# name: test_sensor[ex30_2024][sensor.volvo_ex30_charging_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.volvo_ex30_charging_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Charging power', + 'platform': 'volvo', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'charging_power', + 'unique_id': 'yv1abcdefg1234567_charging_power', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[ex30_2024][sensor.volvo_ex30_charging_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Volvo EX30 Charging power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.volvo_ex30_charging_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- # name: test_sensor[ex30_2024][sensor.volvo_ex30_charging_power_status-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -2164,7 +2220,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0', + 'state': '1386', }) # --- # name: test_sensor[xc40_electric_2024][sensor.volvo_xc40_charging_power_status-entry] @@ -3601,6 +3657,58 @@ 'state': '30000', }) # --- +# name: test_sensor[xc60_phev_2020][sensor.volvo_xc60_target_battery_charge_level-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.volvo_xc60_target_battery_charge_level', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Target battery charge level', + 'platform': 'volvo', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'target_battery_charge_level', + 'unique_id': 'yv1abcdefg1234567_target_battery_charge_level', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor[xc60_phev_2020][sensor.volvo_xc60_target_battery_charge_level-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Volvo XC60 Target battery charge level', + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.volvo_xc60_target_battery_charge_level', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '80', + }) +# --- # name: test_sensor[xc60_phev_2020][sensor.volvo_xc60_time_to_engine_service-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/volvo/test_sensor.py b/tests/components/volvo/test_sensor.py index 2813c741286..a4b7a787117 100644 --- a/tests/components/volvo/test_sensor.py +++ b/tests/components/volvo/test_sensor.py @@ -68,4 +68,20 @@ async def test_skip_invalid_api_fields( with patch("homeassistant.components.volvo.PLATFORMS", [Platform.SENSOR]): assert await setup_integration() - assert not hass.states.get(f"sensor.volvo_{short_model}_charging_power") + assert not hass.states.get(f"sensor.volvo_{short_model}_charging_current_limit") + + +@pytest.mark.parametrize( + "full_model", + ["ex30_2024"], +) +async def test_charging_power_value( + hass: HomeAssistant, + setup_integration: Callable[[], Awaitable[bool]], +) -> None: + """Test if charging_power_value is zero if supported, but not charging.""" + + with patch("homeassistant.components.volvo.PLATFORMS", [Platform.SENSOR]): + assert await setup_integration() + + assert hass.states.get("sensor.volvo_ex30_charging_power").state == "0"