diff --git a/src/saic_ismart_client_ng/api/vehicle/schema.py b/src/saic_ismart_client_ng/api/vehicle/schema.py index f0bbaab..55754c8 100644 --- a/src/saic_ismart_client_ng/api/vehicle/schema.py +++ b/src/saic_ismart_client_ng/api/vehicle/schema.py @@ -162,10 +162,17 @@ class RvcParamsId(Enum): UNK_6 = 6 LOCK_ID = 7 WINDOW_SUNROOF = 8 + # The door windows follow the status model (driverWindow, passengerWindow, + # rearLeftWindow, rearRightWindow). The front pair is named by role, the + # rear pair by side. The WINDOW_2/3/4 names are the original ones, kept as + # aliases. WINDOW_DRIVER = 9 - WINDOW_2 = 10 - WINDOW_3 = 11 - WINDOW_4 = 12 + WINDOW_PASSENGER = 10 + WINDOW_REAR_LEFT = 11 + WINDOW_REAR_RIGHT = 12 + WINDOW_2 = 10 # noqa: PIE796 - alias of WINDOW_PASSENGER + WINDOW_3 = 11 # noqa: PIE796 - alias of WINDOW_REAR_LEFT + WINDOW_4 = 12 # noqa: PIE796 - alias of WINDOW_REAR_RIGHT WINDOW_OPEN_CLOSE = 13 HEATED_SEAT_DRIVER = 17 HEATED_SEAT_PASSENGER = 18 diff --git a/src/saic_ismart_client_ng/api/vehicle/windows/__init__.py b/src/saic_ismart_client_ng/api/vehicle/windows/__init__.py index d7b6211..37f6841 100644 --- a/src/saic_ismart_client_ng/api/vehicle/windows/__init__.py +++ b/src/saic_ismart_client_ng/api/vehicle/windows/__init__.py @@ -38,9 +38,9 @@ async def control_windows( for i in [ VehicleWindowId.SUNROOF, VehicleWindowId.DRIVER, - VehicleWindowId.WINDOW_2, - VehicleWindowId.WINDOW_3, - VehicleWindowId.WINDOW_4, + VehicleWindowId.PASSENGER, + VehicleWindowId.REAR_LEFT, + VehicleWindowId.REAR_RIGHT, ]: if i.value.value in requested_windows: rcv_params.append(RvcParams(i.value, b"\x01")) @@ -78,9 +78,9 @@ async def control_door_windows( rvc_params = [ RvcParams(RvcParamsId.WINDOW_SUNROOF, b"\x00"), RvcParams(RvcParamsId.WINDOW_DRIVER, b"\x01"), - RvcParams(RvcParamsId.WINDOW_2, b"\x01"), - RvcParams(RvcParamsId.WINDOW_3, b"\x01"), - RvcParams(RvcParamsId.WINDOW_4, b"\x01"), + RvcParams(RvcParamsId.WINDOW_PASSENGER, b"\x01"), + RvcParams(RvcParamsId.WINDOW_REAR_LEFT, b"\x01"), + RvcParams(RvcParamsId.WINDOW_REAR_RIGHT, b"\x01"), RvcParams(RvcParamsId.WINDOW_OPEN_CLOSE, action.value.to_bytes(1, "big")), ] request = VehicleControlReq( diff --git a/src/saic_ismart_client_ng/api/vehicle/windows/schema.py b/src/saic_ismart_client_ng/api/vehicle/windows/schema.py index 2e1dc01..6eb8351 100644 --- a/src/saic_ismart_client_ng/api/vehicle/windows/schema.py +++ b/src/saic_ismart_client_ng/api/vehicle/windows/schema.py @@ -8,9 +8,13 @@ class VehicleWindowId(Enum): SUNROOF = RvcParamsId.WINDOW_SUNROOF DRIVER = RvcParamsId.WINDOW_DRIVER - WINDOW_2 = RvcParamsId.WINDOW_2 - WINDOW_3 = RvcParamsId.WINDOW_3 - WINDOW_4 = RvcParamsId.WINDOW_4 + PASSENGER = RvcParamsId.WINDOW_PASSENGER + REAR_LEFT = RvcParamsId.WINDOW_REAR_LEFT + REAR_RIGHT = RvcParamsId.WINDOW_REAR_RIGHT + # The original names, kept as aliases. + WINDOW_2 = RvcParamsId.WINDOW_2 # alias of PASSENGER + WINDOW_3 = RvcParamsId.WINDOW_3 # alias of REAR_LEFT + WINDOW_4 = RvcParamsId.WINDOW_4 # alias of REAR_RIGHT class DoorWindowsAction(Enum): diff --git a/tests/test_door_window_names.py b/tests/test_door_window_names.py new file mode 100644 index 0000000..34f0a5e --- /dev/null +++ b/tests/test_door_window_names.py @@ -0,0 +1,59 @@ +"""Door windows are named after the status model, the old names are aliases. + +The parameters sent to the car don't change. +""" + +from __future__ import annotations + +import base64 +from typing import Any +import unittest + +from saic_ismart_client_ng import SaicApi +from saic_ismart_client_ng.api.vehicle import RvcParamsId +from saic_ismart_client_ng.api.vehicle.windows import VehicleWindowId +from saic_ismart_client_ng.model import SaicApiConfiguration + + +class TestDoorWindowNames(unittest.IsolatedAsyncioTestCase): + def test_new_names_keep_the_param_ids(self) -> None: + assert RvcParamsId.WINDOW_DRIVER.value == 9 + assert RvcParamsId.WINDOW_PASSENGER.value == 10 + assert RvcParamsId.WINDOW_REAR_LEFT.value == 11 + assert RvcParamsId.WINDOW_REAR_RIGHT.value == 12 + + def test_old_names_still_work(self) -> None: + # Looked up by name: mypy doesn't know enum aliases share a member. + assert RvcParamsId["WINDOW_2"] is RvcParamsId.WINDOW_PASSENGER + assert RvcParamsId["WINDOW_3"] is RvcParamsId.WINDOW_REAR_LEFT + assert RvcParamsId["WINDOW_4"] is RvcParamsId.WINDOW_REAR_RIGHT + assert VehicleWindowId["WINDOW_2"] is VehicleWindowId.PASSENGER + assert VehicleWindowId["WINDOW_3"] is VehicleWindowId.REAR_LEFT + assert VehicleWindowId["WINDOW_4"] is VehicleWindowId.REAR_RIGHT + + async def test_control_windows_command_unchanged(self) -> None: + api = SaicApi(SaicApiConfiguration(username="user", password="pass")) # noqa: S106 + captured: dict[str, Any] = {} + + async def capture(body: Any, _vin: str) -> None: + captured["body"] = body + + api.send_vehicle_control_command = capture # type: ignore[method-assign,assignment] + await api.control_windows( + "OFFLINE0000000000", + should_open=False, + windows=[VehicleWindowId.PASSENGER], + ) + await api.close() + params = [ + (p.paramId, base64.b64decode(p.paramValue)) + for p in captured["body"].rvcParams + ] + assert params == [ + (8, b"\x00"), + (9, b"\x00"), + (10, b"\x01"), + (11, b"\x00"), + (12, b"\x00"), + (13, b"\x00"), + ]