rivian-python-client 2.2.0b1__tar.gz → 2.2.0b3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/PKG-INFO +1 -1
  2. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/pyproject.toml +8 -0
  3. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/__version__.py +1 -1
  4. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/body.py +70 -46
  5. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/charging.py +37 -37
  6. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/comfort.py +88 -91
  7. rivian_python_client-2.2.0b3/src/rivian/parallax/device_table.py +99 -0
  8. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/dynamics.py +51 -61
  9. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/energy.py +12 -17
  10. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/energy_edge_compute.py +6 -8
  11. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/gearguard_streaming.py +9 -9
  12. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/geofence.py +11 -5
  13. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/holiday_celebration.py +47 -9
  14. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/navigation.py +12 -32
  15. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/ota.py +28 -25
  16. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/body.proto +86 -27
  17. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/body_pb2.py +72 -0
  18. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/body_pb2.pyi +154 -40
  19. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/charging.proto +1 -1
  20. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/charging_pb2.py +10 -10
  21. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/comfort.proto +44 -37
  22. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/comfort_pb2.py +78 -0
  23. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/comfort_pb2.pyi +57 -43
  24. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/departure.proto +1 -1
  25. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/departure_pb2.py +11 -11
  26. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/device_table.proto +64 -0
  27. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/device_table_pb2.py +50 -0
  28. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/device_table_pb2.pyi +92 -0
  29. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/dynamics.proto +11 -11
  30. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/dynamics_pb2.py +72 -0
  31. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/energy.proto +5 -5
  32. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/energy_edge_compute.proto +11 -11
  33. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/energy_edge_compute_pb2.py +49 -0
  34. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/energy_pb2.py +11 -11
  35. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/geofence.proto +9 -2
  36. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/geofence_pb2.py +5 -3
  37. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/geofence_pb2.pyi +16 -4
  38. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/holiday_celebration.proto +25 -14
  39. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/holiday_celebration_pb2.py +50 -0
  40. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/holiday_celebration_pb2.pyi +92 -0
  41. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/navigation.proto +10 -10
  42. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/navigation_pb2.py +78 -0
  43. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/ota.proto +19 -12
  44. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/ota_pb2.py +66 -0
  45. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/ota_pb2.pyi +26 -19
  46. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/security.proto +1 -1
  47. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/security_pb2.py +66 -0
  48. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/vehicle.proto +18 -18
  49. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/vehicle_access.proto +19 -0
  50. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/vehicle_access_pb2.py +5 -3
  51. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/vehicle_access_pb2.pyi +25 -0
  52. rivian_python_client-2.2.0b3/src/rivian/parallax/proto/vehicle_pb2.py +62 -0
  53. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/vehicle_pb2.pyi +20 -20
  54. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/security.py +39 -39
  55. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/vehicle.py +56 -55
  56. rivian_python_client-2.2.0b3/src/rivian/parallax/vehicle_access.py +39 -0
  57. rivian_python_client-2.2.0b1/src/rivian/parallax/device_table.py +0 -59
  58. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/body_pb2.py +0 -64
  59. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/comfort_pb2.py +0 -78
  60. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/device_table.proto +0 -44
  61. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/device_table_pb2.py +0 -46
  62. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/device_table_pb2.pyi +0 -61
  63. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/dynamics_pb2.py +0 -72
  64. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/energy_edge_compute_pb2.py +0 -49
  65. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/holiday_celebration_pb2.py +0 -44
  66. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/holiday_celebration_pb2.pyi +0 -73
  67. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/navigation_pb2.py +0 -78
  68. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/ota_pb2.py +0 -64
  69. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/security_pb2.py +0 -66
  70. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/vehicle_access.proto +0 -8
  71. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/vehicle_access_pb2.pyi +0 -9
  72. rivian_python_client-2.2.0b1/src/rivian/parallax/proto/vehicle_pb2.py +0 -62
  73. rivian_python_client-2.2.0b1/src/rivian/parallax/vehicle_access.py +0 -18
  74. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/.gitignore +0 -0
  75. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/README.md +0 -0
  76. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/__init__.py +0 -0
  77. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/ble.py +0 -0
  78. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/const.py +0 -0
  79. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/exceptions.py +0 -0
  80. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/__init__.py +0 -0
  81. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/core.py +0 -0
  82. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/departure.py +0 -0
  83. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/parallax.py +0 -0
  84. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/__init__.py +0 -0
  85. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/charging_pb2.pyi +0 -0
  86. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/departure_pb2.pyi +0 -0
  87. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/dynamics_pb2.pyi +0 -0
  88. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/energy_edge_compute_pb2.pyi +0 -0
  89. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/energy_pb2.pyi +0 -0
  90. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/gearguard_streaming.proto +0 -0
  91. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/gearguard_streaming_pb2.py +0 -0
  92. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/gearguard_streaming_pb2.pyi +0 -0
  93. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/navigation_pb2.pyi +0 -0
  94. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/parallax.proto +0 -0
  95. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/parallax_pb2.py +0 -0
  96. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/parallax_pb2.pyi +0 -0
  97. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/secure_file_transfer.proto +0 -0
  98. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/secure_file_transfer_pb2.py +0 -0
  99. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/secure_file_transfer_pb2.pyi +0 -0
  100. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/security_pb2.pyi +0 -0
  101. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/user_passcodes.proto +0 -0
  102. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/user_passcodes_pb2.py +0 -0
  103. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/proto/user_passcodes_pb2.pyi +0 -0
  104. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/secure_file_transfer.py +0 -0
  105. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/parallax/user_passcodes.py +0 -0
  106. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/py.typed +0 -0
  107. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/rivian.py +0 -0
  108. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/schemas/charging.graphql +0 -0
  109. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/schemas/gateway.graphql +0 -0
  110. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/schemas/orders.graphql +0 -0
  111. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/utils.py +0 -0
  112. {rivian_python_client-2.2.0b1 → rivian_python_client-2.2.0b3}/src/rivian/ws_monitor.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: rivian-python-client
3
- Version: 2.2.0b1
3
+ Version: 2.2.0b3
4
4
  Summary: Rivian API Client (Unofficial)
5
5
  Author-email: Brian Retterer <bretterer@gmail.com>, "J.R. Gutierrez" <jrgutier@gmail.com>, Nathan Spencer <natekspencer@gmail.com>, Trevor Mack <drummer8001@gmail.com>
6
6
  License-Expression: MIT
@@ -36,8 +36,16 @@ dev = [
36
36
  "pre-commit>=4.6.1,<5",
37
37
  "types-protobuf>=7.35.1.20260906",
38
38
  "grpcio-tools==1.84.0",
39
+ "pytest-cov>=7.0,<8",
39
40
  ]
40
41
 
42
+ [tool.coverage.run]
43
+ source = ["rivian"]
44
+ omit = ["*_pb2.py"]
45
+
46
+ [tool.coverage.report]
47
+ exclude_also = ["if TYPE_CHECKING:"]
48
+
41
49
  [tool.hatch.build.hooks.version]
42
50
  path = "src/rivian/__version__.py"
43
51
 
@@ -1,4 +1,4 @@
1
1
  # This file is auto-generated by Hatchling. As such, do not:
2
2
  # - modify
3
3
  # - track in version control e.g. be sure to add to .gitignore
4
- __version__ = VERSION = '2.2.0b1'
4
+ __version__ = VERSION = '2.2.0b3'
@@ -8,28 +8,30 @@ from .core import _LOGGER, RVMDecoder, _enum, _present
8
8
  from .proto import body_pb2
9
9
 
10
10
  _CLOSURE_MAP: Final[dict[int, str]] = {
11
- 1: "doorFrontLeftClosed",
12
- 2: "doorFrontRightClosed",
13
- 3: "doorRearLeftClosed",
14
- 4: "doorRearRightClosed",
15
- 5: "closureFrunkClosed",
16
- 6: "closureTailgateClosed",
17
- 7: "closureLiftgateClosed",
18
- 8: "closureSideBinLeftClosed",
19
- 9: "closureSideBinRightClosed",
20
- 10: "chargePortState",
21
- 11: "closureTonneauClosed",
22
- 12: "windowFrontLeftClosed",
23
- 13: "windowFrontRightClosed",
24
- 14: "windowRearLeftClosed",
25
- 15: "windowRearRightClosed",
11
+ body_pb2.DOOR_FRONT_LEFT: "doorFrontLeftClosed",
12
+ body_pb2.DOOR_FRONT_RIGHT: "doorFrontRightClosed",
13
+ body_pb2.DOOR_REAR_LEFT: "doorRearLeftClosed",
14
+ body_pb2.DOOR_REAR_RIGHT: "doorRearRightClosed",
15
+ body_pb2.FRUNK: "closureFrunkClosed",
16
+ body_pb2.TAILGATE: "closureTailgateClosed",
17
+ body_pb2.LIFTGATE: "closureLiftgateClosed",
18
+ body_pb2.SIDE_BIN_LEFT: "closureSideBinLeftClosed",
19
+ body_pb2.SIDE_BIN_RIGHT: "closureSideBinRightClosed",
20
+ body_pb2.CHARGE_PORT: "chargePortState",
21
+ body_pb2.TONNEAU: "closureTonneauClosed",
22
+ body_pb2.WINDOW_FRONT_LEFT: "windowFrontLeftClosed",
23
+ body_pb2.WINDOW_FRONT_RIGHT: "windowFrontRightClosed",
24
+ body_pb2.WINDOW_REAR_LEFT: "windowRearLeftClosed",
25
+ body_pb2.WINDOW_REAR_RIGHT: "windowRearRightClosed",
26
+ body_pb2.WINDOW_REAR: "windowRearClosed",
26
27
  }
27
28
 
28
29
  _CLOSURE_STATE_MAP: Final[dict[int, str]] = {
29
- 1: "open",
30
- 2: "closed",
31
- 4: "opening",
32
- 5: "closing",
30
+ body_pb2.CLOSURE_STATE_OPEN: "open",
31
+ body_pb2.CLOSURE_STATE_CLOSED: "closed",
32
+ body_pb2.CLOSURE_STATE_AJAR: "ajar",
33
+ body_pb2.CLOSURE_STATE_OPENING: "opening",
34
+ body_pb2.CLOSURE_STATE_CLOSING: "closing",
33
35
  }
34
36
 
35
37
 
@@ -41,11 +43,7 @@ def _enum_names(enum: Any, prefix: str) -> dict[int, str]:
41
43
  }
42
44
 
43
45
 
44
- # Other side-bin values are unconfirmed, so they pass through as raw ints.
45
- _SIDE_BIN_NEXT_ACTIONS: Final[dict[int, str]] = {
46
- body_pb2.SIDE_BIN_SNA: "sna",
47
- body_pb2.SIDE_BIN_OPEN_ALLOWED: "open_allowed",
48
- }
46
+ _SIDE_BIN_NEXT_ACTIONS: Final = _enum_names(body_pb2.SideBinNextAction, "SIDE_BIN_")
49
47
 
50
48
  # Closure id -> (next-action field, result key, value names).
51
49
  _NEXT_ACTIONS: Final[dict[int, tuple[str, str, dict[int, str]]]] = {
@@ -54,6 +52,11 @@ _NEXT_ACTIONS: Final[dict[int, tuple[str, str, dict[int, str]]]] = {
54
52
  "closureFrunkNextAction",
55
53
  _enum_names(body_pb2.FrunkNextAction, "FRUNK_"),
56
54
  ),
55
+ body_pb2.LIFTGATE: (
56
+ "liftgate_next_action",
57
+ "closureLiftgateNextAction",
58
+ _enum_names(body_pb2.LiftgateNextAction, "LIFTGATE_"),
59
+ ),
57
60
  body_pb2.SIDE_BIN_LEFT: (
58
61
  "side_bin_next_action",
59
62
  "closureSideBinLeftNextAction",
@@ -74,26 +77,42 @@ _NEXT_ACTIONS: Final[dict[int, tuple[str, str, dict[int, str]]]] = {
74
77
  "closureChargePortDoorNextAction",
75
78
  _enum_names(body_pb2.ChargePortDoorNextAction, "CHARGE_PORT_DOOR_"),
76
79
  ),
80
+ body_pb2.GROUP_WINDOWS: (
81
+ "windows_next_action",
82
+ "windowsNextAction",
83
+ _enum_names(body_pb2.WindowsNextAction, "WINDOWS_"),
84
+ ),
77
85
  }
78
86
 
79
87
  _LOCK_MAP: Final[dict[int, str]] = {
80
- 1: "doorFrontLeftLocked",
81
- 2: "doorFrontRightLocked",
82
- 3: "doorRearLeftLocked",
83
- 4: "doorRearRightLocked",
84
- 5: "closureFrunkLocked",
85
- 6: "closureTailgateLocked",
86
- 7: "closureLiftgateLocked",
87
- 8: "closureSideBinLeftLocked",
88
- 9: "closureSideBinRightLocked",
89
- 15: "closureTonneauLocked",
88
+ body_pb2.LOCK_DOOR_FRONT_LEFT: "doorFrontLeftLocked",
89
+ body_pb2.LOCK_DOOR_FRONT_RIGHT: "doorFrontRightLocked",
90
+ body_pb2.LOCK_DOOR_REAR_LEFT: "doorRearLeftLocked",
91
+ body_pb2.LOCK_DOOR_REAR_RIGHT: "doorRearRightLocked",
92
+ body_pb2.LOCK_FRUNK: "closureFrunkLocked",
93
+ body_pb2.LOCK_TAILGATE: "closureTailgateLocked",
94
+ body_pb2.LOCK_LIFTGATE: "closureLiftgateLocked",
95
+ body_pb2.LOCK_SIDE_BIN_LEFT: "closureSideBinLeftLocked",
96
+ body_pb2.LOCK_SIDE_BIN_RIGHT: "closureSideBinRightLocked",
97
+ body_pb2.LOCK_CHARGE_PORT: "closureChargePortLocked",
98
+ body_pb2.LOCK_TRUNK_SECURITY: "closureTrunkSecurityLocked",
99
+ body_pb2.LOCK_CENTER_CONSOLE: "closureCenterConsoleLocked",
100
+ body_pb2.LOCK_GLOVE_BOX: "closureGloveBoxLocked",
101
+ body_pb2.LOCK_GEAR_GUARD: "gearGuardLocked",
102
+ body_pb2.LOCK_TONNEAU: "closureTonneauLocked",
103
+ }
104
+
105
+ _LOCK_STATE_MAP: Final[dict[int, str]] = {
106
+ body_pb2.LOCK_STATE_LOCKED: "locked",
107
+ body_pb2.LOCK_STATE_UNLOCKED: "unlocked",
108
+ body_pb2.LOCK_STATE_PARTIALLY_UNLOCKED: "partially_unlocked",
90
109
  }
91
110
 
92
111
  _TRAILER_PRESENCE_MAP: Final[dict[int, str]] = {
93
- 1: "trailer_not_present",
94
- 2: "trailer_present",
95
- 3: "trailer_present_with_brakes",
96
- 4: "trailer_invalid",
112
+ body_pb2.TRAILER_NOT_PRESENT: "trailer_not_present",
113
+ body_pb2.TRAILER_PRESENT: "trailer_present",
114
+ body_pb2.TRAILER_PRESENT_WITH_BRAKES: "trailer_present_with_brakes",
115
+ body_pb2.TRAILER_INVALID: "trailer_invalid",
97
116
  }
98
117
 
99
118
 
@@ -103,10 +122,11 @@ def decode_closures(m: body_pb2.ClosuresState) -> dict[str, Any]:
103
122
 
104
123
  Fields:
105
124
  doorFrontLeftClosed, closureFrunkClosed, etc.: str
106
- ("open" | "closed" | "opening" | "closing")
107
- closureFrunkNextAction, closureTailgateNextAction,
108
- closureSideBinLeftNextAction, closureSideBinRightNextAction,
109
- closureChargePortDoorNextAction: str — e.g. "open_allowed" (shut),
125
+ ("open" | "closed" | "ajar" | "opening" | "closing")
126
+ closureFrunkNextAction, closureLiftgateNextAction,
127
+ closureTailgateNextAction, closureSideBinLeftNextAction,
128
+ closureSideBinRightNextAction, closureChargePortDoorNextAction,
129
+ windowsNextAction: str — e.g. "open_allowed" (shut),
110
130
  "close_allowed" (open); for the charge port,
111
131
  "close_not_available" means plugged in
112
132
 
@@ -122,7 +142,7 @@ def decode_closures(m: body_pb2.ClosuresState) -> dict[str, Any]:
122
142
  result[_CLOSURE_MAP[cid]] = _enum(
123
143
  _CLOSURE_STATE_MAP, state_val, what="closure state"
124
144
  )
125
- else:
145
+ elif cid != body_pb2.GROUP_WINDOWS:
126
146
  _LOGGER.debug("Unknown closure id %s (state %s)", cid, state_val)
127
147
  if cid in _NEXT_ACTIONS:
128
148
  field, key, names = _NEXT_ACTIONS[cid]
@@ -133,10 +153,12 @@ def decode_closures(m: body_pb2.ClosuresState) -> dict[str, Any]:
133
153
 
134
154
  @RVMDecoder.register("body.locks.states", body_pb2.LocksState)
135
155
  def decode_locks(m: body_pb2.LocksState) -> dict[str, Any]:
136
- """body.locks.states — lock state of every lockable closure.
156
+ """body.locks.states — lock state of every lock.
137
157
 
138
158
  Fields:
139
- doorFrontLeftLocked, closureFrunkLocked, etc.: str ("locked" | "unlocked")
159
+ doorFrontLeftLocked, closureFrunkLocked, gearGuardLocked (the Gear
160
+ Guard cable), etc.: str ("locked" | "unlocked" |
161
+ "partially_unlocked")
140
162
  """
141
163
  result: dict[str, Any] = {}
142
164
  for s in m.lock:
@@ -145,7 +167,9 @@ def decode_locks(m: body_pb2.LocksState) -> dict[str, Any]:
145
167
  if state_val is None:
146
168
  continue
147
169
  if lid in _LOCK_MAP:
148
- result[_LOCK_MAP[lid]] = "locked" if state_val == 1 else "unlocked"
170
+ result[_LOCK_MAP[lid]] = _enum(
171
+ _LOCK_STATE_MAP, state_val, what="lock state"
172
+ )
149
173
  else:
150
174
  _LOGGER.debug("Unknown lock id %s (state %s)", lid, state_val)
151
175
  return result
@@ -8,13 +8,13 @@ from .core import RVMDecoder, _enum, _present
8
8
  from .proto import charging_pb2
9
9
 
10
10
  _DAY_OF_WEEK_MAP: Final[dict[int, str]] = {
11
- 1: "sunday",
12
- 2: "monday",
13
- 3: "tuesday",
14
- 4: "wednesday",
15
- 5: "thursday",
16
- 6: "friday",
17
- 7: "saturday",
11
+ charging_pb2.ScheduleTimeWindow.SUNDAY: "sunday",
12
+ charging_pb2.ScheduleTimeWindow.MONDAY: "monday",
13
+ charging_pb2.ScheduleTimeWindow.TUESDAY: "tuesday",
14
+ charging_pb2.ScheduleTimeWindow.WEDNESDAY: "wednesday",
15
+ charging_pb2.ScheduleTimeWindow.THURSDAY: "thursday",
16
+ charging_pb2.ScheduleTimeWindow.FRIDAY: "friday",
17
+ charging_pb2.ScheduleTimeWindow.SATURDAY: "saturday",
18
18
  }
19
19
 
20
20
 
@@ -65,8 +65,8 @@ def decode_session_notification(m: charging_pb2.SessionNotification) -> dict[str
65
65
 
66
66
 
67
67
  _REMOTE_COMMAND_MAP: Final[dict[int, str]] = {
68
- 1: "start",
69
- 2: "stop",
68
+ charging_pb2.REMOTE_COMMAND_START: "start",
69
+ charging_pb2.REMOTE_COMMAND_STOP: "stop",
70
70
  }
71
71
 
72
72
 
@@ -144,34 +144,34 @@ def decode_weighted_charging_forecast(
144
144
 
145
145
 
146
146
  _CONNECTION_STATE_MAP: Final[dict[int, str]] = {
147
- 1: "disconnected",
148
- 2: "connected",
147
+ charging_pb2.CONNECTION_STATE_DISCONNECTED: "disconnected",
148
+ charging_pb2.CONNECTION_STATE_CONNECTED: "connected",
149
149
  }
150
150
 
151
151
  _CHARGING_STATE_MAP: Final[dict[int, str]] = {
152
- 1: "charging_ready",
153
- 2: "charging_connecting",
154
- 3: "charging_active",
155
- 4: "charging_complete",
156
- 5: "charging_scheduled",
157
- 6: "charging_vehicle_error",
158
- 7: "charging_station_error",
159
- 8: "charging_stopped_by_user",
160
- 9: "charging_stopped_by_station",
161
- 10: "charging_payment_error",
162
- 11: "charging_cert_error",
163
- 12: "charging_tls_error",
164
- 13: "charging_error_ac_adapter_used_on_dc",
165
- 14: "charging_error_dc_adapter_used_on_ac",
166
- 15: "charging_error_incompatible_charger",
167
- 16: "charging_sd_compensation",
168
- 17: "waiting_on_charger",
169
- 18: "charging_error_not_ready_or_incompatible_charger",
170
- 19: "charging_vehicle_stopped",
171
- 20: "charging_payment_error_start_rivian_app",
172
- 21: "charging_tls_error_unknown_charger",
173
- 22: "charging_tls_error_unexpected_fail",
174
- 23: "charging_tls_error_start_rivian_app",
152
+ charging_pb2.CHARGING_READY: "charging_ready",
153
+ charging_pb2.CHARGING_CONNECTING: "charging_connecting",
154
+ charging_pb2.CHARGING_ACTIVE: "charging_active",
155
+ charging_pb2.CHARGING_COMPLETE: "charging_complete",
156
+ charging_pb2.CHARGING_SCHEDULED: "charging_scheduled",
157
+ charging_pb2.CHARGING_VEHICLE_ERROR: "charging_vehicle_error",
158
+ charging_pb2.CHARGING_STATION_ERROR: "charging_station_error",
159
+ charging_pb2.CHARGING_USER_STOPPED: "charging_stopped_by_user",
160
+ charging_pb2.CHARGING_STATION_STOPPED: "charging_stopped_by_station",
161
+ charging_pb2.CHARGING_PAYMENT_ERROR: "charging_payment_error",
162
+ charging_pb2.CHARGING_CERT_ERROR: "charging_cert_error",
163
+ charging_pb2.CHARGING_TLS_ERROR: "charging_tls_error",
164
+ charging_pb2.CHARGING_ERROR_AC_ADAPTER_USED_ON_DC: "charging_error_ac_adapter_used_on_dc",
165
+ charging_pb2.CHARGING_ERROR_DC_ADAPTER_USED_ON_AC: "charging_error_dc_adapter_used_on_ac",
166
+ charging_pb2.CHARGING_ERROR_INCOMPATIBLE_CHARGER: "charging_error_incompatible_charger",
167
+ charging_pb2.CHARGING_SD_COMPENSATION: "charging_sd_compensation",
168
+ charging_pb2.WAITING_ON_CHARGER: "waiting_on_charger",
169
+ charging_pb2.CHARGER_NOT_READY_OR_INCOMPATIBLE: "charging_error_not_ready_or_incompatible_charger",
170
+ charging_pb2.CHARGING_VEHICLE_STOPPED: "charging_vehicle_stopped",
171
+ charging_pb2.CHARGING_PAYMENT_ERROR_START_RIVIAN_APP: "charging_payment_error_start_rivian_app",
172
+ charging_pb2.CHARGING_TLS_ERROR_UNKNOWN_CHARGER: "charging_tls_error_unknown_charger",
173
+ charging_pb2.CHARGING_TLS_ERROR_UNEXPECTED_FAIL: "charging_tls_error_unexpected_fail",
174
+ charging_pb2.CHARGING_TLS_ERROR_START_RIVIAN_APP: "charging_tls_error_start_rivian_app",
175
175
  }
176
176
 
177
177
 
@@ -211,9 +211,9 @@ def decode_time_estimation(m: charging_pb2.TimeEstimation) -> dict[str, Any]:
211
211
 
212
212
 
213
213
  _CHARGER_STATUS_MAP: Final[dict[int, str]] = {
214
- 1: "chrgr_sts_not_connected",
215
- 2: "chrgr_sts_connected_no_chrg",
216
- 3: "chrgr_sts_connected_charging",
214
+ charging_pb2.CHARGER_STATUS_NOT_CONNECTED: "chrgr_sts_not_connected",
215
+ charging_pb2.CHARGER_STATUS_CONNECTED_NO_CHARGE: "chrgr_sts_connected_no_chrg",
216
+ charging_pb2.CHARGER_STATUS_CONNECTED_CHARGING: "chrgr_sts_connected_charging",
217
217
  }
218
218
 
219
219
 
@@ -17,9 +17,7 @@ def decode_hvac_settings_status(m: comfort_pb2.HvacSettingsStatus) -> dict[str,
17
17
  Fields:
18
18
  hvacTargetTemperature: float (°C; 63.5 = "HI", set while defrosting)
19
19
  """
20
- if (v := _present(m, "target_temperature")) is None:
21
- return {}
22
- return {"hvacTargetTemperature": round(v, 1)}
20
+ return {"hvacTargetTemperature": round(m.target_temperature, 1)}
23
21
 
24
22
 
25
23
  @RVMDecoder.register("comfort.user_modes.state", comfort_pb2.UserModesState)
@@ -34,60 +32,69 @@ def decode_user_modes_state(m: comfort_pb2.UserModesState) -> dict[str, Any]:
34
32
 
35
33
 
36
34
  _CLIMATE_HOLD_AVAILABILITY_MAP: Final[dict[int, str]] = {
37
- 0: "unspecified",
38
- 1: "available",
39
- 2: "controllable",
40
- 3: "unavailable",
35
+ comfort_pb2.CLIMATE_HOLD_AVAILABILITY_UNSPECIFIED: "unspecified",
36
+ comfort_pb2.CLIMATE_HOLD_AVAILABLE: "available",
37
+ comfort_pb2.CLIMATE_HOLD_CONTROLLABLE: "controllable",
38
+ comfort_pb2.CLIMATE_HOLD_UNAVAILABLE: "unavailable",
41
39
  }
42
40
 
43
41
  _CLIMATE_HOLD_STATUS_MAP: Final[dict[int, str]] = {
44
- 0: "unspecified",
45
- 1: "unavailable",
46
- 2: "off",
47
- 3: "on",
48
- 4: "fault",
42
+ comfort_pb2.CLIMATE_HOLD_STATUS_UNSPECIFIED: "unspecified",
43
+ comfort_pb2.CLIMATE_HOLD_STATUS_UNAVAILABLE: "unavailable",
44
+ comfort_pb2.CLIMATE_HOLD_STATUS_OFF: "off",
45
+ comfort_pb2.CLIMATE_HOLD_STATUS_ON: "on",
46
+ comfort_pb2.CLIMATE_HOLD_STATUS_FAULT: "fault",
49
47
  }
50
48
 
51
49
  _CLIMATE_HOLD_UNAVAILABILITY_REASON_MAP: Final[dict[int, str]] = {
52
- 0: "unspecified",
53
- 1: "unknown",
54
- 2: "low_soc",
50
+ comfort_pb2.CLIMATE_HOLD_UNAVAILABILITY_UNSPECIFIED: "unspecified",
51
+ comfort_pb2.CLIMATE_HOLD_UNAVAILABILITY_UNKNOWN: "unknown",
52
+ comfort_pb2.CLIMATE_HOLD_UNAVAILABILITY_LOW_SOC: "low_soc",
55
53
  }
56
54
 
57
55
  _PET_MODE_STATE_MAP: Final[dict[int, str]] = {
58
- 0: "off",
59
- 1: "on",
60
- 2: "disabled",
61
- 3: "faulty",
56
+ comfort_pb2.PET_MODE_OFF: "off",
57
+ comfort_pb2.PET_MODE_ON: "on",
58
+ comfort_pb2.PET_MODE_DISABLED: "disabled",
59
+ comfort_pb2.PET_MODE_FAULTY: "faulty",
62
60
  }
63
61
 
64
62
  _PET_MODE_TEMPERATURE_MAP: Final[dict[int, str]] = {
65
- 0: "default",
66
- 1: "cold",
67
- 2: "hot",
68
- 3: "faulty",
63
+ comfort_pb2.PET_MODE_TEMPERATURE_DEFAULT: "default",
64
+ comfort_pb2.PET_MODE_TEMPERATURE_COLD: "cold",
65
+ comfort_pb2.PET_MODE_TEMPERATURE_HOT: "hot",
66
+ comfort_pb2.PET_MODE_TEMPERATURE_FAULTY: "faulty",
69
67
  }
70
68
 
71
- _SEAT_CONDITIONING_MAP: Final[dict[int, str]] = {
72
- 1: "steeringWheel",
73
- 5: "seatFrontLeft",
74
- 7: "seatFrontRight", # inferred
75
- 8: "seatRearLeft",
76
- 10: "seatRearRight",
77
- 11: "seatThirdRowLeft", # R1S
78
- 13: "seatThirdRowRight", # R1S
69
+ # Seat keys use the GraphQL names: row 1 is "Front", row 2 "Rear", row 3
70
+ # "ThirdRow".
71
+ _CABIN_SURFACE_MAP: Final[dict[int, str]] = {
72
+ comfort_pb2.STEERING_WHEEL: "steeringWheel",
73
+ comfort_pb2.REAR_GLASS: "rearGlass",
74
+ comfort_pb2.FRONT_GLASS: "frontGlass",
75
+ comfort_pb2.SIDEVIEW_MIRRORS: "sideviewMirrors",
76
+ comfort_pb2.SEAT_ROW_1_LEFT: "seatFrontLeft",
77
+ comfort_pb2.SEAT_ROW_1_MIDDLE: "seatFrontMiddle",
78
+ comfort_pb2.SEAT_ROW_1_RIGHT: "seatFrontRight",
79
+ comfort_pb2.SEAT_ROW_2_LEFT: "seatRearLeft",
80
+ comfort_pb2.SEAT_ROW_2_MIDDLE: "seatRearMiddle",
81
+ comfort_pb2.SEAT_ROW_2_RIGHT: "seatRearRight",
82
+ comfort_pb2.SEAT_ROW_3_LEFT: "seatThirdRowLeft",
83
+ comfort_pb2.SEAT_ROW_3_MIDDLE: "seatThirdRowMiddle",
84
+ comfort_pb2.SEAT_ROW_3_RIGHT: "seatThirdRowRight",
85
+ comfort_pb2.WIPER_AREA: "wiperArea",
79
86
  }
80
87
 
81
- _SEAT_CONDITIONING_STATUS_MAP: Final[dict[int | None, str]] = {
88
+ _CONDITIONING_LEVEL_MAP: Final[dict[int | None, str]] = {
82
89
  None: "Off",
83
- 1: "Level_1",
84
- 2: "Level_2",
85
- 3: "Level_3",
90
+ comfort_pb2.CONDITIONING_LEVEL_1: "Level_1",
91
+ comfort_pb2.CONDITIONING_LEVEL_2: "Level_2",
92
+ comfort_pb2.CONDITIONING_LEVEL_3: "Level_3",
86
93
  }
87
94
 
88
- _SEAT_CONDITIONING_TYPE_MAP: Final[dict[int, str]] = {
89
- 1: "Heat",
90
- 2: "Vent",
95
+ _CONDITIONING_TYPE_MAP: Final[dict[int, str]] = {
96
+ comfort_pb2.CONDITIONING_HEAT: "Heat",
97
+ comfort_pb2.CONDITIONING_VENT: "Vent",
91
98
  }
92
99
 
93
100
 
@@ -123,12 +130,10 @@ def decode_cabin_temperatures(m: comfort_pb2.CabinTemperatures) -> dict[str, Any
123
130
  cabinClimateDriverTemperature: float (°C) — set point, same as
124
131
  `hvacTargetTemperature`
125
132
  """
126
- result: dict[str, Any] = {}
127
- if (v := _present(m, "interior_temperature")) is not None:
128
- result["cabinClimateInteriorTemperature"] = round(v, 1)
129
- if (v := _present(m, "driver_set_point")) is not None:
130
- result["cabinClimateDriverTemperature"] = round(v, 1)
131
- return result
133
+ return {
134
+ "cabinClimateInteriorTemperature": round(m.interior_temperature, 1),
135
+ "cabinClimateDriverTemperature": round(m.driver_set_point, 1),
136
+ }
132
137
 
133
138
 
134
139
  @RVMDecoder.register(
@@ -137,24 +142,20 @@ def decode_cabin_temperatures(m: comfort_pb2.CabinTemperatures) -> dict[str, Any
137
142
  def decode_cabin_ventilation(m: comfort_pb2.CabinVentilationSetting) -> dict[str, Any]:
138
143
  """comfort.cabin.cabin_ventilation_setting — passive ventilation settings.
139
144
 
140
- Fields (each only when sent):
145
+ Fields:
141
146
  cabinVentilationEnabled: bool
142
- cabinVentilationMode: str ("AUTO" | "MANUAL" | "OFF")
147
+ cabinVentilationMode: str | None ("AUTO" | "MANUAL" | "OFF")
143
148
  cabinVentilationWindowsPosition: int (percent open)
144
149
  cabinVentilationSunroofPosition: int (percent open)
145
150
  cabinVentilationDuration: int (minutes)
146
151
  """
147
- result: dict[str, Any] = {}
148
- for field, key in (
149
- ("enabled", "cabinVentilationEnabled"),
150
- ("mode", "cabinVentilationMode"),
151
- ("windows_position", "cabinVentilationWindowsPosition"),
152
- ("sunroof_position", "cabinVentilationSunroofPosition"),
153
- ("duration", "cabinVentilationDuration"),
154
- ):
155
- if (v := _present(m, field)) is not None:
156
- result[key] = v
157
- return result
152
+ return {
153
+ "cabinVentilationEnabled": m.enabled,
154
+ "cabinVentilationMode": m.mode or None,
155
+ "cabinVentilationWindowsPosition": m.windows_position,
156
+ "cabinVentilationSunroofPosition": m.sunroof_position,
157
+ "cabinVentilationDuration": m.duration,
158
+ }
158
159
 
159
160
 
160
161
  @RVMDecoder.register(
@@ -176,29 +177,26 @@ def decode_climate_hold_status(m: comfort_pb2.ClimateHoldStatus) -> dict[str, An
176
177
  Fields:
177
178
  climateHoldStatus: str ("off" | "on" | "unavailable" | "fault" | "unspecified")
178
179
  climateHoldAvailability: str
179
- climateHoldUnavailabilityReason: str (only when not "unspecified")
180
- climateHoldEndTime: int (epoch seconds, only while a hold runs)
180
+ climateHoldUnavailabilityReason: str | None — None when unspecified
181
+ climateHoldEndTime: int | None (epoch seconds; None unless a hold runs)
181
182
  """
182
- result: dict[str, Any] = {}
183
- if (val := _present(m, "status")) is not None:
184
- result["climateHoldStatus"] = _enum(
185
- _CLIMATE_HOLD_STATUS_MAP, val, what="climate hold status"
186
- )
187
- if (val := _present(m, "availability")) is not None:
188
- result["climateHoldAvailability"] = _enum(
189
- _CLIMATE_HOLD_AVAILABILITY_MAP, val, what="climate hold availability"
190
- )
191
- if (val := _present(m, "unavailability_reason")) is not None:
192
- reason = _enum(
193
- _CLIMATE_HOLD_UNAVAILABILITY_REASON_MAP,
194
- val,
195
- what="climate hold unavailability reason",
196
- )
197
- if reason != "unspecified":
198
- result["climateHoldUnavailabilityReason"] = reason
199
- if m.end_time.seconds:
200
- result["climateHoldEndTime"] = m.end_time.seconds
201
- return result
183
+ reason = _enum(
184
+ _CLIMATE_HOLD_UNAVAILABILITY_REASON_MAP,
185
+ m.unavailability_reason,
186
+ what="climate hold unavailability reason",
187
+ )
188
+ return {
189
+ "climateHoldStatus": _enum(
190
+ _CLIMATE_HOLD_STATUS_MAP, m.status, what="climate hold status"
191
+ ),
192
+ "climateHoldAvailability": _enum(
193
+ _CLIMATE_HOLD_AVAILABILITY_MAP,
194
+ m.availability,
195
+ what="climate hold availability",
196
+ ),
197
+ "climateHoldUnavailabilityReason": None if reason == "unspecified" else reason,
198
+ "climateHoldEndTime": m.end_time.seconds or None,
199
+ }
202
200
 
203
201
 
204
202
  @RVMDecoder.register(
@@ -247,23 +245,22 @@ def decode_seat_conditioning(m: comfort_pb2.SeatConditioningStatus) -> dict[str,
247
245
  seatThirdRowLeftHeat, seatThirdRowRightHeat: str
248
246
  ("Off" | "Level_1" | "Level_2" | "Level_3")
249
247
  steeringWheelHeat: str ("Off" | "Level_1")
248
+ plus <surface>Heat/Vent for any other surface sent (middle seats,
249
+ rearGlass, frontGlass, sideviewMirrors, wiperArea)
250
250
 
251
- Entries without a state are skipped.
251
+ A surface sent without a state is off.
252
252
  """
253
253
  result: dict[str, Any] = {}
254
- for s in m.seat:
255
- cid, hvac_type = s.id, s.type
256
- if (state_val := _present(s, "state")) is None:
257
- continue
258
- if cid in _SEAT_CONDITIONING_MAP and hvac_type in _SEAT_CONDITIONING_TYPE_MAP:
259
- key = (
260
- f"{_SEAT_CONDITIONING_MAP[cid]}{_SEAT_CONDITIONING_TYPE_MAP[hvac_type]}"
261
- )
262
- result[key] = _SEAT_CONDITIONING_STATUS_MAP.get(state_val, state_val)
254
+ for surface in m.surface:
255
+ surface_id, hvac_type = surface.id, surface.type
256
+ state_val = _present(surface, "state")
257
+ if surface_id in _CABIN_SURFACE_MAP and hvac_type in _CONDITIONING_TYPE_MAP:
258
+ key = f"{_CABIN_SURFACE_MAP[surface_id]}{_CONDITIONING_TYPE_MAP[hvac_type]}"
259
+ result[key] = _CONDITIONING_LEVEL_MAP.get(state_val, state_val)
263
260
  else:
264
261
  _LOGGER.debug(
265
- "Unknown seat conditioning status id %s (hvac_type %s; state %s)",
266
- cid,
262
+ "Unknown cabin surface %s (hvac_type %s; state %s)",
263
+ surface_id,
267
264
  hvac_type,
268
265
  state_val,
269
266
  )