Show charging power as 0 when not charging for the Volvo integration (#150797)

This commit is contained in:
Thomas D
2025-08-19 16:23:30 +02:00
committed by GitHub
parent 76f3397aa0
commit b52a806b36
10 changed files with 168 additions and 16 deletions

View File

@@ -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
}

View File

@@ -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
)

View File

@@ -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(

View File

@@ -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

View File

@@ -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"
}
}

View File

@@ -9,7 +9,7 @@
"chargerConnectionStatus": {
"isSupported": true
},
"chargingSystemStatus": {
"chargingStatus": {
"isSupported": true
},
"chargingType": {

View File

@@ -9,7 +9,7 @@
"chargerConnectionStatus": {
"isSupported": true
},
"chargingSystemStatus": {
"chargingStatus": {
"isSupported": true
},
"chargingType": {

View File

@@ -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",

View File

@@ -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': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'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': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
'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': <UnitOfPower.WATT: 'W'>,
})
# ---
# 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': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
}),
'context': <ANY>,
'entity_id': 'sensor.volvo_ex30_charging_power',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0',
})
# ---
# name: test_sensor[ex30_2024][sensor.volvo_ex30_charging_power_status-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -2164,7 +2220,7 @@
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'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': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'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': <ANY>,
'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': <ANY>,
'entity_id': 'sensor.volvo_xc60_target_battery_charge_level',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '80',
})
# ---
# name: test_sensor[xc60_phev_2020][sensor.volvo_xc60_time_to_engine_service-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@@ -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"