rivian-python-client 2.1.0b0__py3-none-any.whl → 2.2.0__py3-none-any.whl

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 (88) hide show
  1. rivian/__version__.py +1 -1
  2. rivian/parallax/__init__.py +70 -0
  3. rivian/parallax/body.py +260 -0
  4. rivian/parallax/charging.py +407 -0
  5. rivian/parallax/comfort.py +317 -0
  6. rivian/parallax/core.py +163 -0
  7. rivian/parallax/departure.py +105 -0
  8. rivian/parallax/device_table.py +136 -0
  9. rivian/parallax/dynamics.py +288 -0
  10. rivian/parallax/energy.py +148 -0
  11. rivian/parallax/energy_edge_compute.py +193 -0
  12. rivian/parallax/gearguard_streaming.py +66 -0
  13. rivian/parallax/geofence.py +35 -0
  14. rivian/parallax/holiday_celebration.py +193 -0
  15. rivian/parallax/navigation.py +377 -0
  16. rivian/parallax/ota.py +242 -0
  17. rivian/parallax/parallax.py +33 -0
  18. rivian/parallax/proto/__init__.py +8 -0
  19. rivian/parallax/proto/body.proto +268 -0
  20. rivian/parallax/proto/body_pb2.py +84 -0
  21. rivian/parallax/proto/body_pb2.pyi +436 -0
  22. rivian/parallax/proto/charging.proto +239 -0
  23. rivian/parallax/proto/charging_pb2.py +86 -0
  24. rivian/parallax/proto/charging_pb2.pyi +361 -0
  25. rivian/parallax/proto/comfort.proto +190 -0
  26. rivian/parallax/proto/comfort_pb2.py +84 -0
  27. rivian/parallax/proto/comfort_pb2.pyi +287 -0
  28. rivian/parallax/proto/departure.proto +78 -0
  29. rivian/parallax/proto/departure_pb2.py +54 -0
  30. rivian/parallax/proto/departure_pb2.pyi +115 -0
  31. rivian/parallax/proto/device_table.proto +111 -0
  32. rivian/parallax/proto/device_table_pb2.py +60 -0
  33. rivian/parallax/proto/device_table_pb2.pyi +162 -0
  34. rivian/parallax/proto/dynamics.proto +158 -0
  35. rivian/parallax/proto/dynamics_pb2.py +74 -0
  36. rivian/parallax/proto/dynamics_pb2.pyi +238 -0
  37. rivian/parallax/proto/energy.proto +97 -0
  38. rivian/parallax/proto/energy_edge_compute.proto +93 -0
  39. rivian/parallax/proto/energy_edge_compute_pb2.py +53 -0
  40. rivian/parallax/proto/energy_edge_compute_pb2.pyi +138 -0
  41. rivian/parallax/proto/energy_pb2.py +58 -0
  42. rivian/parallax/proto/energy_pb2.pyi +148 -0
  43. rivian/parallax/proto/gearguard_streaming.proto +29 -0
  44. rivian/parallax/proto/gearguard_streaming_pb2.py +42 -0
  45. rivian/parallax/proto/gearguard_streaming_pb2.pyi +40 -0
  46. rivian/parallax/proto/geofence.proto +21 -0
  47. rivian/parallax/proto/geofence_pb2.py +40 -0
  48. rivian/parallax/proto/geofence_pb2.pyi +30 -0
  49. rivian/parallax/proto/holiday_celebration.proto +86 -0
  50. rivian/parallax/proto/holiday_celebration_pb2.py +56 -0
  51. rivian/parallax/proto/holiday_celebration_pb2.pyi +128 -0
  52. rivian/parallax/proto/navigation.proto +201 -0
  53. rivian/parallax/proto/navigation_pb2.py +76 -0
  54. rivian/parallax/proto/navigation_pb2.pyi +312 -0
  55. rivian/parallax/proto/ota.proto +173 -0
  56. rivian/parallax/proto/ota_pb2.py +78 -0
  57. rivian/parallax/proto/ota_pb2.pyi +253 -0
  58. rivian/parallax/proto/parallax.proto +17 -0
  59. rivian/parallax/proto/parallax_pb2.py +38 -0
  60. rivian/parallax/proto/parallax_pb2.pyi +23 -0
  61. rivian/parallax/proto/secure_file_transfer.proto +9 -0
  62. rivian/parallax/proto/secure_file_transfer_pb2.py +36 -0
  63. rivian/parallax/proto/secure_file_transfer_pb2.pyi +9 -0
  64. rivian/parallax/proto/security.proto +131 -0
  65. rivian/parallax/proto/security_pb2.py +68 -0
  66. rivian/parallax/proto/security_pb2.pyi +198 -0
  67. rivian/parallax/proto/user_passcodes.proto +17 -0
  68. rivian/parallax/proto/user_passcodes_pb2.py +38 -0
  69. rivian/parallax/proto/user_passcodes_pb2.pyi +21 -0
  70. rivian/parallax/proto/vehicle.proto +165 -0
  71. rivian/parallax/proto/vehicle_access.proto +30 -0
  72. rivian/parallax/proto/vehicle_access_pb2.py +42 -0
  73. rivian/parallax/proto/vehicle_access_pb2.pyi +38 -0
  74. rivian/parallax/proto/vehicle_pb2.py +72 -0
  75. rivian/parallax/proto/vehicle_pb2.pyi +259 -0
  76. rivian/parallax/secure_file_transfer.py +19 -0
  77. rivian/parallax/security.py +224 -0
  78. rivian/parallax/user_passcodes.py +32 -0
  79. rivian/parallax/vehicle.py +240 -0
  80. rivian/parallax/vehicle_access.py +68 -0
  81. rivian/rivian.py +20 -9
  82. rivian/utils.py +17 -0
  83. rivian/ws_monitor.py +31 -0
  84. {rivian_python_client-2.1.0b0.dist-info → rivian_python_client-2.2.0.dist-info}/METADATA +29 -2
  85. rivian_python_client-2.2.0.dist-info/RECORD +94 -0
  86. {rivian_python_client-2.1.0b0.dist-info → rivian_python_client-2.2.0.dist-info}/WHEEL +1 -1
  87. rivian/parallax.py +0 -624
  88. rivian_python_client-2.1.0b0.dist-info/RECORD +0 -16
rivian/__version__.py CHANGED
@@ -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.1.0b0'
4
+ __version__ = VERSION = '2.2.0'
@@ -0,0 +1,70 @@
1
+ """Decoders for Rivian Parallax protobuf payloads.
2
+
3
+ Public API:
4
+ decode_parallax_message(rvm, payload, timestamp=None, **kwargs) -> dict | None
5
+ Adds `timestamp` (epoch milliseconds) as a UTC datetime if given.
6
+ decode_parallax_subscription_message(data) -> dict | None
7
+ Same, for a raw `subscribe_for_parallax_messages` message.
8
+ PARALLAX_RVMS: list[str] — every RVM with a registered decoder
9
+ CHARGING_RVMS: list[str] — the subset relevant to a charging session
10
+
11
+ Layout:
12
+ core.py - registry, payload parsing and shared helpers
13
+ proto/ - .proto schemas and their generated *_pb2 modules
14
+ <topic prefix>.py - one module per RVM topic prefix (body.*, etc.)
15
+
16
+ To add a decoder, decorate it with
17
+ `@RVMDecoder.register("the.rvm.topic", some_pb2.Message)` in its prefix's
18
+ module; a new module also needs adding to the import list below.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from . import ( # noqa: F401 (imported to register their decoders)
24
+ body,
25
+ charging,
26
+ comfort,
27
+ departure,
28
+ device_table,
29
+ dynamics,
30
+ energy,
31
+ energy_edge_compute,
32
+ gearguard_streaming,
33
+ geofence,
34
+ holiday_celebration,
35
+ navigation,
36
+ ota,
37
+ parallax,
38
+ secure_file_transfer,
39
+ security,
40
+ user_passcodes,
41
+ vehicle,
42
+ vehicle_access,
43
+ )
44
+ from .core import (
45
+ RVMDecoder,
46
+ decode_parallax_message,
47
+ decode_parallax_subscription_message,
48
+ )
49
+
50
+ PARALLAX_RVMS: list[str] = list(RVMDecoder.decoders)
51
+
52
+ CHARGING_RVMS: list[str] = [
53
+ "charging.energy.state",
54
+ "charging.session.notification",
55
+ "charging.session.power",
56
+ "charging.session.remote_command",
57
+ "charging.session.soc_slider",
58
+ "charging.session.status",
59
+ "charging.session.time_estimation",
60
+ "energy.high_voltage.battery_state",
61
+ "energy_edge_compute.graphs.charge_session_breakdown",
62
+ "energy_edge_compute.graphs.charging_graph_global",
63
+ ]
64
+
65
+ __all__ = [
66
+ "CHARGING_RVMS",
67
+ "PARALLAX_RVMS",
68
+ "decode_parallax_message",
69
+ "decode_parallax_subscription_message",
70
+ ]
@@ -0,0 +1,260 @@
1
+ """Decoders for `body.*` RVM topics: closures, locks, trailer."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Final
6
+
7
+ from .core import _LOGGER, RVMDecoder, _enum, _present
8
+ from .proto import body_pb2
9
+
10
+ _CLOSURE_MAP: Final[dict[int, str]] = {
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",
27
+ }
28
+
29
+ _CLOSURE_STATE_MAP: Final[dict[int, str]] = {
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",
35
+ }
36
+
37
+
38
+ def _enum_names(enum: Any, prefix: str) -> dict[int, str]:
39
+ """Map an enum's numbers to its lowercased names, minus `prefix`."""
40
+ return {
41
+ value.number: value.name.removeprefix(prefix).lower()
42
+ for value in enum.DESCRIPTOR.values
43
+ }
44
+
45
+
46
+ _SIDE_BIN_NEXT_ACTIONS: Final = _enum_names(body_pb2.SideBinNextAction, "SIDE_BIN_")
47
+
48
+ # Closure id -> (next-action field, result key, value names).
49
+ _NEXT_ACTIONS: Final[dict[int, tuple[str, str, dict[int, str]]]] = {
50
+ body_pb2.FRUNK: (
51
+ "frunk_next_action",
52
+ "closureFrunkNextAction",
53
+ _enum_names(body_pb2.FrunkNextAction, "FRUNK_"),
54
+ ),
55
+ body_pb2.LIFTGATE: (
56
+ "liftgate_next_action",
57
+ "closureLiftgateNextAction",
58
+ _enum_names(body_pb2.LiftgateNextAction, "LIFTGATE_"),
59
+ ),
60
+ body_pb2.SIDE_BIN_LEFT: (
61
+ "side_bin_next_action",
62
+ "closureSideBinLeftNextAction",
63
+ _SIDE_BIN_NEXT_ACTIONS,
64
+ ),
65
+ body_pb2.SIDE_BIN_RIGHT: (
66
+ "side_bin_next_action",
67
+ "closureSideBinRightNextAction",
68
+ _SIDE_BIN_NEXT_ACTIONS,
69
+ ),
70
+ body_pb2.TAILGATE: (
71
+ "tailgate_next_action",
72
+ "closureTailgateNextAction",
73
+ _enum_names(body_pb2.TailgateNextAction, "TAILGATE_"),
74
+ ),
75
+ body_pb2.CHARGE_PORT: (
76
+ "charge_port_door_next_action",
77
+ "closureChargePortDoorNextAction",
78
+ _enum_names(body_pb2.ChargePortDoorNextAction, "CHARGE_PORT_DOOR_"),
79
+ ),
80
+ body_pb2.GROUP_WINDOWS: (
81
+ "windows_next_action",
82
+ "windowsNextAction",
83
+ _enum_names(body_pb2.WindowsNextAction, "WINDOWS_"),
84
+ ),
85
+ }
86
+
87
+ _LOCK_MAP: Final[dict[int, str]] = {
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",
109
+ }
110
+
111
+ _REAR_HITCH_STATUS_MAP: Final[dict[int, str]] = {
112
+ body_pb2.REAR_HITCH_STATUS_NOT_PRESENT: "not_present",
113
+ body_pb2.REAR_HITCH_STATUS_ACCESSORY: "accessory",
114
+ body_pb2.REAR_HITCH_STATUS_TRAILER1: "trailer1",
115
+ body_pb2.REAR_HITCH_STATUS_TRAILER2: "trailer2",
116
+ body_pb2.REAR_HITCH_STATUS_TRAILER3: "trailer3",
117
+ }
118
+
119
+ _WINDOW_MAP: Final[dict[int, str]] = {
120
+ body_pb2.WINDOW_INSTANCE_FRONT_LEFT: "windowFrontLeftCalibrated",
121
+ body_pb2.WINDOW_INSTANCE_FRONT_RIGHT: "windowFrontRightCalibrated",
122
+ body_pb2.WINDOW_INSTANCE_REAR_LEFT: "windowRearLeftCalibrated",
123
+ body_pb2.WINDOW_INSTANCE_REAR_RIGHT: "windowRearRightCalibrated",
124
+ body_pb2.WINDOW_INSTANCE_REAR: "windowRearCalibrated",
125
+ }
126
+
127
+ # GraphQL's windowXCalibrated values.
128
+ _CALIBRATION_MAP: Final[dict[int, str]] = {
129
+ body_pb2.CALIBRATION_STATUS_CALIBRATED: "calibrated",
130
+ body_pb2.CALIBRATION_STATUS_NOT_CALIBRATED: "not_calibrated",
131
+ }
132
+
133
+ _TRAILER_PRESENCE_MAP: Final[dict[int, str]] = {
134
+ body_pb2.TRAILER_NOT_PRESENT: "trailer_not_present",
135
+ body_pb2.TRAILER_PRESENT: "trailer_present",
136
+ body_pb2.TRAILER_PRESENT_WITH_BRAKES: "trailer_present_with_brakes",
137
+ body_pb2.TRAILER_INVALID: "trailer_invalid",
138
+ }
139
+
140
+
141
+ @RVMDecoder.register("body.closures.states", body_pb2.ClosuresState)
142
+ def decode_closures(m: body_pb2.ClosuresState) -> dict[str, Any]:
143
+ """body.closures.states — state of every door, window and closure.
144
+
145
+ Fields:
146
+ doorFrontLeftClosed, closureFrunkClosed, etc.: str
147
+ ("open" | "closed" | "ajar" | "opening" | "closing")
148
+ closureFrunkNextAction, closureLiftgateNextAction,
149
+ closureTailgateNextAction, closureSideBinLeftNextAction,
150
+ closureSideBinRightNextAction, closureChargePortDoorNextAction,
151
+ windowsNextAction: str — e.g. "open_allowed" (shut),
152
+ "close_allowed" (open); for the charge port,
153
+ "close_not_available" means plugged in
154
+
155
+ `chargePortState` can lag the door (e.g. "opening" until plugged in),
156
+ so prefer its next action. After an app command, next actions briefly
157
+ drop to "sna" / "open_not_available".
158
+ """
159
+ result: dict[str, Any] = {}
160
+ for s in m.closure:
161
+ cid = s.id
162
+ state_val = _present(s, "state")
163
+ if cid in _CLOSURE_MAP:
164
+ result[_CLOSURE_MAP[cid]] = _enum(
165
+ _CLOSURE_STATE_MAP, state_val, what="closure state"
166
+ )
167
+ elif cid != body_pb2.GROUP_WINDOWS:
168
+ _LOGGER.debug("Unknown closure id %s (state %s)", cid, state_val)
169
+ if cid in _NEXT_ACTIONS:
170
+ field, key, names = _NEXT_ACTIONS[cid]
171
+ if (next_action := _present(s, field)) is not None:
172
+ result[key] = _enum(names, next_action, what=f"{key} value")
173
+ return result
174
+
175
+
176
+ @RVMDecoder.register("body.locks.states", body_pb2.LocksState)
177
+ def decode_locks(m: body_pb2.LocksState) -> dict[str, Any]:
178
+ """body.locks.states — lock state of every lock.
179
+
180
+ Fields:
181
+ doorFrontLeftLocked, closureFrunkLocked, gearGuardLocked (the Gear
182
+ Guard cable), etc.: str ("locked" | "unlocked" |
183
+ "partially_unlocked")
184
+ """
185
+ result: dict[str, Any] = {}
186
+ for s in m.lock:
187
+ lid = s.id
188
+ state_val = _present(s, "state")
189
+ if state_val is None:
190
+ continue
191
+ if lid in _LOCK_MAP:
192
+ result[_LOCK_MAP[lid]] = _enum(
193
+ _LOCK_STATE_MAP, state_val, what="lock state"
194
+ )
195
+ else:
196
+ _LOGGER.debug("Unknown lock id %s (state %s)", lid, state_val)
197
+ return result
198
+
199
+
200
+ @RVMDecoder.register("body.windows.states", body_pb2.WindowsState)
201
+ def decode_windows(m: body_pb2.WindowsState) -> dict[str, Any]:
202
+ """body.windows.states — window calibration.
203
+
204
+ Fields:
205
+ windowFrontLeftCalibrated, windowFrontRightCalibrated,
206
+ windowRearLeftCalibrated, windowRearRightCalibrated,
207
+ windowRearCalibrated: str ("calibrated" | "not_calibrated")
208
+ """
209
+ return {
210
+ _WINDOW_MAP[w.instance]: _enum(
211
+ _CALIBRATION_MAP, w.calibration_status or None, what="window calibration"
212
+ )
213
+ for w in m.window
214
+ if w.instance in _WINDOW_MAP
215
+ }
216
+
217
+
218
+ @RVMDecoder.register("body.trailer.state", body_pb2.TrailerState)
219
+ def decode_trailer_state(m: body_pb2.TrailerState) -> dict[str, Any]:
220
+ """body.trailer.state — trailer presence and rear hitch status.
221
+
222
+ Fields:
223
+ trailerStatus: str
224
+ rearHitchStatus: str | None ("not_present" | "accessory" |
225
+ "trailer1" | "trailer2" | "trailer3")
226
+ """
227
+ result: dict[str, Any] = {
228
+ "rearHitchStatus": _enum(
229
+ _REAR_HITCH_STATUS_MAP, m.rear_hitch_status or None, what="rear hitch"
230
+ )
231
+ }
232
+ presence = _enum(
233
+ _TRAILER_PRESENCE_MAP, _present(m, "presence"), what="trailer presence"
234
+ )
235
+ if presence is not None:
236
+ result["trailerStatus"] = presence
237
+ return result
238
+
239
+
240
+ @RVMDecoder.register("body.wipers.fluid_level", body_pb2.WiperFluidLevel)
241
+ def decode_wiper_fluid_level(m: body_pb2.WiperFluidLevel) -> dict[str, Any]:
242
+ """body.wipers.fluid_level — washer fluid level.
243
+
244
+ The value numbering is a best guess.
245
+
246
+ Fields:
247
+ wiperFluidState: str | None ("normal" | "low" | "empty")
248
+ """
249
+ return {
250
+ "wiperFluidState": _enum(
251
+ _WIPER_FLUID_STATE_MAP, m.state or None, what="wiper fluid state"
252
+ )
253
+ }
254
+
255
+
256
+ _WIPER_FLUID_STATE_MAP: Final[dict[int, str]] = {
257
+ body_pb2.WIPER_FLUID_STATE_NORMAL: "normal",
258
+ body_pb2.WIPER_FLUID_STATE_LOW: "low",
259
+ body_pb2.WIPER_FLUID_STATE_EMPTY: "empty",
260
+ }