Skip to content

Commit e0e821a

Browse files
authored
Get next service by distance/time (bimmerconnected#713)
* Get next service by distance/time * Fix format
1 parent 6dca9f8 commit e0e821a

File tree

3 files changed

+46
-5
lines changed

3 files changed

+46
-5
lines changed

bimmer_connected/tests/responses/G01/bmw-eadrax-vcs_v4_vehicles_state_WBA00000000DEMO04.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,14 +251,14 @@
251251
"type": "BRAKE_FLUID"
252252
},
253253
{
254-
"dateTime": "2024-12-01T00:00:00.000Z",
254+
"dateTime": "2024-11-01T00:00:00.000Z",
255255
"description": "",
256256
"mileage": 50000,
257257
"status": "OK",
258258
"type": "VEHICLE_TUV"
259259
},
260260
{
261-
"dateTime": "2024-12-01T00:00:00.000Z",
261+
"dateTime": "2024-11-01T00:00:00.000Z",
262262
"description": "",
263263
"mileage": 50000,
264264
"status": "OK",

bimmer_connected/tests/test_vehicle_status.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,16 @@ async def test_plugged_in_waiting_for_charge_window(caplog, bmw_fixture: respx.R
210210
@pytest.mark.asyncio
211211
async def test_condition_based_services(caplog, bmw_fixture: respx.Router):
212212
"""Test condition based service messages."""
213-
vehicle = (await prepare_account_with_vehicles()).get_vehicle(VIN_G26)
213+
vehicle = (await prepare_account_with_vehicles()).get_vehicle(VIN_G01)
214+
215+
assert vehicle.condition_based_services.next_service_by_distance.due_distance == (50000, "km")
216+
assert vehicle.condition_based_services.next_service_by_distance.service_type == "BRAKE_FLUID"
217+
218+
assert vehicle.condition_based_services.next_service_by_time.due_date == datetime.datetime(2024, 11, 1, tzinfo=UTC)
219+
assert vehicle.condition_based_services.next_service_by_time.service_type == "VEHICLE_CHECK"
214220

215221
cbs = vehicle.condition_based_services.messages
216-
assert len(cbs) == 5
222+
assert len(cbs) == 4
217223
assert cbs[0].state == ConditionBasedServiceStatus.OK
218224
expected_cbs0 = datetime.datetime(year=2024, month=12, day=1, tzinfo=UTC)
219225
assert expected_cbs0 == cbs[0].due_date
@@ -225,7 +231,7 @@ async def test_condition_based_services(caplog, bmw_fixture: respx.Router):
225231
assert cbs[1].due_distance == (50000, "km")
226232

227233
assert cbs[2].state == ConditionBasedServiceStatus.OK
228-
expected_cbs2 = datetime.datetime(year=2024, month=12, day=1, tzinfo=UTC)
234+
expected_cbs2 = datetime.datetime(year=2024, month=11, day=1, tzinfo=UTC)
229235
assert expected_cbs2 == cbs[2].due_date
230236
assert cbs[2].due_distance == (50000, "km")
231237

@@ -367,6 +373,7 @@ async def test_check_control_messages(caplog, bmw_fixture: respx.Router):
367373
"""
368374
vehicle = (await prepare_account_with_vehicles()).get_vehicle(VIN_G01)
369375
assert vehicle.check_control_messages.has_check_control_messages is True
376+
assert vehicle.check_control_messages.urgent_check_control_messages == "ENGINE_OIL"
370377

371378
ccms = vehicle.check_control_messages.messages
372379
assert len(ccms) == 2
@@ -377,6 +384,7 @@ async def test_check_control_messages(caplog, bmw_fixture: respx.Router):
377384

378385
vehicle = (await prepare_account_with_vehicles()).get_vehicle(VIN_G20)
379386
assert vehicle.check_control_messages.has_check_control_messages is False
387+
assert vehicle.check_control_messages.urgent_check_control_messages is None
380388

381389
ccms = vehicle.check_control_messages.messages
382390
assert len(ccms) == 2

bimmer_connected/vehicle/reports.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ class ConditionBasedServiceReport(VehicleDataBase):
5555
is_service_required: bool = False
5656
"""Indicate if a service is required."""
5757

58+
next_service_by_distance: Optional[ConditionBasedService] = None
59+
"""Next service by distance."""
60+
61+
next_service_by_time: Optional[ConditionBasedService] = None
62+
"""Next service by due date."""
63+
5864
@classmethod
5965
def _parse_vehicle_data(cls, vehicle_data: Dict) -> Optional[Dict]:
6066
"""Parse doors and windows."""
@@ -64,6 +70,26 @@ def _parse_vehicle_data(cls, vehicle_data: Dict) -> Optional[Dict]:
6470
retval["messages"] = [ConditionBasedService.from_api_entry(**m) for m in messages]
6571
retval["is_service_required"] = any((m.state != ConditionBasedServiceStatus.OK) for m in retval["messages"])
6672

73+
retval["next_service_by_distance"] = next(
74+
iter(
75+
sorted(
76+
[m for m in retval["messages"] if m.due_distance.value is not None],
77+
key=lambda x: f"{x.due_distance.value:010}-{x.service_type}",
78+
)
79+
),
80+
None,
81+
)
82+
83+
retval["next_service_by_time"] = next(
84+
iter(
85+
sorted(
86+
[m for m in retval["messages"] if m.due_date is not None],
87+
key=lambda x: f"{x.due_date!s}-{x.service_type}",
88+
)
89+
),
90+
None,
91+
)
92+
6793
return retval
6894

6995

@@ -108,6 +134,8 @@ class CheckControlMessageReport(VehicleDataBase):
108134
has_check_control_messages: bool = False
109135
"""Indicate if check control messages are present."""
110136

137+
urgent_check_control_messages: Optional[str] = None
138+
111139
@classmethod
112140
def _parse_vehicle_data(cls, vehicle_data: Dict) -> Optional[Dict]:
113141
"""Parse doors and windows."""
@@ -116,6 +144,11 @@ def _parse_vehicle_data(cls, vehicle_data: Dict) -> Optional[Dict]:
116144
if ATTR_STATE in vehicle_data and (messages := vehicle_data[ATTR_STATE].get("checkControlMessages")):
117145
retval["messages"] = [CheckControlMessage.from_api_entry(**m) for m in messages if m["severity"] != "OK"]
118146
retval["has_check_control_messages"] = len([m for m in retval["messages"] if m.state != "LOW"]) > 0
147+
retval["urgent_check_control_messages"] = (
148+
", ".join([m.description_short for m in retval["messages"] if m.state != "LOW"])
149+
if retval["has_check_control_messages"]
150+
else None
151+
)
119152

120153
return retval
121154

0 commit comments

Comments
 (0)