rivian-python-client 2.2.0b1__py3-none-any.whl → 2.2.0b3__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/body.py +70 -46
- rivian/parallax/charging.py +37 -37
- rivian/parallax/comfort.py +88 -91
- rivian/parallax/device_table.py +56 -16
- rivian/parallax/dynamics.py +51 -61
- rivian/parallax/energy.py +12 -17
- rivian/parallax/energy_edge_compute.py +6 -8
- rivian/parallax/gearguard_streaming.py +9 -9
- rivian/parallax/geofence.py +11 -5
- rivian/parallax/holiday_celebration.py +47 -9
- rivian/parallax/navigation.py +12 -32
- rivian/parallax/ota.py +28 -25
- 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 +1 -1
- rivian/parallax/proto/charging_pb2.py +10 -10
- rivian/parallax/proto/comfort.proto +44 -37
- rivian/parallax/proto/comfort_pb2.py +44 -44
- rivian/parallax/proto/comfort_pb2.pyi +57 -43
- rivian/parallax/proto/departure.proto +1 -1
- rivian/parallax/proto/departure_pb2.py +11 -11
- 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/dynamics.proto +11 -11
- rivian/parallax/proto/dynamics_pb2.py +38 -38
- rivian/parallax/proto/energy.proto +5 -5
- rivian/parallax/proto/energy_edge_compute.proto +11 -11
- rivian/parallax/proto/energy_edge_compute_pb2.py +11 -11
- rivian/parallax/proto/energy_pb2.py +11 -11
- 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 +25 -14
- rivian/parallax/proto/holiday_celebration_pb2.py +12 -6
- rivian/parallax/proto/holiday_celebration_pb2.pyi +44 -25
- rivian/parallax/proto/navigation.proto +10 -10
- rivian/parallax/proto/navigation_pb2.py +40 -40
- rivian/parallax/proto/ota.proto +19 -12
- rivian/parallax/proto/ota_pb2.py +24 -22
- rivian/parallax/proto/ota_pb2.pyi +26 -19
- rivian/parallax/proto/security.proto +1 -1
- rivian/parallax/proto/security_pb2.py +22 -22
- rivian/parallax/proto/vehicle.proto +18 -18
- 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 +39 -39
- rivian/parallax/vehicle.py +56 -55
- rivian/parallax/vehicle_access.py +26 -5
- {rivian_python_client-2.2.0b1.dist-info → rivian_python_client-2.2.0b3.dist-info}/METADATA +1 -1
- rivian_python_client-2.2.0b3.dist-info/RECORD +94 -0
- rivian_python_client-2.2.0b1.dist-info/RECORD +0 -94
- {rivian_python_client-2.2.0b1.dist-info → rivian_python_client-2.2.0b3.dist-info}/WHEEL +0 -0
rivian/__version__.py
CHANGED
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
|
|
|
@@ -211,9 +211,9 @@ def decode_time_estimation(m: charging_pb2.TimeEstimation) -> dict[str, Any]:
|
|
|
211
211
|
|
|
212
212
|
|
|
213
213
|
_CHARGER_STATUS_MAP: Final[dict[int, str]] = {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
214
|
+
charging_pb2.CHARGER_STATUS_NOT_CONNECTED: "chrgr_sts_not_connected",
|
|
215
|
+
charging_pb2.CHARGER_STATUS_CONNECTED_NO_CHARGE: "chrgr_sts_connected_no_chrg",
|
|
216
|
+
charging_pb2.CHARGER_STATUS_CONNECTED_CHARGING: "chrgr_sts_connected_charging",
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
|
rivian/parallax/comfort.py
CHANGED
|
@@ -17,9 +17,7 @@ def decode_hvac_settings_status(m: comfort_pb2.HvacSettingsStatus) -> dict[str,
|
|
|
17
17
|
Fields:
|
|
18
18
|
hvacTargetTemperature: float (°C; 63.5 = "HI", set while defrosting)
|
|
19
19
|
"""
|
|
20
|
-
|
|
21
|
-
return {}
|
|
22
|
-
return {"hvacTargetTemperature": round(v, 1)}
|
|
20
|
+
return {"hvacTargetTemperature": round(m.target_temperature, 1)}
|
|
23
21
|
|
|
24
22
|
|
|
25
23
|
@RVMDecoder.register("comfort.user_modes.state", comfort_pb2.UserModesState)
|
|
@@ -34,60 +32,69 @@ def decode_user_modes_state(m: comfort_pb2.UserModesState) -> dict[str, Any]:
|
|
|
34
32
|
|
|
35
33
|
|
|
36
34
|
_CLIMATE_HOLD_AVAILABILITY_MAP: Final[dict[int, str]] = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
comfort_pb2.CLIMATE_HOLD_AVAILABILITY_UNSPECIFIED: "unspecified",
|
|
36
|
+
comfort_pb2.CLIMATE_HOLD_AVAILABLE: "available",
|
|
37
|
+
comfort_pb2.CLIMATE_HOLD_CONTROLLABLE: "controllable",
|
|
38
|
+
comfort_pb2.CLIMATE_HOLD_UNAVAILABLE: "unavailable",
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
_CLIMATE_HOLD_STATUS_MAP: Final[dict[int, str]] = {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
comfort_pb2.CLIMATE_HOLD_STATUS_UNSPECIFIED: "unspecified",
|
|
43
|
+
comfort_pb2.CLIMATE_HOLD_STATUS_UNAVAILABLE: "unavailable",
|
|
44
|
+
comfort_pb2.CLIMATE_HOLD_STATUS_OFF: "off",
|
|
45
|
+
comfort_pb2.CLIMATE_HOLD_STATUS_ON: "on",
|
|
46
|
+
comfort_pb2.CLIMATE_HOLD_STATUS_FAULT: "fault",
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
_CLIMATE_HOLD_UNAVAILABILITY_REASON_MAP: Final[dict[int, str]] = {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
comfort_pb2.CLIMATE_HOLD_UNAVAILABILITY_UNSPECIFIED: "unspecified",
|
|
51
|
+
comfort_pb2.CLIMATE_HOLD_UNAVAILABILITY_UNKNOWN: "unknown",
|
|
52
|
+
comfort_pb2.CLIMATE_HOLD_UNAVAILABILITY_LOW_SOC: "low_soc",
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
_PET_MODE_STATE_MAP: Final[dict[int, str]] = {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
comfort_pb2.PET_MODE_OFF: "off",
|
|
57
|
+
comfort_pb2.PET_MODE_ON: "on",
|
|
58
|
+
comfort_pb2.PET_MODE_DISABLED: "disabled",
|
|
59
|
+
comfort_pb2.PET_MODE_FAULTY: "faulty",
|
|
62
60
|
}
|
|
63
61
|
|
|
64
62
|
_PET_MODE_TEMPERATURE_MAP: Final[dict[int, str]] = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
comfort_pb2.PET_MODE_TEMPERATURE_DEFAULT: "default",
|
|
64
|
+
comfort_pb2.PET_MODE_TEMPERATURE_COLD: "cold",
|
|
65
|
+
comfort_pb2.PET_MODE_TEMPERATURE_HOT: "hot",
|
|
66
|
+
comfort_pb2.PET_MODE_TEMPERATURE_FAULTY: "faulty",
|
|
69
67
|
}
|
|
70
68
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
69
|
+
# Seat keys use the GraphQL names: row 1 is "Front", row 2 "Rear", row 3
|
|
70
|
+
# "ThirdRow".
|
|
71
|
+
_CABIN_SURFACE_MAP: Final[dict[int, str]] = {
|
|
72
|
+
comfort_pb2.STEERING_WHEEL: "steeringWheel",
|
|
73
|
+
comfort_pb2.REAR_GLASS: "rearGlass",
|
|
74
|
+
comfort_pb2.FRONT_GLASS: "frontGlass",
|
|
75
|
+
comfort_pb2.SIDEVIEW_MIRRORS: "sideviewMirrors",
|
|
76
|
+
comfort_pb2.SEAT_ROW_1_LEFT: "seatFrontLeft",
|
|
77
|
+
comfort_pb2.SEAT_ROW_1_MIDDLE: "seatFrontMiddle",
|
|
78
|
+
comfort_pb2.SEAT_ROW_1_RIGHT: "seatFrontRight",
|
|
79
|
+
comfort_pb2.SEAT_ROW_2_LEFT: "seatRearLeft",
|
|
80
|
+
comfort_pb2.SEAT_ROW_2_MIDDLE: "seatRearMiddle",
|
|
81
|
+
comfort_pb2.SEAT_ROW_2_RIGHT: "seatRearRight",
|
|
82
|
+
comfort_pb2.SEAT_ROW_3_LEFT: "seatThirdRowLeft",
|
|
83
|
+
comfort_pb2.SEAT_ROW_3_MIDDLE: "seatThirdRowMiddle",
|
|
84
|
+
comfort_pb2.SEAT_ROW_3_RIGHT: "seatThirdRowRight",
|
|
85
|
+
comfort_pb2.WIPER_AREA: "wiperArea",
|
|
79
86
|
}
|
|
80
87
|
|
|
81
|
-
|
|
88
|
+
_CONDITIONING_LEVEL_MAP: Final[dict[int | None, str]] = {
|
|
82
89
|
None: "Off",
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
90
|
+
comfort_pb2.CONDITIONING_LEVEL_1: "Level_1",
|
|
91
|
+
comfort_pb2.CONDITIONING_LEVEL_2: "Level_2",
|
|
92
|
+
comfort_pb2.CONDITIONING_LEVEL_3: "Level_3",
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
95
|
+
_CONDITIONING_TYPE_MAP: Final[dict[int, str]] = {
|
|
96
|
+
comfort_pb2.CONDITIONING_HEAT: "Heat",
|
|
97
|
+
comfort_pb2.CONDITIONING_VENT: "Vent",
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
|
|
@@ -123,12 +130,10 @@ def decode_cabin_temperatures(m: comfort_pb2.CabinTemperatures) -> dict[str, Any
|
|
|
123
130
|
cabinClimateDriverTemperature: float (°C) — set point, same as
|
|
124
131
|
`hvacTargetTemperature`
|
|
125
132
|
"""
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
result["cabinClimateDriverTemperature"] = round(v, 1)
|
|
131
|
-
return result
|
|
133
|
+
return {
|
|
134
|
+
"cabinClimateInteriorTemperature": round(m.interior_temperature, 1),
|
|
135
|
+
"cabinClimateDriverTemperature": round(m.driver_set_point, 1),
|
|
136
|
+
}
|
|
132
137
|
|
|
133
138
|
|
|
134
139
|
@RVMDecoder.register(
|
|
@@ -137,24 +142,20 @@ def decode_cabin_temperatures(m: comfort_pb2.CabinTemperatures) -> dict[str, Any
|
|
|
137
142
|
def decode_cabin_ventilation(m: comfort_pb2.CabinVentilationSetting) -> dict[str, Any]:
|
|
138
143
|
"""comfort.cabin.cabin_ventilation_setting — passive ventilation settings.
|
|
139
144
|
|
|
140
|
-
Fields
|
|
145
|
+
Fields:
|
|
141
146
|
cabinVentilationEnabled: bool
|
|
142
|
-
cabinVentilationMode: str ("AUTO" | "MANUAL" | "OFF")
|
|
147
|
+
cabinVentilationMode: str | None ("AUTO" | "MANUAL" | "OFF")
|
|
143
148
|
cabinVentilationWindowsPosition: int (percent open)
|
|
144
149
|
cabinVentilationSunroofPosition: int (percent open)
|
|
145
150
|
cabinVentilationDuration: int (minutes)
|
|
146
151
|
"""
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
):
|
|
155
|
-
if (v := _present(m, field)) is not None:
|
|
156
|
-
result[key] = v
|
|
157
|
-
return result
|
|
152
|
+
return {
|
|
153
|
+
"cabinVentilationEnabled": m.enabled,
|
|
154
|
+
"cabinVentilationMode": m.mode or None,
|
|
155
|
+
"cabinVentilationWindowsPosition": m.windows_position,
|
|
156
|
+
"cabinVentilationSunroofPosition": m.sunroof_position,
|
|
157
|
+
"cabinVentilationDuration": m.duration,
|
|
158
|
+
}
|
|
158
159
|
|
|
159
160
|
|
|
160
161
|
@RVMDecoder.register(
|
|
@@ -176,29 +177,26 @@ def decode_climate_hold_status(m: comfort_pb2.ClimateHoldStatus) -> dict[str, An
|
|
|
176
177
|
Fields:
|
|
177
178
|
climateHoldStatus: str ("off" | "on" | "unavailable" | "fault" | "unspecified")
|
|
178
179
|
climateHoldAvailability: str
|
|
179
|
-
climateHoldUnavailabilityReason: str
|
|
180
|
-
climateHoldEndTime: int (epoch seconds
|
|
180
|
+
climateHoldUnavailabilityReason: str | None — None when unspecified
|
|
181
|
+
climateHoldEndTime: int | None (epoch seconds; None unless a hold runs)
|
|
181
182
|
"""
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if m.end_time.seconds:
|
|
200
|
-
result["climateHoldEndTime"] = m.end_time.seconds
|
|
201
|
-
return result
|
|
183
|
+
reason = _enum(
|
|
184
|
+
_CLIMATE_HOLD_UNAVAILABILITY_REASON_MAP,
|
|
185
|
+
m.unavailability_reason,
|
|
186
|
+
what="climate hold unavailability reason",
|
|
187
|
+
)
|
|
188
|
+
return {
|
|
189
|
+
"climateHoldStatus": _enum(
|
|
190
|
+
_CLIMATE_HOLD_STATUS_MAP, m.status, what="climate hold status"
|
|
191
|
+
),
|
|
192
|
+
"climateHoldAvailability": _enum(
|
|
193
|
+
_CLIMATE_HOLD_AVAILABILITY_MAP,
|
|
194
|
+
m.availability,
|
|
195
|
+
what="climate hold availability",
|
|
196
|
+
),
|
|
197
|
+
"climateHoldUnavailabilityReason": None if reason == "unspecified" else reason,
|
|
198
|
+
"climateHoldEndTime": m.end_time.seconds or None,
|
|
199
|
+
}
|
|
202
200
|
|
|
203
201
|
|
|
204
202
|
@RVMDecoder.register(
|
|
@@ -247,23 +245,22 @@ def decode_seat_conditioning(m: comfort_pb2.SeatConditioningStatus) -> dict[str,
|
|
|
247
245
|
seatThirdRowLeftHeat, seatThirdRowRightHeat: str
|
|
248
246
|
("Off" | "Level_1" | "Level_2" | "Level_3")
|
|
249
247
|
steeringWheelHeat: str ("Off" | "Level_1")
|
|
248
|
+
plus <surface>Heat/Vent for any other surface sent (middle seats,
|
|
249
|
+
rearGlass, frontGlass, sideviewMirrors, wiperArea)
|
|
250
250
|
|
|
251
|
-
|
|
251
|
+
A surface sent without a state is off.
|
|
252
252
|
"""
|
|
253
253
|
result: dict[str, Any] = {}
|
|
254
|
-
for
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
key = (
|
|
260
|
-
f"{_SEAT_CONDITIONING_MAP[cid]}{_SEAT_CONDITIONING_TYPE_MAP[hvac_type]}"
|
|
261
|
-
)
|
|
262
|
-
result[key] = _SEAT_CONDITIONING_STATUS_MAP.get(state_val, state_val)
|
|
254
|
+
for surface in m.surface:
|
|
255
|
+
surface_id, hvac_type = surface.id, surface.type
|
|
256
|
+
state_val = _present(surface, "state")
|
|
257
|
+
if surface_id in _CABIN_SURFACE_MAP and hvac_type in _CONDITIONING_TYPE_MAP:
|
|
258
|
+
key = f"{_CABIN_SURFACE_MAP[surface_id]}{_CONDITIONING_TYPE_MAP[hvac_type]}"
|
|
259
|
+
result[key] = _CONDITIONING_LEVEL_MAP.get(state_val, state_val)
|
|
263
260
|
else:
|
|
264
261
|
_LOGGER.debug(
|
|
265
|
-
"Unknown
|
|
266
|
-
|
|
262
|
+
"Unknown cabin surface %s (hvac_type %s; state %s)",
|
|
263
|
+
surface_id,
|
|
267
264
|
hvac_type,
|
|
268
265
|
state_val,
|
|
269
266
|
)
|
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
|