rivian-python-client 2.3.0__tar.gz → 2.4.0__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.
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/PKG-INFO +42 -1
- rivian_python_client-2.4.0/README.md +93 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/pyproject.toml +4 -1
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/__version__.py +1 -1
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/ble.py +2 -2
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/const.py +2 -2
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/__init__.py +18 -2
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/body.py +13 -0
- rivian_python_client-2.4.0/src/rivian/parallax/command.py +168 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/core.py +11 -6
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/departure.py +16 -6
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/navigation.py +7 -3
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/body.proto +11 -0
- rivian_python_client-2.4.0/src/rivian/parallax/proto/body_pb2.py +88 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/body_pb2.pyi +12 -0
- rivian_python_client-2.4.0/src/rivian/parallax/proto/command.proto +108 -0
- rivian_python_client-2.4.0/src/rivian/parallax/proto/command_pb2.py +62 -0
- rivian_python_client-2.4.0/src/rivian/parallax/proto/command_pb2.pyi +151 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/departure.proto +12 -0
- rivian_python_client-2.4.0/src/rivian/parallax/proto/departure_pb2.py +58 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/departure_pb2.pyi +16 -2
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/rivian.py +233 -71
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/utils.py +32 -3
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/ws_monitor.py +179 -33
- rivian_python_client-2.3.0/README.md +0 -52
- rivian_python_client-2.3.0/src/rivian/parallax/proto/body_pb2.py +0 -84
- rivian_python_client-2.3.0/src/rivian/parallax/proto/departure_pb2.py +0 -54
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/.gitignore +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/__init__.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/exceptions.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/charging.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/comfort.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/device_table.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/dynamics.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/energy.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/energy_edge_compute.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/gearguard_streaming.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/geofence.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/holiday_celebration.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/operation.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/ota.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/parallax.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/__init__.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/charging.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/charging_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/charging_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/comfort.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/comfort_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/comfort_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/device_table.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/device_table_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/device_table_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/dynamics.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/dynamics_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/dynamics_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/energy.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/energy_edge_compute.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/energy_edge_compute_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/energy_edge_compute_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/energy_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/energy_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/gearguard_streaming.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/gearguard_streaming_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/gearguard_streaming_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/geofence.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/geofence_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/geofence_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/holiday_celebration.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/holiday_celebration_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/holiday_celebration_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/navigation.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/navigation_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/navigation_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/operation.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/operation_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/operation_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/ota.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/ota_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/ota_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/parallax.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/parallax_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/parallax_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/secure_file_transfer.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/secure_file_transfer_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/secure_file_transfer_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/security.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/security_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/security_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/user_passcodes.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/user_passcodes_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/user_passcodes_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/vehicle.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/vehicle_access.proto +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/vehicle_access_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/vehicle_access_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/vehicle_pb2.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/vehicle_pb2.pyi +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/secure_file_transfer.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/security.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/user_passcodes.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/vehicle.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/vehicle_access.py +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/py.typed +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/schemas/charging.graphql +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/schemas/gateway.graphql +0 -0
- {rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/schemas/orders.graphql +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: rivian-python-client
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
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
|
|
@@ -65,3 +65,44 @@ editing one, regenerate its `*_pb2` modules (don't edit those by hand):
|
|
|
65
65
|
uv run python -m grpc_tools.protoc --proto_path=src --python_out=src \
|
|
66
66
|
--pyi_out=src src/rivian/parallax/proto/*.proto
|
|
67
67
|
```
|
|
68
|
+
|
|
69
|
+
### Commands
|
|
70
|
+
|
|
71
|
+
`send_parallax_command` sends a signed command, such as unlocking
|
|
72
|
+
(`parallax.UNLOCK_RVM` with `parallax.encode_unlock()`; `LOCK_RVM` and
|
|
73
|
+
`encode_lock()` to lock), and `subscribe_for_parallax_command_state` follows it.
|
|
74
|
+
Subscribe first, then send:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
import uuid
|
|
78
|
+
|
|
79
|
+
from rivian import parallax
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def on_state(data):
|
|
83
|
+
if state := parallax.decode_command_state_message(data):
|
|
84
|
+
print(state["progress"], state["status"], state["error"])
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
command_id = str(uuid.uuid4())
|
|
88
|
+
unsubscribe = await rivian.subscribe_for_parallax_command_state(
|
|
89
|
+
vehicle_id, command_id, on_state
|
|
90
|
+
)
|
|
91
|
+
if unsubscribe:
|
|
92
|
+
await rivian.send_parallax_command(
|
|
93
|
+
vehicle_id,
|
|
94
|
+
parallax.UNLOCK_RVM,
|
|
95
|
+
parallax.encode_unlock(),
|
|
96
|
+
identity_id=identity_id,
|
|
97
|
+
vehicle_key=vehicle_key,
|
|
98
|
+
private_key=private_key,
|
|
99
|
+
command_id=command_id,
|
|
100
|
+
)
|
|
101
|
+
... # wait for the progress "complete", or give up
|
|
102
|
+
await unsubscribe()
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The keys are those of `send_vehicle_command`. The command is done when the progress
|
|
106
|
+
is `complete`, the status `success` and there is no `error`. If you never see that,
|
|
107
|
+
check the vehicle before sending it again. This unlocks a real vehicle, so keep the
|
|
108
|
+
keys secret.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Python: Rivian API Client
|
|
2
|
+
|
|
3
|
+
Currently a Work In Progress
|
|
4
|
+
|
|
5
|
+
## Dependencies
|
|
6
|
+
|
|
7
|
+
[uv](https://docs.astral.sh/uv/)
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
14
|
+
|
|
15
|
+
Install project dependencies into the uv virtual environment and run pre-commit
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
uv sync --all-extras
|
|
19
|
+
pre-commit install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Run Tests
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
uv run pytest
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Parallax
|
|
29
|
+
|
|
30
|
+
`subscribe_for_parallax_messages` streams the vehicle's Parallax RVM topics,
|
|
31
|
+
whose payloads are protobuf. `rivian.parallax` decodes them into dicts keyed
|
|
32
|
+
like the GraphQL vehicle state where a matching property exists:
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from rivian import parallax
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def on_message(data):
|
|
39
|
+
if decoded := parallax.decode_parallax_subscription_message(data):
|
|
40
|
+
print(decoded)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`parallax.PARALLAX_RVMS` lists every topic with a decoder, and
|
|
44
|
+
`parallax.CHARGING_RVMS` the ones relevant to a charging session.
|
|
45
|
+
|
|
46
|
+
The schemas in `src/rivian/parallax/proto/*.proto` are reverse-engineered. After
|
|
47
|
+
editing one, regenerate its `*_pb2` modules (don't edit those by hand):
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
uv run python -m grpc_tools.protoc --proto_path=src --python_out=src \
|
|
51
|
+
--pyi_out=src src/rivian/parallax/proto/*.proto
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Commands
|
|
55
|
+
|
|
56
|
+
`send_parallax_command` sends a signed command, such as unlocking
|
|
57
|
+
(`parallax.UNLOCK_RVM` with `parallax.encode_unlock()`; `LOCK_RVM` and
|
|
58
|
+
`encode_lock()` to lock), and `subscribe_for_parallax_command_state` follows it.
|
|
59
|
+
Subscribe first, then send:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
import uuid
|
|
63
|
+
|
|
64
|
+
from rivian import parallax
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def on_state(data):
|
|
68
|
+
if state := parallax.decode_command_state_message(data):
|
|
69
|
+
print(state["progress"], state["status"], state["error"])
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
command_id = str(uuid.uuid4())
|
|
73
|
+
unsubscribe = await rivian.subscribe_for_parallax_command_state(
|
|
74
|
+
vehicle_id, command_id, on_state
|
|
75
|
+
)
|
|
76
|
+
if unsubscribe:
|
|
77
|
+
await rivian.send_parallax_command(
|
|
78
|
+
vehicle_id,
|
|
79
|
+
parallax.UNLOCK_RVM,
|
|
80
|
+
parallax.encode_unlock(),
|
|
81
|
+
identity_id=identity_id,
|
|
82
|
+
vehicle_key=vehicle_key,
|
|
83
|
+
private_key=private_key,
|
|
84
|
+
command_id=command_id,
|
|
85
|
+
)
|
|
86
|
+
... # wait for the progress "complete", or give up
|
|
87
|
+
await unsubscribe()
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The keys are those of `send_vehicle_command`. The command is done when the progress
|
|
91
|
+
is `complete`, the status `success` and there is no `error`. If you never see that,
|
|
92
|
+
check the vehicle before sending it again. This unlocks a real vehicle, so keep the
|
|
93
|
+
keys secret.
|
|
@@ -30,9 +30,12 @@ dev = [
|
|
|
30
30
|
"python-dotenv>=1.0,<1.3",
|
|
31
31
|
"aresponses>=3.0,<4.0",
|
|
32
32
|
"mypy>=1.7,<3.0",
|
|
33
|
-
"ruff>=0.16,<0.
|
|
33
|
+
"ruff>=0.16,<0.18",
|
|
34
34
|
"pre-commit>=4.6.1,<5",
|
|
35
35
|
"types-protobuf>=6.32.1.20260221",
|
|
36
|
+
# Generates the committed *_pb2 modules. Newer releases emit protobuf 7.x
|
|
37
|
+
# gencode, which won't import on the protobuf 6.32 that Home Assistant
|
|
38
|
+
# 2026.9 pins, so bump this only with the minimum supported HA version.
|
|
36
39
|
"grpcio-tools==1.80.0",
|
|
37
40
|
"pytest-cov>=7.0,<8",
|
|
38
41
|
]
|
|
@@ -7,7 +7,7 @@ import logging
|
|
|
7
7
|
import platform
|
|
8
8
|
import secrets
|
|
9
9
|
|
|
10
|
-
from .utils import
|
|
10
|
+
from .utils import generate_command_hmac
|
|
11
11
|
|
|
12
12
|
_LOGGER = logging.getLogger(__name__)
|
|
13
13
|
|
|
@@ -96,7 +96,7 @@ async def pair_phone(
|
|
|
96
96
|
|
|
97
97
|
_LOGGER.debug("Exchanging nonce")
|
|
98
98
|
phone_nonce = secrets.token_bytes(16)
|
|
99
|
-
hmac =
|
|
99
|
+
hmac = generate_command_hmac(phone_nonce, vehicle_key, private_key)
|
|
100
100
|
await client.write_gatt_char(
|
|
101
101
|
PHONE_NONCE_VEHICLE_NONCE_UUID, phone_nonce + hmac
|
|
102
102
|
)
|
|
@@ -185,8 +185,8 @@ class VehicleCommand(StrEnum):
|
|
|
185
185
|
VEHICLE_CABIN_PRECONDITION_DISABLE = "VEHICLE_CABIN_PRECONDITION_DISABLE"
|
|
186
186
|
VEHICLE_CABIN_PRECONDITION_ENABLE = "VEHICLE_CABIN_PRECONDITION_ENABLE"
|
|
187
187
|
# Gen2 HVAC Controls
|
|
188
|
-
|
|
189
|
-
|
|
188
|
+
CABIN_HVAC_3RD_ROW_REAR_LEFT_SEAT_HEAT = "CABIN_HVAC_3RD_ROW_REAR_LEFT_SEAT_HEAT"
|
|
189
|
+
CABIN_HVAC_3RD_ROW_REAR_RIGHT_SEAT_HEAT = "CABIN_HVAC_3RD_ROW_REAR_RIGHT_SEAT_HEAT"
|
|
190
190
|
|
|
191
191
|
# Closures
|
|
192
192
|
LOCK_ALL_CLOSURES_FEEDBACK = "LOCK_ALL_CLOSURES_FEEDBACK"
|
|
@@ -10,10 +10,18 @@ Public API:
|
|
|
10
10
|
encode_vehicle_operation(rvm, payload=b"", ...) -> str
|
|
11
11
|
Builds a `send_vehicle_operation` request; an empty payload reads
|
|
12
12
|
the RVM, anything else (e.g. `encode_climate_hold_setting`) writes it.
|
|
13
|
+
encode_command(vehicle_id, rvm, payload, ...) -> str
|
|
14
|
+
Builds and signs a `send_parallax_command` request, with a payload
|
|
15
|
+
such as `encode_unlock()`.
|
|
16
|
+
LOCK_RVM / encode_lock(), UNLOCK_RVM / encode_unlock()
|
|
17
|
+
The RVM and payload of a signed lock or unlock command.
|
|
18
|
+
decode_command_state_message(data) -> dict | None
|
|
19
|
+
Reads a raw `subscribe_for_parallax_command_state` message.
|
|
13
20
|
|
|
14
21
|
Layout:
|
|
15
|
-
core.py
|
|
16
|
-
|
|
22
|
+
core.py - registry, payload parsing and shared helpers
|
|
23
|
+
command.py - signed remote commands and their state messages
|
|
24
|
+
proto/ - .proto schemas and their generated *_pb2 modules
|
|
17
25
|
<topic prefix>.py - one module per RVM topic prefix (body.*, etc.)
|
|
18
26
|
|
|
19
27
|
To add a decoder, decorate it with
|
|
@@ -44,11 +52,13 @@ from . import ( # noqa: F401 (imported to register their decoders)
|
|
|
44
52
|
vehicle,
|
|
45
53
|
vehicle_access,
|
|
46
54
|
)
|
|
55
|
+
from .body import LOCK_RVM, UNLOCK_RVM, encode_lock, encode_unlock
|
|
47
56
|
from .comfort import (
|
|
48
57
|
CLIMATE_HOLD_SETTING_RVM,
|
|
49
58
|
CLIMATE_HOLD_STATUS_RVM,
|
|
50
59
|
encode_climate_hold_setting,
|
|
51
60
|
)
|
|
61
|
+
from .command import decode_command_state_message, encode_command
|
|
52
62
|
from .core import (
|
|
53
63
|
RVMDecoder,
|
|
54
64
|
decode_parallax_message,
|
|
@@ -75,9 +85,15 @@ __all__ = [
|
|
|
75
85
|
"CHARGING_RVMS",
|
|
76
86
|
"CLIMATE_HOLD_SETTING_RVM",
|
|
77
87
|
"CLIMATE_HOLD_STATUS_RVM",
|
|
88
|
+
"LOCK_RVM",
|
|
78
89
|
"PARALLAX_RVMS",
|
|
90
|
+
"UNLOCK_RVM",
|
|
91
|
+
"decode_command_state_message",
|
|
79
92
|
"decode_parallax_message",
|
|
80
93
|
"decode_parallax_subscription_message",
|
|
81
94
|
"encode_climate_hold_setting",
|
|
95
|
+
"encode_command",
|
|
96
|
+
"encode_lock",
|
|
97
|
+
"encode_unlock",
|
|
82
98
|
"encode_vehicle_operation",
|
|
83
99
|
]
|
|
@@ -7,6 +7,9 @@ from typing import Any, Final
|
|
|
7
7
|
from .core import _LOGGER, RVMDecoder, _enum, _present
|
|
8
8
|
from .proto import body_pb2
|
|
9
9
|
|
|
10
|
+
LOCK_RVM: Final = "body.locks.lock"
|
|
11
|
+
UNLOCK_RVM: Final = "body.locks.unlock"
|
|
12
|
+
|
|
10
13
|
_CLOSURE_MAP: Final[dict[int, str]] = {
|
|
11
14
|
body_pb2.DOOR_FRONT_LEFT: "doorFrontLeftClosed",
|
|
12
15
|
body_pb2.DOOR_FRONT_RIGHT: "doorFrontRightClosed",
|
|
@@ -173,6 +176,16 @@ def decode_closures(m: body_pb2.ClosuresState) -> dict[str, Any]:
|
|
|
173
176
|
return result
|
|
174
177
|
|
|
175
178
|
|
|
179
|
+
def encode_lock() -> bytes:
|
|
180
|
+
"""Encode a body.locks.lock payload, which has no fields."""
|
|
181
|
+
return body_pb2.LockCommand().SerializeToString()
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def encode_unlock() -> bytes:
|
|
185
|
+
"""Encode a body.locks.unlock payload that unlocks everything."""
|
|
186
|
+
return body_pb2.UnlockCommand(all=True).SerializeToString()
|
|
187
|
+
|
|
188
|
+
|
|
176
189
|
@RVMDecoder.register("body.locks.states", body_pb2.LocksState)
|
|
177
190
|
def decode_locks(m: body_pb2.LocksState) -> dict[str, Any]:
|
|
178
191
|
"""body.locks.states — lock state of every lock.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""Encoder and decoder for signed Parallax remote commands.
|
|
2
|
+
|
|
3
|
+
A command such as `body.locks.unlock` is sent with the `sendParallaxPayload`
|
|
4
|
+
mutation (`Rivian.send_parallax_command`). Its payload is an `Operation` in an
|
|
5
|
+
`Envelope`, signed with the secret that `Rivian.send_vehicle_command` derives from
|
|
6
|
+
the phone's key and the vehicle's, but over the operation's bytes. In testing,
|
|
7
|
+
Rivian woke a sleeping vehicle for it.
|
|
8
|
+
|
|
9
|
+
The `vehicleCommandStatePx` subscription
|
|
10
|
+
(`Rivian.subscribe_for_parallax_command_state`) reports on the command as it
|
|
11
|
+
goes: the vehicle waking up, validating and executing it, then the result.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import base64
|
|
17
|
+
import time
|
|
18
|
+
import uuid
|
|
19
|
+
from typing import Any, Final
|
|
20
|
+
|
|
21
|
+
from google.protobuf.message import DecodeError
|
|
22
|
+
|
|
23
|
+
from ..utils import generate_command_hmac
|
|
24
|
+
from .core import _LOGGER, _debug_message, _enum, _present
|
|
25
|
+
from .proto import command_pb2
|
|
26
|
+
|
|
27
|
+
_PROGRESS_MAP: Final[dict[int, str]] = {
|
|
28
|
+
command_pb2.VEHICLE_MODEL_OP_PROGRESS_UNSPECIFIED: "unspecified",
|
|
29
|
+
command_pb2.VEHICLE_MODEL_OP_PROGRESS_VEHICLE_WAKING_UP: "waking_up",
|
|
30
|
+
command_pb2.VEHICLE_MODEL_OP_PROGRESS_VEHICLE_VALIDATING: "validating",
|
|
31
|
+
command_pb2.VEHICLE_MODEL_OP_PROGRESS_VEHICLE_EXECUTING: "executing",
|
|
32
|
+
command_pb2.VEHICLE_MODEL_OP_PROGRESS_VEHICLE_COMPLETE: "complete",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
_STATUS_MAP: Final[dict[int, str]] = {
|
|
36
|
+
command_pb2.RESPONSE_STATUS_UNDEFINED: "undefined",
|
|
37
|
+
command_pb2.RESPONSE_STATUS_SUCCESS: "success",
|
|
38
|
+
command_pb2.RESPONSE_STATUS_FAIL: "failed",
|
|
39
|
+
command_pb2.RESPONSE_STATUS_INVALID_REQUEST: "invalid_request",
|
|
40
|
+
command_pb2.RESPONSE_STATUS_NOT_SUPPORTED: "not_supported",
|
|
41
|
+
command_pb2.RESPONSE_STATUS_TIMEOUT: "timeout",
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def encode_command(
|
|
46
|
+
vehicle_id: str,
|
|
47
|
+
rvm: str,
|
|
48
|
+
payload: bytes,
|
|
49
|
+
*,
|
|
50
|
+
identity_id: str,
|
|
51
|
+
vehicle_key: str,
|
|
52
|
+
private_key: str,
|
|
53
|
+
command_id: str | None = None,
|
|
54
|
+
timestamp: float | None = None,
|
|
55
|
+
) -> str:
|
|
56
|
+
"""Encode and sign a command, as the payload of `sendParallaxPayload`.
|
|
57
|
+
|
|
58
|
+
`payload` is the RVM's message, e.g. `encode_unlock()` for `UNLOCK_RVM`;
|
|
59
|
+
nothing checks that they go together. `identity_id`, `vehicle_key` and
|
|
60
|
+
`private_key` are the ones `send_vehicle_command` takes. The command id, a
|
|
61
|
+
UUID, is a new one unless `command_id` is given (`ValueError` if it isn't
|
|
62
|
+
one); `timestamp` is epoch milliseconds, now unless given.
|
|
63
|
+
|
|
64
|
+
The result is signed and can be replayed until the vehicle rejects its
|
|
65
|
+
timestamp, so treat it as a secret.
|
|
66
|
+
"""
|
|
67
|
+
command_id_bytes = (
|
|
68
|
+
uuid.uuid4().bytes if command_id is None else uuid.UUID(command_id).bytes
|
|
69
|
+
)
|
|
70
|
+
timestamp_ms = int(time.time() * 1000 if timestamp is None else timestamp)
|
|
71
|
+
stamp = command_pb2.Timestamp(
|
|
72
|
+
seconds=timestamp_ms // 1000, nanos=timestamp_ms % 1000 * 1_000_000
|
|
73
|
+
)
|
|
74
|
+
operation = command_pb2.Operation(
|
|
75
|
+
rvm=rvm,
|
|
76
|
+
type=command_pb2.PARALLAX_OPERATION_REQUEST,
|
|
77
|
+
command_id=command_id_bytes,
|
|
78
|
+
payload=payload,
|
|
79
|
+
created_at=stamp,
|
|
80
|
+
vehicle_id=vehicle_id,
|
|
81
|
+
).SerializeToString()
|
|
82
|
+
envelope = command_pb2.Envelope(
|
|
83
|
+
composite=command_pb2.Composite(bytes_val=operation),
|
|
84
|
+
last_update=stamp,
|
|
85
|
+
correlation_id=command_id_bytes,
|
|
86
|
+
security_info=command_pb2.SecurityInfo(
|
|
87
|
+
signature=command_pb2.Signature(
|
|
88
|
+
type=command_pb2.DATA_SIGNATURE_TYPE_HMAC_SHA256,
|
|
89
|
+
# The raw HMAC-SHA256 of the data, as BLE commands use too
|
|
90
|
+
value=generate_command_hmac(operation, vehicle_key, private_key),
|
|
91
|
+
),
|
|
92
|
+
mapped_identity=identity_id,
|
|
93
|
+
),
|
|
94
|
+
)
|
|
95
|
+
return base64.b64encode(envelope.SerializeToString()).decode("utf-8")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def decode_command_state(payload: str) -> dict[str, Any] | None:
|
|
99
|
+
"""Decode the payload of a `vehicleCommandStatePx` message.
|
|
100
|
+
|
|
101
|
+
Returns None if the payload is empty or can't be read.
|
|
102
|
+
|
|
103
|
+
Fields:
|
|
104
|
+
commandId: str | None — the command's UUID
|
|
105
|
+
rvm: str
|
|
106
|
+
progress: str | int — "unspecified" | "waking_up" | "validating" |
|
|
107
|
+
"executing" | "complete". Any of the ones before "complete" can be
|
|
108
|
+
skipped, and "waking_up" has come more than once for one command.
|
|
109
|
+
status: str | int | None — how the vehicle answered ("undefined" |
|
|
110
|
+
"success" | "failed" | "invalid_request" | "not_supported" |
|
|
111
|
+
"timeout"); None if the message has no result
|
|
112
|
+
error: dict | None — {"code": int, "message": str}, from the result or,
|
|
113
|
+
if the whole operation failed, from the operation error (which has
|
|
114
|
+
no status)
|
|
115
|
+
|
|
116
|
+
A value this library doesn't know comes back as the number it was sent as.
|
|
117
|
+
|
|
118
|
+
The vehicle has done the command when the progress is "complete", the status
|
|
119
|
+
"success" and there is no error. "failed", "invalid_request" and
|
|
120
|
+
"not_supported" mean it has not. With "timeout" or "undefined", or if no
|
|
121
|
+
"complete" message comes at all, it isn't known, and the vehicle may do it
|
|
122
|
+
later.
|
|
123
|
+
"""
|
|
124
|
+
try:
|
|
125
|
+
data = base64.b64decode(payload)
|
|
126
|
+
message = command_pb2.CommandState.FromString(data)
|
|
127
|
+
except (TypeError, ValueError, DecodeError):
|
|
128
|
+
_LOGGER.debug("Failed to decode command state", exc_info=True)
|
|
129
|
+
return None
|
|
130
|
+
if not data:
|
|
131
|
+
return None
|
|
132
|
+
_debug_message("command state", message)
|
|
133
|
+
|
|
134
|
+
status: str | int | None = None
|
|
135
|
+
error: dict[str, Any] | None = None
|
|
136
|
+
if (result := _present(message, "data")) is not None:
|
|
137
|
+
status = _enum(_STATUS_MAP, result.response_status, what="command status")
|
|
138
|
+
if (result_error := _present(result, "error")) is not None:
|
|
139
|
+
error = {"code": result_error.code, "message": result_error.message}
|
|
140
|
+
elif (operation_error := _present(message, "operation_error")) is not None:
|
|
141
|
+
error = {"code": operation_error.error, "message": operation_error.message}
|
|
142
|
+
return {
|
|
143
|
+
"commandId": (
|
|
144
|
+
str(uuid.UUID(bytes=message.command_id))
|
|
145
|
+
if len(message.command_id) == 16
|
|
146
|
+
else None
|
|
147
|
+
),
|
|
148
|
+
"rvm": message.rvm,
|
|
149
|
+
"progress": _enum(_PROGRESS_MAP, message.progress, what="command progress"),
|
|
150
|
+
"status": status,
|
|
151
|
+
"error": error,
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def decode_command_state_message(data: dict[str, Any]) -> dict[str, Any] | None:
|
|
156
|
+
"""Decode a raw `subscribe_for_parallax_command_state` message.
|
|
157
|
+
|
|
158
|
+
Unwraps `payload.data.vehicleCommandStatePx.payload` for
|
|
159
|
+
`decode_command_state`; returns None if it's missing or can't be read. That
|
|
160
|
+
includes a message that carries GraphQL errors (`data["payload"]["errors"]`)
|
|
161
|
+
instead of a state.
|
|
162
|
+
"""
|
|
163
|
+
payload: Any = data
|
|
164
|
+
for key in ("payload", "data", "vehicleCommandStatePx", "payload"):
|
|
165
|
+
if not isinstance(payload, dict):
|
|
166
|
+
return None
|
|
167
|
+
payload = payload.get(key)
|
|
168
|
+
return decode_command_state(payload)
|
|
@@ -76,6 +76,16 @@ def _describe_unknowns(message: Message, path: str = "") -> list[str]:
|
|
|
76
76
|
return found
|
|
77
77
|
|
|
78
78
|
|
|
79
|
+
def _debug_message(label: str, message: Message) -> None:
|
|
80
|
+
"""Debug-log a parsed `message` and anything its schema doesn't define."""
|
|
81
|
+
if _LOGGER.isEnabledFor(logging.DEBUG):
|
|
82
|
+
_LOGGER.debug(
|
|
83
|
+
"%s: %s", label, text_format.MessageToString(message, as_one_line=True)
|
|
84
|
+
)
|
|
85
|
+
for unknown in _describe_unknowns(message):
|
|
86
|
+
_LOGGER.debug("%s: %s", label, unknown)
|
|
87
|
+
|
|
88
|
+
|
|
79
89
|
class RVMDecoder:
|
|
80
90
|
"""Registry of RVM topic -> (message class, decoder).
|
|
81
91
|
|
|
@@ -124,12 +134,7 @@ def _decode_rvm_payload(payload: str | None, rvm: str) -> dict[str, Any]:
|
|
|
124
134
|
except Exception:
|
|
125
135
|
_LOGGER.debug("Failed to decode %s payload", rvm, exc_info=True)
|
|
126
136
|
return {}
|
|
127
|
-
|
|
128
|
-
_LOGGER.debug(
|
|
129
|
-
"%s: %s", rvm, text_format.MessageToString(message, as_one_line=True)
|
|
130
|
-
)
|
|
131
|
-
for unknown in _describe_unknowns(message):
|
|
132
|
-
_LOGGER.debug("%s: %s", rvm, unknown)
|
|
137
|
+
_debug_message(rvm, message)
|
|
133
138
|
return result
|
|
134
139
|
|
|
135
140
|
|
|
@@ -53,11 +53,19 @@ def _decode_schedule(schedule: _Schedules.Schedule) -> dict[str, Any]:
|
|
|
53
53
|
entry["name"] = v
|
|
54
54
|
entry["isEnabled"] = schedule.is_enabled
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
if schedule.HasField("single_occurrence"):
|
|
57
|
+
starts_at = schedule.single_occurrence.starts_at
|
|
58
|
+
entry["occurrence"] = {
|
|
59
|
+
"startsAt": from_epoch(starts_at.seconds + starts_at.nanos / 1e9)
|
|
60
|
+
}
|
|
61
|
+
else:
|
|
62
|
+
occurrence = schedule.occurrence
|
|
63
|
+
entry["occurrence"] = {
|
|
64
|
+
"days": [
|
|
65
|
+
day for field, day in _WEEKDAYS if getattr(occurrence.days, field)
|
|
66
|
+
],
|
|
67
|
+
"startsAtMin": occurrence.starts_at,
|
|
68
|
+
}
|
|
61
69
|
|
|
62
70
|
settings = schedule.departure_settings
|
|
63
71
|
comfort = settings.comfort_settings
|
|
@@ -87,7 +95,9 @@ def decode_departure_schedules(m: departure_pb2.DepartureSchedules) -> dict[str,
|
|
|
87
95
|
departureSchedules: list[dict] — the gateway's DepartureSchedule shape:
|
|
88
96
|
id: str, name: str, isEnabled: bool
|
|
89
97
|
occurrence: {"days": list[str] ("monday" ... "sunday"; order
|
|
90
|
-
inferred), "startsAtMin": int (minutes after local midnight)}
|
|
98
|
+
inferred), "startsAtMin": int (minutes after local midnight)},
|
|
99
|
+
or {"startsAt": datetime} for the one-off "s-" schedule a
|
|
100
|
+
departNow adds (departing 10 minutes after the call)
|
|
91
101
|
departureSettings: {"shouldOverrideChargeSchedule": bool,
|
|
92
102
|
"comfortSettings": {"cabinTempCelsius": float,
|
|
93
103
|
"frontDefogDefrost": "off" | "defog" | "defrost",
|
|
@@ -310,7 +310,9 @@ def decode_trip_info(m: navigation_pb2.TripInfo) -> dict[str, Any]:
|
|
|
310
310
|
and incidents ({firstIndex, lastIndex, type})
|
|
311
311
|
overviewPolyline: str — Google-encoded, whole trip
|
|
312
312
|
nextWaypointDepartureTime: datetime — the next stop's departure if
|
|
313
|
-
it's a charging stop, else its arrival
|
|
313
|
+
it's a charging stop, else its arrival. It stops updating once
|
|
314
|
+
the first stop is reached, keeping that stop's time for the
|
|
315
|
+
rest of the trip; use waypoints[0] instead
|
|
314
316
|
finalStateOfCharge, finalRangeRemaining: float — the last
|
|
315
317
|
waypoint's (percent, meters)
|
|
316
318
|
socIsBelowLimit: bool
|
|
@@ -346,9 +348,11 @@ def decode_trip_progress(m: navigation_pb2.TripProgress) -> dict[str, Any]:
|
|
|
346
348
|
"""navigation.navigation_service.trip_progress — live progress on the active trip.
|
|
347
349
|
|
|
348
350
|
Fields:
|
|
349
|
-
nextWaypointArrivalTime: datetime — live ETA
|
|
351
|
+
nextWaypointArrivalTime: datetime — live ETA, to the minute
|
|
350
352
|
finalDestinationArrivalTime: datetime — live ETA for the last
|
|
351
|
-
waypoint
|
|
353
|
+
waypoint, to the minute; missing while the route is
|
|
354
|
+
recalculating and on the stale progress the vehicle keeps
|
|
355
|
+
resending after navigation ends
|
|
352
356
|
nextStopIndex: int
|
|
353
357
|
distanceRemaining, durationRemaining: float — to the next waypoint
|
|
354
358
|
(meters, seconds)
|
{rivian_python_client-2.3.0 → rivian_python_client-2.4.0}/src/rivian/parallax/proto/body.proto
RENAMED
|
@@ -266,3 +266,14 @@ enum WiperFluidState {
|
|
|
266
266
|
WIPER_FLUID_STATE_LOW = 2;
|
|
267
267
|
WIPER_FLUID_STATE_EMPTY = 3;
|
|
268
268
|
}
|
|
269
|
+
|
|
270
|
+
// body.locks.unlock, the payload of a signed command (see ../command.py)
|
|
271
|
+
message UnlockCommand {
|
|
272
|
+
oneof target {
|
|
273
|
+
bool all = 1; // the app always sets this
|
|
274
|
+
bool user_preference = 2; // in the app's schema; its button never sends it
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// body.locks.lock, the payload of a signed command. It has no fields.
|
|
279
|
+
message LockCommand {}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# NO CHECKED-IN PROTOBUF GENCODE
|
|
4
|
+
# source: rivian/parallax/proto/body.proto
|
|
5
|
+
# Protobuf Python Version: 6.31.1
|
|
6
|
+
"""Generated protocol buffer code."""
|
|
7
|
+
from google.protobuf import descriptor as _descriptor
|
|
8
|
+
from google.protobuf import descriptor_pool as _descriptor_pool
|
|
9
|
+
from google.protobuf import runtime_version as _runtime_version
|
|
10
|
+
from google.protobuf import symbol_database as _symbol_database
|
|
11
|
+
from google.protobuf.internal import builder as _builder
|
|
12
|
+
_runtime_version.ValidateProtobufRuntimeVersion(
|
|
13
|
+
_runtime_version.Domain.PUBLIC,
|
|
14
|
+
6,
|
|
15
|
+
31,
|
|
16
|
+
1,
|
|
17
|
+
'',
|
|
18
|
+
'rivian/parallax/proto/body.proto'
|
|
19
|
+
)
|
|
20
|
+
# @@protoc_insertion_point(imports)
|
|
21
|
+
|
|
22
|
+
_sym_db = _symbol_database.Default()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n rivian/parallax/proto/body.proto\x12\x14rivian.parallax.body\"\x89\x06\n\rClosuresState\x12<\n\x07\x63losure\x18\x01 \x03(\x0b\x32+.rivian.parallax.body.ClosuresState.Closure\x1a\xb9\x05\n\x07\x43losure\x12+\n\x02id\x18\x01 \x01(\x0e\x32\x1f.rivian.parallax.body.ClosureId\x12\x36\n\x05state\x18\x02 \x01(\x0e\x32\".rivian.parallax.body.ClosureStateH\x01\x88\x01\x01\x12\x1d\n\x15open_position_percent\x18\x03 \x01(\x05\x12\x31\n\x05\x66\x61ult\x18\x04 \x01(\x0e\x32\".rivian.parallax.body.ClosureFault\x12\x46\n\x13windows_next_action\x18\x05 \x01(\x0e\x32\'.rivian.parallax.body.WindowsNextActionH\x00\x12\x42\n\x11\x66runk_next_action\x18\x06 \x01(\x0e\x32%.rivian.parallax.body.FrunkNextActionH\x00\x12H\n\x14liftgate_next_action\x18\x07 \x01(\x0e\x32(.rivian.parallax.body.LiftgateNextActionH\x00\x12G\n\x14side_bin_next_action\x18\x08 \x01(\x0e\x32\'.rivian.parallax.body.SideBinNextActionH\x00\x12H\n\x14tailgate_next_action\x18\t \x01(\x0e\x32(.rivian.parallax.body.TailgateNextActionH\x00\x12V\n\x1c\x63harge_port_door_next_action\x18\n \x01(\x0e\x32..rivian.parallax.body.ChargePortDoorNextActionH\x00\x12\x1d\n\x13tonneau_next_action\x18\x0b \x01(\x05H\x00\x42\r\n\x0bnext_actionB\x08\n\x06_state\"\xe3\x01\n\nLocksState\x12\x33\n\x04lock\x18\x01 \x03(\x0b\x32%.rivian.parallax.body.LocksState.Lock\x1a\x9f\x01\n\x04Lock\x12(\n\x02id\x18\x01 \x01(\x0e\x32\x1c.rivian.parallax.body.LockId\x12\x33\n\x05state\x18\x02 \x01(\x0e\x32\x1f.rivian.parallax.body.LockStateH\x00\x88\x01\x01\x12.\n\x05\x66\x61ult\x18\x03 \x01(\x0e\x32\x1f.rivian.parallax.body.LockFaultB\x08\n\x06_state\"\xd1\x01\n\x0cWindowsState\x12\x39\n\x06window\x18\x01 \x03(\x0b\x32).rivian.parallax.body.WindowsState.Window\x1a\x85\x01\n\x06Window\x12\x36\n\x08instance\x18\x01 \x01(\x0e\x32$.rivian.parallax.body.WindowInstance\x12\x43\n\x12\x63\x61libration_status\x18\x02 \x01(\x0e\x32\'.rivian.parallax.body.CalibrationStatus\"\x9b\x01\n\x0cTrailerState\x12<\n\x08presence\x18\x01 \x01(\x0e\x32%.rivian.parallax.body.TrailerPresenceH\x00\x88\x01\x01\x12@\n\x11rear_hitch_status\x18\x02 \x01(\x0e\x32%.rivian.parallax.body.RearHitchStatusB\x0b\n\t_presence\"G\n\x0fWiperFluidLevel\x12\x34\n\x05state\x18\x02 \x01(\x0e\x32%.rivian.parallax.body.WiperFluidState\"C\n\rUnlockCommand\x12\r\n\x03\x61ll\x18\x01 \x01(\x08H\x00\x12\x19\n\x0fuser_preference\x18\x02 \x01(\x08H\x00\x42\x08\n\x06target\"\r\n\x0bLockCommand*\xe8\x02\n\tClosureId\x12\x1a\n\x16\x43LOSURE_ID_UNSPECIFIED\x10\x00\x12\x13\n\x0f\x44OOR_FRONT_LEFT\x10\x01\x12\x14\n\x10\x44OOR_FRONT_RIGHT\x10\x02\x12\x12\n\x0e\x44OOR_REAR_LEFT\x10\x03\x12\x13\n\x0f\x44OOR_REAR_RIGHT\x10\x04\x12\t\n\x05\x46RUNK\x10\x05\x12\x0c\n\x08TAILGATE\x10\x06\x12\x0c\n\x08LIFTGATE\x10\x07\x12\x11\n\rSIDE_BIN_LEFT\x10\x08\x12\x12\n\x0eSIDE_BIN_RIGHT\x10\t\x12\x0f\n\x0b\x43HARGE_PORT\x10\n\x12\x0b\n\x07TONNEAU\x10\x0b\x12\x15\n\x11WINDOW_FRONT_LEFT\x10\x0c\x12\x16\n\x12WINDOW_FRONT_RIGHT\x10\r\x12\x14\n\x10WINDOW_REAR_LEFT\x10\x0e\x12\x15\n\x11WINDOW_REAR_RIGHT\x10\x0f\x12\x0f\n\x0bWINDOW_REAR\x10\x10\x12\x12\n\rGROUP_WINDOWS\x10\x90N*\xad\x01\n\x0c\x43losureState\x12\x1d\n\x19\x43LOSURE_STATE_UNSPECIFIED\x10\x00\x12\x16\n\x12\x43LOSURE_STATE_OPEN\x10\x01\x12\x18\n\x14\x43LOSURE_STATE_CLOSED\x10\x02\x12\x16\n\x12\x43LOSURE_STATE_AJAR\x10\x03\x12\x19\n\x15\x43LOSURE_STATE_OPENING\x10\x04\x12\x19\n\x15\x43LOSURE_STATE_CLOSING\x10\x05*\xf3\x02\n\x06LockId\x12\x17\n\x13LOCK_ID_UNSPECIFIED\x10\x00\x12\x18\n\x14LOCK_DOOR_FRONT_LEFT\x10\x01\x12\x19\n\x15LOCK_DOOR_FRONT_RIGHT\x10\x02\x12\x17\n\x13LOCK_DOOR_REAR_LEFT\x10\x03\x12\x18\n\x14LOCK_DOOR_REAR_RIGHT\x10\x04\x12\x0e\n\nLOCK_FRUNK\x10\x05\x12\x11\n\rLOCK_TAILGATE\x10\x06\x12\x11\n\rLOCK_LIFTGATE\x10\x07\x12\x16\n\x12LOCK_SIDE_BIN_LEFT\x10\x08\x12\x17\n\x13LOCK_SIDE_BIN_RIGHT\x10\t\x12\x14\n\x10LOCK_CHARGE_PORT\x10\n\x12\x17\n\x13LOCK_TRUNK_SECURITY\x10\x0b\x12\x17\n\x13LOCK_CENTER_CONSOLE\x10\x0c\x12\x12\n\x0eLOCK_GLOVE_BOX\x10\r\x12\x13\n\x0fLOCK_GEAR_GUARD\x10\x0e\x12\x10\n\x0cLOCK_TONNEAU\x10\x0f*z\n\tLockState\x12\x1a\n\x16LOCK_STATE_UNSPECIFIED\x10\x00\x12\x15\n\x11LOCK_STATE_LOCKED\x10\x01\x12\x17\n\x13LOCK_STATE_UNLOCKED\x10\x02\x12!\n\x1dLOCK_STATE_PARTIALLY_UNLOCKED\x10\x03*?\n\tLockFault\x12\x1a\n\x16LOCK_FAULT_UNSPECIFIED\x10\x00\x12\x16\n\x12LOCK_FAULT_FAULTED\x10\x01*\xcb\x01\n\x0eWindowInstance\x12\x1f\n\x1bWINDOW_INSTANCE_UNSPECIFIED\x10\x00\x12\x1e\n\x1aWINDOW_INSTANCE_FRONT_LEFT\x10\x01\x12\x1f\n\x1bWINDOW_INSTANCE_FRONT_RIGHT\x10\x02\x12\x1d\n\x19WINDOW_INSTANCE_REAR_LEFT\x10\x03\x12\x1e\n\x1aWINDOW_INSTANCE_REAR_RIGHT\x10\x04\x12\x18\n\x14WINDOW_INSTANCE_REAR\x10\x05*\x81\x01\n\x11\x43\x61librationStatus\x12\"\n\x1e\x43\x41LIBRATION_STATUS_UNSPECIFIED\x10\x00\x12!\n\x1d\x43\x41LIBRATION_STATUS_CALIBRATED\x10\x01\x12%\n!CALIBRATION_STATUS_NOT_CALIBRATED\x10\x02*\xd8\x01\n\x0fRearHitchStatus\x12!\n\x1dREAR_HITCH_STATUS_UNSPECIFIED\x10\x00\x12!\n\x1dREAR_HITCH_STATUS_NOT_PRESENT\x10\x01\x12\x1f\n\x1bREAR_HITCH_STATUS_ACCESSORY\x10\x02\x12\x1e\n\x1aREAR_HITCH_STATUS_TRAILER1\x10\x03\x12\x1e\n\x1aREAR_HITCH_STATUS_TRAILER2\x10\x04\x12\x1e\n\x1aREAR_HITCH_STATUS_TRAILER3\x10\x05*\xaa\x01\n\x0c\x43losureFault\x12\x1d\n\x19\x43LOSURE_FAULT_UNSPECIFIED\x10\x00\x12\x1a\n\x16\x43LOSURE_FAULT_NO_FAULT\x10\x01\x12\x19\n\x15\x43LOSURE_FAULT_GENERAL\x10\x02\x12&\n\"CLOSURE_FAULT_NO_POWERED_OPERATION\x10\x03\x12\x1c\n\x18\x43LOSURE_FAULT_OBSTRUCTED\x10\x04*\x97\x01\n\x0fTrailerPresence\x12 \n\x1cTRAILER_PRESENCE_UNSPECIFIED\x10\x00\x12\x17\n\x13TRAILER_NOT_PRESENT\x10\x01\x12\x13\n\x0fTRAILER_PRESENT\x10\x02\x12\x1f\n\x1bTRAILER_PRESENT_WITH_BRAKES\x10\x03\x12\x13\n\x0fTRAILER_INVALID\x10\x04*\x9f\x04\n\x18\x43hargePortDoorNextAction\x12\x18\n\x14\x43HARGE_PORT_DOOR_SNA\x10\x00\x12!\n\x1d\x43HARGE_PORT_DOOR_OPEN_ALLOWED\x10\x01\x12\'\n#CHARGE_PORT_DOOR_OPEN_NOT_AVAILABLE\x10\x02\x12-\n)CHARGE_PORT_DOOR_OPEN_NOT_ALLOWED_FAULTED\x10\x03\x12\x1c\n\x18\x43HARGE_PORT_DOOR_OPENING\x10\x04\x12\"\n\x1e\x43HARGE_PORT_DOOR_CLOSE_ALLOWED\x10\x05\x12;\n7CHARGE_PORT_DOOR_OBSTRUCTED_WHILE_OPENING_CLOSE_ALLOWED\x10\x06\x12:\n6CHARGE_PORT_DOOR_OBSTRUCTED_WHILE_OPENING_OPEN_ALLOWED\x10\x07\x12;\n7CHARGE_PORT_DOOR_OBSTRUCTED_WHILE_CLOSING_CLOSE_ALLOWED\x10\x08\x12(\n$CHARGE_PORT_DOOR_CLOSE_NOT_AVAILABLE\x10\t\x12.\n*CHARGE_PORT_DOOR_CLOSE_NOT_ALLOWED_FAULTED\x10\n\x12\x1c\n\x18\x43HARGE_PORT_DOOR_CLOSING\x10\x0b*\xb0\x03\n\x0f\x46runkNextAction\x12\r\n\tFRUNK_SNA\x10\x00\x12\x16\n\x12\x46RUNK_OPEN_ALLOWED\x10\x01\x12\x17\n\x13\x46RUNK_CLOSE_ALLOWED\x10\x02\x12\x11\n\rFRUNK_OPENING\x10\x03\x12\x11\n\rFRUNK_CLOSING\x10\x04\x12\x1c\n\x18\x46RUNK_OPEN_NOT_AVAILABLE\x10\x05\x12\x1d\n\x19\x46RUNK_CLOSE_NOT_AVAILABLE\x10\x06\x12\"\n\x1e\x46RUNK_OPEN_NOT_ALLOWED_FAULTED\x10\x07\x12#\n\x1f\x46RUNK_CLOSE_NOT_ALLOWED_FAULTED\x10\x08\x12)\n%FRUNK_OPEN_ALLOWED_NO_POWER_OPERATION\x10\t\x12.\n*FRUNK_CLOSE_NOT_ALLOWED_NO_POWER_OPERATION\x10\n\x12*\n&FRUNK_OBSTRUCTED_OPENING_CLOSE_ALLOWED\x10\x0b\x12*\n&FRUNK_OBSTRUCTED_CLOSING_CLOSE_ALLOWED\x10\x0c*\xa7\x06\n\x12LiftgateNextAction\x12\x10\n\x0cLIFTGATE_SNA\x10\x00\x12\x19\n\x15LIFTGATE_OPEN_ALLOWED\x10\x01\x12\x1a\n\x16LIFTGATE_CLOSE_ALLOWED\x10\x02\x12\x14\n\x10LIFTGATE_OPENING\x10\x03\x12\x14\n\x10LIFTGATE_CLOSING\x10\x04\x12\x1f\n\x1bLIFTGATE_OPEN_NOT_AVAILABLE\x10\x05\x12 \n\x1cLIFTGATE_CLOSE_NOT_AVAILABLE\x10\x06\x12%\n!LIFTGATE_OPEN_NOT_ALLOWED_FAULTED\x10\x07\x12&\n\"LIFTGATE_CLOSE_NOT_ALLOWED_FAULTED\x10\x08\x12,\n(LIFTGATE_OPEN_ALLOWED_NO_POWER_OPERATION\x10\t\x12\x31\n-LIFTGATE_CLOSE_NOT_ALLOWED_NO_POWER_OPERATION\x10\n\x12-\n)LIFTGATE_OBSTRUCTED_OPENING_CLOSE_ALLOWED\x10\x0b\x12-\n)LIFTGATE_OBSTRUCTED_CLOSING_CLOSE_ALLOWED\x10\x0c\x12.\n*LIFTGATE_LOWER_GATE_OPEN_CLOSE_NOT_ALLOWED\x10\r\x12&\n\"LIFTGATE_OPENING_PAUSE_NOT_ALLOWED\x10\x0e\x12&\n\"LIFTGATE_CLOSING_PAUSE_NOT_ALLOWED\x10\x0f\x12+\n\'LIFTGATE_OPEN_ALLOWED_OBSTACLE_DETECTED\x10\x10\x12*\n&LIFTGATE_OPEN_ALLOWED_TRAILER_DETECTED\x10\x11\x12,\n(LIFTGATE_CLOSE_ALLOWED_OBSTACLE_DETECTED\x10\x12\x12+\n\'LIFTGATE_CLOSE_ALLOWED_TRAILER_DETECTED\x10\x13\x12\x17\n\x13LIFTGATE_PROCESSING\x10\x14*\xb2\x02\n\x11SideBinNextAction\x12\x10\n\x0cSIDE_BIN_SNA\x10\x00\x12\x19\n\x15SIDE_BIN_OPEN_ALLOWED\x10\x01\x12\x14\n\x10SIDE_BIN_OPENING\x10\x02\x12\x1f\n\x1bSIDE_BIN_OPEN_NOT_AVAILABLE\x10\x03\x12%\n!SIDE_BIN_OPEN_NOT_ALLOWED_FAULTED\x10\x04\x12\x32\n.SIDE_BIN_STUCK_AJAR_WHILE_OPENING_OPEN_ALLOWED\x10\x05\x12-\n)SIDE_BIN_OPEN_ALREADY_NO_ACTION_AVAILABLE\x10\x06\x12/\n+SIDE_BIN_OPEN_ALLOWED_CONFIRM_VEHICLE_ANGLE\x10\x07*\x8c\x03\n\x12TailgateNextAction\x12\x10\n\x0cTAILGATE_SNA\x10\x00\x12\x19\n\x15TAILGATE_OPEN_ALLOWED\x10\x01\x12\x14\n\x10TAILGATE_OPENING\x10\x02\x12\x1f\n\x1bTAILGATE_OPEN_NOT_AVAILABLE\x10\x03\x12%\n!TAILGATE_OPEN_NOT_ALLOWED_FAULTED\x10\x04\x12\x32\n.TAILGATE_STUCK_AJAR_WHILE_OPENING_OPEN_ALLOWED\x10\x05\x12-\n)TAILGATE_OPEN_ALREADY_NO_ACTION_AVAILABLE\x10\x06\x12/\n+TAILGATE_OPEN_ALLOWED_CONFIRM_VEHICLE_ANGLE\x10\x07\x12+\n\'TAILGATE_OPEN_ALLOWED_OBSTACLE_DETECTED\x10\x08\x12*\n&TAILGATE_OPEN_ALLOWED_TRAILER_DETECTED\x10\t*\xb0\x03\n\x11WindowsNextAction\x12\x0f\n\x0bWINDOWS_SNA\x10\x00\x12\x18\n\x14WINDOWS_OPEN_ALLOWED\x10\x01\x12\x19\n\x15WINDOWS_CLOSE_ALLOWED\x10\x02\x12\x13\n\x0fWINDOWS_OPENING\x10\x03\x12\x13\n\x0fWINDOWS_CLOSING\x10\x04\x12\x12\n\x0eWINDOWS_MOVING\x10\x05\x12\x1e\n\x1aWINDOWS_OPEN_NOT_AVAILABLE\x10\x06\x12\x1f\n\x1bWINDOWS_CLOSE_NOT_AVAILABLE\x10\x07\x12$\n WINDOWS_OPEN_NOT_ALLOWED_FAULTED\x10\x08\x12%\n!WINDOWS_CLOSE_NOT_ALLOWED_FAULTED\x10\t\x12\x32\n.WINDOWS_OBSTRUCTED_WHILE_CLOSING_CLOSE_ALLOWED\x10\n\x12*\n&WINDOWS_CLOSE_NOT_ALLOWED_UNCALIBRATED\x10\x0b\x12)\n%WINDOWS_OPEN_NOT_ALLOWED_UNCALIBRATED\x10\x0c*\x8a\x01\n\x0fWiperFluidState\x12!\n\x1dWIPER_FLUID_STATE_UNSPECIFIED\x10\x00\x12\x1c\n\x18WIPER_FLUID_STATE_NORMAL\x10\x01\x12\x19\n\x15WIPER_FLUID_STATE_LOW\x10\x02\x12\x1b\n\x17WIPER_FLUID_STATE_EMPTY\x10\x03\x62\x06proto3')
|
|
28
|
+
|
|
29
|
+
_globals = globals()
|
|
30
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
31
|
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'rivian.parallax.proto.body_pb2', _globals)
|
|
32
|
+
if not _descriptor._USE_C_DESCRIPTORS:
|
|
33
|
+
DESCRIPTOR._loaded_options = None
|
|
34
|
+
_globals['_CLOSUREID']._serialized_start=1596
|
|
35
|
+
_globals['_CLOSUREID']._serialized_end=1956
|
|
36
|
+
_globals['_CLOSURESTATE']._serialized_start=1959
|
|
37
|
+
_globals['_CLOSURESTATE']._serialized_end=2132
|
|
38
|
+
_globals['_LOCKID']._serialized_start=2135
|
|
39
|
+
_globals['_LOCKID']._serialized_end=2506
|
|
40
|
+
_globals['_LOCKSTATE']._serialized_start=2508
|
|
41
|
+
_globals['_LOCKSTATE']._serialized_end=2630
|
|
42
|
+
_globals['_LOCKFAULT']._serialized_start=2632
|
|
43
|
+
_globals['_LOCKFAULT']._serialized_end=2695
|
|
44
|
+
_globals['_WINDOWINSTANCE']._serialized_start=2698
|
|
45
|
+
_globals['_WINDOWINSTANCE']._serialized_end=2901
|
|
46
|
+
_globals['_CALIBRATIONSTATUS']._serialized_start=2904
|
|
47
|
+
_globals['_CALIBRATIONSTATUS']._serialized_end=3033
|
|
48
|
+
_globals['_REARHITCHSTATUS']._serialized_start=3036
|
|
49
|
+
_globals['_REARHITCHSTATUS']._serialized_end=3252
|
|
50
|
+
_globals['_CLOSUREFAULT']._serialized_start=3255
|
|
51
|
+
_globals['_CLOSUREFAULT']._serialized_end=3425
|
|
52
|
+
_globals['_TRAILERPRESENCE']._serialized_start=3428
|
|
53
|
+
_globals['_TRAILERPRESENCE']._serialized_end=3579
|
|
54
|
+
_globals['_CHARGEPORTDOORNEXTACTION']._serialized_start=3582
|
|
55
|
+
_globals['_CHARGEPORTDOORNEXTACTION']._serialized_end=4125
|
|
56
|
+
_globals['_FRUNKNEXTACTION']._serialized_start=4128
|
|
57
|
+
_globals['_FRUNKNEXTACTION']._serialized_end=4560
|
|
58
|
+
_globals['_LIFTGATENEXTACTION']._serialized_start=4563
|
|
59
|
+
_globals['_LIFTGATENEXTACTION']._serialized_end=5370
|
|
60
|
+
_globals['_SIDEBINNEXTACTION']._serialized_start=5373
|
|
61
|
+
_globals['_SIDEBINNEXTACTION']._serialized_end=5679
|
|
62
|
+
_globals['_TAILGATENEXTACTION']._serialized_start=5682
|
|
63
|
+
_globals['_TAILGATENEXTACTION']._serialized_end=6078
|
|
64
|
+
_globals['_WINDOWSNEXTACTION']._serialized_start=6081
|
|
65
|
+
_globals['_WINDOWSNEXTACTION']._serialized_end=6513
|
|
66
|
+
_globals['_WIPERFLUIDSTATE']._serialized_start=6516
|
|
67
|
+
_globals['_WIPERFLUIDSTATE']._serialized_end=6654
|
|
68
|
+
_globals['_CLOSURESSTATE']._serialized_start=59
|
|
69
|
+
_globals['_CLOSURESSTATE']._serialized_end=836
|
|
70
|
+
_globals['_CLOSURESSTATE_CLOSURE']._serialized_start=139
|
|
71
|
+
_globals['_CLOSURESSTATE_CLOSURE']._serialized_end=836
|
|
72
|
+
_globals['_LOCKSSTATE']._serialized_start=839
|
|
73
|
+
_globals['_LOCKSSTATE']._serialized_end=1066
|
|
74
|
+
_globals['_LOCKSSTATE_LOCK']._serialized_start=907
|
|
75
|
+
_globals['_LOCKSSTATE_LOCK']._serialized_end=1066
|
|
76
|
+
_globals['_WINDOWSSTATE']._serialized_start=1069
|
|
77
|
+
_globals['_WINDOWSSTATE']._serialized_end=1278
|
|
78
|
+
_globals['_WINDOWSSTATE_WINDOW']._serialized_start=1145
|
|
79
|
+
_globals['_WINDOWSSTATE_WINDOW']._serialized_end=1278
|
|
80
|
+
_globals['_TRAILERSTATE']._serialized_start=1281
|
|
81
|
+
_globals['_TRAILERSTATE']._serialized_end=1436
|
|
82
|
+
_globals['_WIPERFLUIDLEVEL']._serialized_start=1438
|
|
83
|
+
_globals['_WIPERFLUIDLEVEL']._serialized_end=1509
|
|
84
|
+
_globals['_UNLOCKCOMMAND']._serialized_start=1511
|
|
85
|
+
_globals['_UNLOCKCOMMAND']._serialized_end=1578
|
|
86
|
+
_globals['_LOCKCOMMAND']._serialized_start=1580
|
|
87
|
+
_globals['_LOCKCOMMAND']._serialized_end=1593
|
|
88
|
+
# @@protoc_insertion_point(module_scope)
|