rivian-python-client 2.2.0b0__py3-none-any.whl → 2.2.0b2__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.
- rivian/__version__.py +1 -1
- rivian/parallax/__init__.py +2 -0
- rivian/parallax/body.py +70 -46
- rivian/parallax/charging.py +63 -43
- rivian/parallax/comfort.py +54 -45
- rivian/parallax/device_table.py +56 -16
- rivian/parallax/dynamics.py +34 -34
- rivian/parallax/energy.py +6 -6
- rivian/parallax/gearguard_streaming.py +9 -9
- rivian/parallax/geofence.py +11 -5
- rivian/parallax/holiday_celebration.py +46 -6
- rivian/parallax/navigation.py +6 -3
- rivian/parallax/ota.py +37 -24
- rivian/parallax/proto/body.proto +86 -27
- rivian/parallax/proto/body_pb2.py +37 -29
- rivian/parallax/proto/body_pb2.pyi +154 -40
- rivian/parallax/proto/charging.proto +16 -7
- rivian/parallax/proto/charging_pb2.py +12 -10
- rivian/parallax/proto/charging_pb2.pyi +19 -6
- rivian/parallax/proto/comfort.proto +33 -26
- rivian/parallax/proto/comfort_pb2.py +24 -24
- rivian/parallax/proto/comfort_pb2.pyi +57 -43
- rivian/parallax/proto/device_table.proto +37 -17
- rivian/parallax/proto/device_table_pb2.py +16 -12
- rivian/parallax/proto/device_table_pb2.pyi +60 -29
- rivian/parallax/proto/geofence.proto +9 -2
- rivian/parallax/proto/geofence_pb2.py +5 -3
- rivian/parallax/proto/geofence_pb2.pyi +16 -4
- rivian/parallax/proto/holiday_celebration.proto +24 -10
- rivian/parallax/proto/holiday_celebration_pb2.py +10 -4
- rivian/parallax/proto/holiday_celebration_pb2.pyi +44 -19
- rivian/parallax/proto/navigation.proto +8 -1
- rivian/parallax/proto/navigation_pb2.py +19 -17
- rivian/parallax/proto/navigation_pb2.pyi +15 -4
- rivian/parallax/proto/ota.proto +24 -12
- rivian/parallax/proto/ota_pb2.py +17 -13
- rivian/parallax/proto/ota_pb2.pyi +30 -18
- rivian/parallax/proto/vehicle.proto +5 -5
- rivian/parallax/proto/vehicle_access.proto +13 -2
- rivian/parallax/proto/vehicle_access_pb2.py +5 -3
- rivian/parallax/proto/vehicle_access_pb2.pyi +19 -3
- rivian/parallax/proto/vehicle_pb2.py +27 -27
- rivian/parallax/proto/vehicle_pb2.pyi +20 -20
- rivian/parallax/security.py +37 -37
- rivian/parallax/vehicle.py +29 -23
- rivian/parallax/vehicle_access.py +26 -5
- rivian/ws_monitor.py +31 -0
- {rivian_python_client-2.2.0b0.dist-info → rivian_python_client-2.2.0b2.dist-info}/METADATA +1 -1
- rivian_python_client-2.2.0b2.dist-info/RECORD +94 -0
- rivian_python_client-2.2.0b0.dist-info/RECORD +0 -94
- {rivian_python_client-2.2.0b0.dist-info → rivian_python_client-2.2.0b2.dist-info}/WHEEL +0 -0
rivian/__version__.py
CHANGED
rivian/parallax/__init__.py
CHANGED
|
@@ -50,7 +50,9 @@ from .core import (
|
|
|
50
50
|
PARALLAX_RVMS: list[str] = list(RVMDecoder.decoders)
|
|
51
51
|
|
|
52
52
|
CHARGING_RVMS: list[str] = [
|
|
53
|
+
"charging.energy.state",
|
|
53
54
|
"charging.session.notification",
|
|
55
|
+
"charging.session.power",
|
|
54
56
|
"charging.session.remote_command",
|
|
55
57
|
"charging.session.soc_slider",
|
|
56
58
|
"charging.session.status",
|
rivian/parallax/body.py
CHANGED
|
@@ -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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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,
|
|
108
|
-
|
|
109
|
-
closureChargePortDoorNextAction
|
|
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
|
-
|
|
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
|
|
156
|
+
"""body.locks.states — lock state of every lock.
|
|
137
157
|
|
|
138
158
|
Fields:
|
|
139
|
-
doorFrontLeftLocked, closureFrunkLocked,
|
|
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]] =
|
|
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
|
rivian/parallax/charging.py
CHANGED
|
@@ -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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
69
|
-
|
|
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
|
-
|
|
148
|
-
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
|
|
@@ -210,17 +210,37 @@ def decode_time_estimation(m: charging_pb2.TimeEstimation) -> dict[str, Any]:
|
|
|
210
210
|
return {"timeToEndOfCharge": m.estimated_time_remaining}
|
|
211
211
|
|
|
212
212
|
|
|
213
|
+
_CHARGER_STATUS_MAP: Final[dict[int, str]] = {
|
|
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
|
+
}
|
|
218
|
+
|
|
219
|
+
|
|
213
220
|
@RVMDecoder.register("charging.energy.state", charging_pb2.EnergyState)
|
|
214
221
|
def decode_energy_state(m: charging_pb2.EnergyState) -> dict[str, Any]:
|
|
215
|
-
"""charging.energy.state —
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
222
|
+
"""charging.energy.state — charger connection status.
|
|
223
|
+
|
|
224
|
+
Fields:
|
|
225
|
+
chargerStatus: str — GraphQL chargerStatus values
|
|
226
|
+
("chrgr_sts_not_connected" | "chrgr_sts_connected_no_chrg" |
|
|
227
|
+
"chrgr_sts_connected_charging"); inferred
|
|
228
|
+
_field1, _field3, _field11: int — raw
|
|
229
|
+
"""
|
|
230
|
+
result: dict[str, Any] = {}
|
|
231
|
+
if (v := _present(m, "charger_status")) is not None:
|
|
232
|
+
result["chargerStatus"] = _enum(_CHARGER_STATUS_MAP, v, what="charger status")
|
|
233
|
+
for num in (1, 3, 11):
|
|
234
|
+
if (v := _present(m, f"field_{num}")) is not None:
|
|
235
|
+
result[f"_field{num}"] = v
|
|
236
|
+
return result
|
|
221
237
|
|
|
222
238
|
|
|
223
239
|
@RVMDecoder.register("charging.session.power", charging_pb2.SessionPower)
|
|
224
|
-
def decode_session_power(
|
|
225
|
-
"""charging.session.power —
|
|
226
|
-
|
|
240
|
+
def decode_session_power(m: charging_pb2.SessionPower) -> dict[str, Any]:
|
|
241
|
+
"""charging.session.power — live charging power, about every 5 seconds.
|
|
242
|
+
|
|
243
|
+
Fields:
|
|
244
|
+
power: float (kW; 0 when not charging)
|
|
245
|
+
"""
|
|
246
|
+
return {"power": round(m.power, 2)}
|
rivian/parallax/comfort.py
CHANGED
|
@@ -34,60 +34,69 @@ def decode_user_modes_state(m: comfort_pb2.UserModesState) -> dict[str, Any]:
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
_CLIMATE_HOLD_AVAILABILITY_MAP: Final[dict[int, str]] = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
comfort_pb2.CLIMATE_HOLD_AVAILABILITY_UNSPECIFIED: "unspecified",
|
|
38
|
+
comfort_pb2.CLIMATE_HOLD_AVAILABLE: "available",
|
|
39
|
+
comfort_pb2.CLIMATE_HOLD_CONTROLLABLE: "controllable",
|
|
40
|
+
comfort_pb2.CLIMATE_HOLD_UNAVAILABLE: "unavailable",
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
_CLIMATE_HOLD_STATUS_MAP: Final[dict[int, str]] = {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
comfort_pb2.CLIMATE_HOLD_STATUS_UNSPECIFIED: "unspecified",
|
|
45
|
+
comfort_pb2.CLIMATE_HOLD_STATUS_UNAVAILABLE: "unavailable",
|
|
46
|
+
comfort_pb2.CLIMATE_HOLD_STATUS_OFF: "off",
|
|
47
|
+
comfort_pb2.CLIMATE_HOLD_STATUS_ON: "on",
|
|
48
|
+
comfort_pb2.CLIMATE_HOLD_STATUS_FAULT: "fault",
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
_CLIMATE_HOLD_UNAVAILABILITY_REASON_MAP: Final[dict[int, str]] = {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
comfort_pb2.CLIMATE_HOLD_UNAVAILABILITY_UNSPECIFIED: "unspecified",
|
|
53
|
+
comfort_pb2.CLIMATE_HOLD_UNAVAILABILITY_UNKNOWN: "unknown",
|
|
54
|
+
comfort_pb2.CLIMATE_HOLD_UNAVAILABILITY_LOW_SOC: "low_soc",
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
_PET_MODE_STATE_MAP: Final[dict[int, str]] = {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
comfort_pb2.PET_MODE_OFF: "off",
|
|
59
|
+
comfort_pb2.PET_MODE_ON: "on",
|
|
60
|
+
comfort_pb2.PET_MODE_DISABLED: "disabled",
|
|
61
|
+
comfort_pb2.PET_MODE_FAULTY: "faulty",
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
_PET_MODE_TEMPERATURE_MAP: Final[dict[int, str]] = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
comfort_pb2.PET_MODE_TEMPERATURE_DEFAULT: "default",
|
|
66
|
+
comfort_pb2.PET_MODE_TEMPERATURE_COLD: "cold",
|
|
67
|
+
comfort_pb2.PET_MODE_TEMPERATURE_HOT: "hot",
|
|
68
|
+
comfort_pb2.PET_MODE_TEMPERATURE_FAULTY: "faulty",
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
# Seat keys use the GraphQL names: row 1 is "Front", row 2 "Rear", row 3
|
|
72
|
+
# "ThirdRow".
|
|
73
|
+
_CABIN_SURFACE_MAP: Final[dict[int, str]] = {
|
|
74
|
+
comfort_pb2.STEERING_WHEEL: "steeringWheel",
|
|
75
|
+
comfort_pb2.REAR_GLASS: "rearGlass",
|
|
76
|
+
comfort_pb2.FRONT_GLASS: "frontGlass",
|
|
77
|
+
comfort_pb2.SIDEVIEW_MIRRORS: "sideviewMirrors",
|
|
78
|
+
comfort_pb2.SEAT_ROW_1_LEFT: "seatFrontLeft",
|
|
79
|
+
comfort_pb2.SEAT_ROW_1_MIDDLE: "seatFrontMiddle",
|
|
80
|
+
comfort_pb2.SEAT_ROW_1_RIGHT: "seatFrontRight",
|
|
81
|
+
comfort_pb2.SEAT_ROW_2_LEFT: "seatRearLeft",
|
|
82
|
+
comfort_pb2.SEAT_ROW_2_MIDDLE: "seatRearMiddle",
|
|
83
|
+
comfort_pb2.SEAT_ROW_2_RIGHT: "seatRearRight",
|
|
84
|
+
comfort_pb2.SEAT_ROW_3_LEFT: "seatThirdRowLeft",
|
|
85
|
+
comfort_pb2.SEAT_ROW_3_MIDDLE: "seatThirdRowMiddle",
|
|
86
|
+
comfort_pb2.SEAT_ROW_3_RIGHT: "seatThirdRowRight",
|
|
87
|
+
comfort_pb2.WIPER_AREA: "wiperArea",
|
|
79
88
|
}
|
|
80
89
|
|
|
81
|
-
|
|
90
|
+
_CONDITIONING_LEVEL_MAP: Final[dict[int | None, str]] = {
|
|
82
91
|
None: "Off",
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
92
|
+
comfort_pb2.CONDITIONING_LEVEL_1: "Level_1",
|
|
93
|
+
comfort_pb2.CONDITIONING_LEVEL_2: "Level_2",
|
|
94
|
+
comfort_pb2.CONDITIONING_LEVEL_3: "Level_3",
|
|
86
95
|
}
|
|
87
96
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
97
|
+
_CONDITIONING_TYPE_MAP: Final[dict[int, str]] = {
|
|
98
|
+
comfort_pb2.CONDITIONING_HEAT: "Heat",
|
|
99
|
+
comfort_pb2.CONDITIONING_VENT: "Vent",
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
|
|
@@ -247,23 +256,23 @@ def decode_seat_conditioning(m: comfort_pb2.SeatConditioningStatus) -> dict[str,
|
|
|
247
256
|
seatThirdRowLeftHeat, seatThirdRowRightHeat: str
|
|
248
257
|
("Off" | "Level_1" | "Level_2" | "Level_3")
|
|
249
258
|
steeringWheelHeat: str ("Off" | "Level_1")
|
|
259
|
+
plus <surface>Heat/Vent for any other surface sent (middle seats,
|
|
260
|
+
rearGlass, frontGlass, sideviewMirrors, wiperArea)
|
|
250
261
|
|
|
251
262
|
Entries without a state are skipped.
|
|
252
263
|
"""
|
|
253
264
|
result: dict[str, Any] = {}
|
|
254
|
-
for
|
|
255
|
-
|
|
256
|
-
if (state_val := _present(
|
|
265
|
+
for surface in m.surface:
|
|
266
|
+
surface_id, hvac_type = surface.id, surface.type
|
|
267
|
+
if (state_val := _present(surface, "state")) is None:
|
|
257
268
|
continue
|
|
258
|
-
if
|
|
259
|
-
key =
|
|
260
|
-
|
|
261
|
-
)
|
|
262
|
-
result[key] = _SEAT_CONDITIONING_STATUS_MAP.get(state_val, state_val)
|
|
269
|
+
if surface_id in _CABIN_SURFACE_MAP and hvac_type in _CONDITIONING_TYPE_MAP:
|
|
270
|
+
key = f"{_CABIN_SURFACE_MAP[surface_id]}{_CONDITIONING_TYPE_MAP[hvac_type]}"
|
|
271
|
+
result[key] = _CONDITIONING_LEVEL_MAP.get(state_val, state_val)
|
|
263
272
|
else:
|
|
264
273
|
_LOGGER.debug(
|
|
265
|
-
"Unknown
|
|
266
|
-
|
|
274
|
+
"Unknown cabin surface %s (hvac_type %s; state %s)",
|
|
275
|
+
surface_id,
|
|
267
276
|
hvac_type,
|
|
268
277
|
state_val,
|
|
269
278
|
)
|
rivian/parallax/device_table.py
CHANGED
|
@@ -2,35 +2,68 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import uuid
|
|
6
|
+
from typing import Any, Final
|
|
6
7
|
|
|
7
|
-
from .core import RVMDecoder, _present
|
|
8
|
+
from .core import RVMDecoder, _enum, _present
|
|
8
9
|
from .proto import device_table_pb2
|
|
9
10
|
|
|
11
|
+
_Devices = device_table_pb2.VasKeyperDevices
|
|
12
|
+
_KEY_STATUS_MAP: Final[dict[int, str]] = {
|
|
13
|
+
_Devices.KEY_STATUS_ACTIVE: "active",
|
|
14
|
+
_Devices.KEY_STATUS_INACTIVE: "inactive",
|
|
15
|
+
_Devices.KEY_STATUS_WAITING_TO_PAIR: "waiting_to_pair",
|
|
16
|
+
_Devices.KEY_STATUS_PAIRING: "pairing",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_KEY_TYPE_MAP: Final[dict[int, str]] = {
|
|
20
|
+
_Devices.KEY_TYPE_PHONE: "phone",
|
|
21
|
+
_Devices.KEY_TYPE_KEY_CARD: "key_card",
|
|
22
|
+
_Devices.KEY_TYPE_KEY_FOB: "key_fob",
|
|
23
|
+
}
|
|
24
|
+
|
|
10
25
|
|
|
11
26
|
@RVMDecoder.register(
|
|
12
27
|
"device_table.vas_keyper.devices", device_table_pb2.VasKeyperDevices
|
|
13
28
|
)
|
|
14
29
|
def decode_vas_keyper_devices(m: device_table_pb2.VasKeyperDevices) -> dict[str, Any]:
|
|
15
|
-
"""device_table.vas_keyper.devices — a
|
|
30
|
+
"""device_table.vas_keyper.devices — a key (phone, key card or fob).
|
|
31
|
+
|
|
32
|
+
Covers every driver's keys. A deleted key isn't removed; it's resent
|
|
33
|
+
as inactive.
|
|
16
34
|
|
|
17
35
|
Fields (partial updates, so each only when sent):
|
|
36
|
+
deviceName: str — phone keys, e.g. the phone's name
|
|
37
|
+
keyType: str ("phone" | "key_card" | "key_fob"; key_fob inferred)
|
|
18
38
|
mappedIdentityId: str — the GraphQL device's `mappedIdentityId`
|
|
19
|
-
hrid: str — short human-readable id
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
39
|
+
hrid: str — short human-readable id (key card)
|
|
40
|
+
profileId: str — the driver profile the key belongs to
|
|
41
|
+
publicKey: str — hex; phone keys
|
|
42
|
+
keyRevision: int — key table revision when the entry was last written
|
|
43
|
+
keyStatus: str ("active" | "inactive" | "waiting_to_pair" |
|
|
44
|
+
"pairing"); inactive covers unpaired, no longer paired and
|
|
45
|
+
deleted keys
|
|
46
|
+
infoC: int — 1 while active, 2147483647 while inactive, else the
|
|
47
|
+
pairing attempt number
|
|
48
|
+
infoA, infoB: int — unknown; always equal
|
|
49
|
+
deviceId: str — hex; for a key card, the GraphQL `devices[].id`
|
|
50
|
+
phoneId: str — the phone's UUID; phone keys
|
|
24
51
|
credentialHex: str — hex; likely key material
|
|
25
|
-
keyType: int — raw enum
|
|
26
52
|
active: bool
|
|
27
53
|
"""
|
|
28
54
|
result: dict[str, Any] = {}
|
|
55
|
+
if m.HasField("label"):
|
|
56
|
+
if (v := _present(m.label, "name")) is not None:
|
|
57
|
+
result["deviceName"] = v
|
|
58
|
+
if (v := _present(m.label, "key_type")) is not None:
|
|
59
|
+
result["keyType"] = _enum(_KEY_TYPE_MAP, v, what="key type")
|
|
29
60
|
if m.HasField("device"):
|
|
30
61
|
for field, key in (
|
|
31
62
|
("mapped_identity_id", "mappedIdentityId"),
|
|
32
63
|
("hrid", "hrid"),
|
|
33
|
-
("
|
|
64
|
+
("profile_id", "profileId"),
|
|
65
|
+
("public_key", "publicKey"),
|
|
66
|
+
("revision", "keyRevision"),
|
|
34
67
|
):
|
|
35
68
|
if (v := _present(m.device, field)) is not None:
|
|
36
69
|
result[key] = v
|
|
@@ -42,18 +75,25 @@ def decode_vas_keyper_devices(m: device_table_pb2.VasKeyperDevices) -> dict[str,
|
|
|
42
75
|
for field, key in (
|
|
43
76
|
("a", "infoA"),
|
|
44
77
|
("c", "infoC"),
|
|
45
|
-
("status", "infoStatus"),
|
|
46
78
|
("b", "infoB"),
|
|
47
79
|
):
|
|
48
80
|
if (v := _present(credentials.info, field)) is not None:
|
|
49
81
|
result[key] = v
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if
|
|
82
|
+
if (v := _present(credentials.info, "status")) is not None:
|
|
83
|
+
result["keyStatus"] = _enum(_KEY_STATUS_MAP, v, what="key status")
|
|
84
|
+
for field in ("card", "fob", "phone"):
|
|
85
|
+
if not credentials.HasField(field):
|
|
86
|
+
continue
|
|
87
|
+
material = getattr(credentials, field)
|
|
88
|
+
if (ident := _present(material, "id")) is not None:
|
|
89
|
+
if field == "phone" and len(ident) == 16:
|
|
90
|
+
result["phoneId"] = str(uuid.UUID(bytes=ident))
|
|
91
|
+
else:
|
|
92
|
+
result["deviceId"] = ident.hex()
|
|
93
|
+
if (cred := _present(material, "credential")) is not None:
|
|
54
94
|
result["credentialHex"] = cred.hex()
|
|
55
95
|
if (v := _present(credentials, "key_type")) is not None:
|
|
56
|
-
result["keyType"] = v
|
|
96
|
+
result["keyType"] = _enum(_KEY_TYPE_MAP, v, what="key type")
|
|
57
97
|
if (v := _present(credentials, "active")) is not None:
|
|
58
98
|
result["active"] = v
|
|
59
99
|
return result
|