Skip to content

Commit 437aa1c

Browse files
committed
Add support for energy v2 endpoint
1 parent 9498408 commit 437aa1c

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

src/volvocarsapi/api.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@
2323
VolvoCarsLocation,
2424
VolvoCarsValue,
2525
VolvoCarsValueField,
26+
VolvoCarsValueStatusField,
2627
VolvoCarsVehicle,
2728
)
2829
from .util import redact_data, redact_url
2930

3031
_API_CONNECTED_ENDPOINT = "/connected-vehicle/v2/vehicles"
3132
_API_ENERGY_ENDPOINT = "/energy/v1/vehicles"
33+
_API_ENERGY_V2_ENDPOINT = "/energy/v2/vehicles"
3234
_API_LOCATION_ENDPOINT = "/location/v1/vehicles"
3335
_API_URL = "https://api.volvocars.com"
3436
_API_STATUS_URL = "https://public-developer-portal-bff.weu-prod.ecpaz.volvocars.biz/api/v1/backend-status"
@@ -122,6 +124,23 @@ async def async_get_doors_status(self, vin: str = "") -> dict[str, VolvoCarsValu
122124
"""
123125
return await self._async_get_field(_API_CONNECTED_ENDPOINT, "doors", vin)
124126

127+
async def async_get_energy_capabilities(self, vin: str = "") -> dict[str, Any]:
128+
"""Get energy state.
129+
130+
Required scopes: openid energy:capability:read
131+
"""
132+
return await self._async_get_data_dict(_API_ENERGY_V2_ENDPOINT, "capabilities", vin, data_key="getEnergyState")
133+
134+
async def async_get_energy_state(self, vin: str = "") -> dict[str, VolvoCarsValueStatusField | None]:
135+
"""Get energy state.
136+
137+
Required scopes: openid energy:state:read
138+
"""
139+
body = await self._async_get(_API_ENERGY_V2_ENDPOINT, "state", vin)
140+
return {
141+
key: VolvoCarsValueStatusField.from_dict(value) for key, value in body.items()
142+
}
143+
125144
async def async_get_engine_status(self, vin: str = "") -> dict[str, VolvoCarsValueField | None]:
126145
"""Get engine status.
127146
@@ -251,10 +270,10 @@ async def _async_get_field(
251270
}
252271

253272
async def _async_get_data_dict(
254-
self, endpoint: str, operation: str, vin: str = ""
273+
self, endpoint: str, operation: str, vin: str = "", *, data_key: str = "data"
255274
) -> dict[str, Any]:
256275
body = await self._async_get(endpoint, operation, vin)
257-
return cast(dict[str, Any], body.get("data", {}))
276+
return cast(dict[str, Any], body.get(data_key, {}))
258277

259278
async def _async_get(self, endpoint: str, operation: str, vin: str = "") -> dict[str, Any]:
260279
url = self._create_vin_url(endpoint, operation, vin)

src/volvocarsapi/models.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ def from_dict(cls, data: dict[str, Any]) -> Self | None:
4343
):
4444
# Recursive call for nested dataclasses
4545
class_data[key] = param_type.from_dict(value)
46-
elif key == "timestamp" and isinstance(value, str):
46+
elif key in ("timestamp", "updatedAt") and isinstance(value, str):
4747
if value:
48-
class_data[key] = datetime.fromisoformat(value)
48+
class_data["timestamp"] = datetime.fromisoformat(value)
4949
else:
5050
class_data[key] = value
5151
else:
@@ -116,6 +116,14 @@ class VolvoCarsValueField(VolvoCarsValue):
116116
unit: str | None = None
117117

118118

119+
@dataclass
120+
class VolvoCarsValueStatusField(VolvoCarsValueField):
121+
"""API value and status field model."""
122+
123+
value: Any = None
124+
status: str | None = None
125+
126+
119127
@dataclass
120128
class VolvoCarsGeometry(VolvoCarsApiBaseModel):
121129
"""API geometry model."""

src/volvocarsapi/scopes.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ class RestrictedScope(StrEnum):
3131
"conve:vehicle_relation",
3232
"conve:warnings",
3333
"conve:windows_status",
34+
"energy:capability:read",
35+
"energy:state:read"
36+
]
37+
38+
DEPRECATED_SCOPES = [
3439
"energy:battery_charge_level",
3540
"energy:charging_connection_status",
3641
"energy:charging_current_limit",

0 commit comments

Comments
 (0)