leapmotor-api 0.1.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.
@@ -0,0 +1,34 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.12", "3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install dependencies
25
+ run: pip install -e ".[dev]"
26
+
27
+ - name: Lint with ruff
28
+ run: ruff check src/ tests/
29
+
30
+ - name: Type check with mypy
31
+ run: mypy src/
32
+
33
+ - name: Run tests
34
+ run: pytest --cov=leapmotor_api --cov-report=term-missing
@@ -0,0 +1,51 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ name: Build distribution
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Set up Python
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.12"
21
+
22
+ - name: Install build tools
23
+ run: pip install build
24
+
25
+ - name: Build package
26
+ run: python -m build
27
+
28
+ - name: Upload distribution artifacts
29
+ uses: actions/upload-artifact@v4
30
+ with:
31
+ name: dist
32
+ path: dist/
33
+
34
+ publish-pypi:
35
+ name: Publish to PyPI
36
+ needs: build
37
+ runs-on: ubuntu-latest
38
+ environment:
39
+ name: pypi
40
+ url: https://pypi.org/p/leapmotor-api
41
+ permissions:
42
+ id-token: write # trusted publishing
43
+ steps:
44
+ - name: Download distribution artifacts
45
+ uses: actions/download-artifact@v4
46
+ with:
47
+ name: dist
48
+ path: dist/
49
+
50
+ - name: Publish to PyPI
51
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,25 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ *.egg
8
+
9
+ # Virtual environments
10
+ .venv/
11
+ venv/
12
+
13
+ # IDE
14
+ .idea/
15
+ .vscode/
16
+ *.swp
17
+
18
+ # Testing
19
+ .pytest_cache/
20
+ .coverage
21
+ htmlcov/
22
+
23
+ # Distribution
24
+ *.tar.gz
25
+ *.whl
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 markoceri
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,207 @@
1
+ Metadata-Version: 2.4
2
+ Name: leapmotor-api
3
+ Version: 0.1.0
4
+ Summary: Unofficial Python client for the Leapmotor vehicle cloud API
5
+ Project-URL: Homepage, https://github.com/markoceri/leapmotor-api
6
+ Project-URL: Issues, https://github.com/markoceri/leapmotor-api/issues
7
+ Author: markoceri
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: api,ev,iot,leapmotor,vehicle
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Home Automation
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.12
21
+ Requires-Dist: cryptography>=42.0.0
22
+ Requires-Dist: requests>=2.32.4
23
+ Provides-Extra: dev
24
+ Requires-Dist: mypy>=1.10; extra == 'dev'
25
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
26
+ Requires-Dist: pytest>=8.0; extra == 'dev'
27
+ Requires-Dist: ruff>=0.4; extra == 'dev'
28
+ Provides-Extra: image
29
+ Requires-Dist: pillow>=10.0.0; extra == 'image'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # leapmotor-api
33
+
34
+ Unofficial Python client for the Leapmotor vehicle cloud API.
35
+
36
+ Extracted from the [leapmotor-ha](https://github.com/kerniger/leapmotor-ha) Home Assistant integration
37
+ to provide a reusable, framework-agnostic library.
38
+
39
+ ## Acknowledgments
40
+
41
+ Special thanks to [Jakob Kern](https://github.com/kerniger) for the impressive reverse engineering work on the Leapmotor application and for generously sharing his work.
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install leapmotor-api
47
+ ```
48
+
49
+ ## Quick Start
50
+
51
+ ```python
52
+ from leapmotor_api import LeapmotorApiClient
53
+
54
+ client = LeapmotorApiClient(
55
+ username="user@example.com",
56
+ password="password",
57
+ app_cert_path="/path/to/app_cert.pem",
58
+ app_key_path="/path/to/app_key.pem",
59
+ language="it-IT", # default: en-GB
60
+ )
61
+
62
+ client.login()
63
+ vehicles = client.get_vehicle_list()
64
+
65
+ for vehicle in vehicles:
66
+ print(f"{vehicle.vin} ({vehicle.car_type}) — {vehicle.nickname}")
67
+ status = client.get_vehicle_status(vehicle)
68
+ print(f" Battery: {status.battery.soc}%")
69
+ print(f" Range: {status.battery.expected_mileage} km")
70
+ print(f" Odometer: {status.driving.total_mileage} km")
71
+
72
+ client.close()
73
+ ```
74
+
75
+ ## Typed Models vs Raw Data
76
+
77
+ The library exposes two ways to access vehicle data:
78
+
79
+ ### Typed models (recommended)
80
+
81
+ `get_vehicle_status()` returns a `VehicleStatus` dataclass with typed sub-objects:
82
+
83
+ ```python
84
+ status = client.get_vehicle_status(vehicle)
85
+
86
+ # Battery & charging
87
+ status.battery.soc # int | None — state of charge %
88
+ status.battery.expected_mileage # int | None — remaining range km
89
+ status.battery.is_charging # bool | None
90
+ status.battery.charging_power_kw # float | None
91
+ status.battery.dump_energy_kwh # float | None — available energy in kWh
92
+
93
+ # Driving
94
+ status.driving.total_mileage # int | None — odometer km
95
+ status.driving.speed # int | None
96
+ status.driving.is_parked # bool | None
97
+
98
+ # Location
99
+ status.location.latitude # float | None
100
+ status.location.longitude # float | None
101
+
102
+ # Climate
103
+ status.climate.ac_switch # bool | None
104
+ status.climate.outdoor_temp # int | None
105
+
106
+ # Doors & locks
107
+ status.doors.is_locked # bool | None
108
+
109
+ # Windows
110
+ status.windows.left_front_window_percent # int | None
111
+
112
+ # Tire pressure
113
+ status.tires.front_left_bar # float | None — pressure in bar
114
+ status.tires.all_ok # bool | None — all pressures normal
115
+
116
+ # Connectivity
117
+ status.connectivity.bluetooth_state # bool | None
118
+
119
+ # Timestamps
120
+ status.collect_time # datetime | None
121
+ ```
122
+
123
+ ### Raw API data
124
+
125
+ For forward-compatibility or debugging, use `get_vehicle_raw_status()`:
126
+
127
+ ```python
128
+ raw = client.get_vehicle_raw_status(vehicle)
129
+ # Returns the full API JSON dict with signal codes, config, etc.
130
+ # raw["data"]["signal"]["1204"] → battery SOC
131
+ # raw["data"]["config"]["3"] → charging plan
132
+ ```
133
+
134
+ The `VehicleStatus` object also retains the raw dict in `status.raw` for convenience.
135
+
136
+ ## Async Usage
137
+
138
+ ```python
139
+ from leapmotor_api import LeapmotorApiClient
140
+ from leapmotor_api.async_client import AsyncLeapmotorApiClient
141
+
142
+ sync_client = LeapmotorApiClient(
143
+ username="user@example.com",
144
+ password="password",
145
+ app_cert_path="/path/to/app_cert.pem",
146
+ app_key_path="/path/to/app_key.pem",
147
+ language="it-IT",
148
+ )
149
+ client = AsyncLeapmotorApiClient(sync_client)
150
+
151
+ await client.login()
152
+ vehicles = await client.get_vehicle_list()
153
+ status = await client.get_vehicle_status(vehicles[0])
154
+ await client.close()
155
+ ```
156
+
157
+ ## Remote Control
158
+
159
+ Remote actions require the vehicle PIN:
160
+
161
+ ```python
162
+ client = LeapmotorApiClient(
163
+ username="user@example.com",
164
+ password="password",
165
+ app_cert_path="/path/to/app_cert.pem",
166
+ app_key_path="/path/to/app_key.pem",
167
+ operation_password="1234",
168
+ language="de-DE",
169
+ )
170
+
171
+ client.login()
172
+ client.lock_vehicle("WLM...")
173
+ client.unlock_vehicle("WLM...")
174
+ client.open_trunk("WLM...")
175
+ client.close_trunk("WLM...")
176
+ client.find_vehicle("WLM...")
177
+ client.open_windows("WLM...")
178
+ client.close_windows("WLM...")
179
+ client.ac_switch("WLM...")
180
+ client.quick_cool("WLM...")
181
+ client.quick_heat("WLM...")
182
+ client.windshield_defrost("WLM...")
183
+ client.open_sunshade("WLM...")
184
+ client.close_sunshade("WLM...")
185
+ client.battery_preheat("WLM...")
186
+ client.set_charge_limit("WLM...", charge_limit_percent=80)
187
+ client.close()
188
+ ```
189
+
190
+ ## License
191
+
192
+ MIT
193
+
194
+ ## Configuration
195
+
196
+ | Parameter | Type | Default | Description |
197
+ |-----------|------|---------|-------------|
198
+ | `username` | `str` | — | Leapmotor account email |
199
+ | `password` | `str` | — | Leapmotor account password |
200
+ | `app_cert_path` | `str` | — | Path to app certificate PEM |
201
+ | `app_key_path` | `str` | — | Path to app private key PEM |
202
+ | `operation_password` | `str \| None` | `None` | Vehicle PIN (required for remote control) |
203
+ | `language` | `str` | `"en-GB"` | API language (`en-GB`, `it-IT`, `de-DE`, `fr-FR`, …) |
204
+ | `verify_ssl` | `bool` | `False` | Verify server TLS certificate |
205
+ | `base_url` | `str` | `DEFAULT_BASE_URL` | API base URL |
206
+ | `timeout` | `int` | `30` | HTTP timeout in seconds |
207
+ | `device_id` | `str \| None` | `None` | Custom device ID (auto-generated if omitted) |
@@ -0,0 +1,176 @@
1
+ # leapmotor-api
2
+
3
+ Unofficial Python client for the Leapmotor vehicle cloud API.
4
+
5
+ Extracted from the [leapmotor-ha](https://github.com/kerniger/leapmotor-ha) Home Assistant integration
6
+ to provide a reusable, framework-agnostic library.
7
+
8
+ ## Acknowledgments
9
+
10
+ Special thanks to [Jakob Kern](https://github.com/kerniger) for the impressive reverse engineering work on the Leapmotor application and for generously sharing his work.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pip install leapmotor-api
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```python
21
+ from leapmotor_api import LeapmotorApiClient
22
+
23
+ client = LeapmotorApiClient(
24
+ username="user@example.com",
25
+ password="password",
26
+ app_cert_path="/path/to/app_cert.pem",
27
+ app_key_path="/path/to/app_key.pem",
28
+ language="it-IT", # default: en-GB
29
+ )
30
+
31
+ client.login()
32
+ vehicles = client.get_vehicle_list()
33
+
34
+ for vehicle in vehicles:
35
+ print(f"{vehicle.vin} ({vehicle.car_type}) — {vehicle.nickname}")
36
+ status = client.get_vehicle_status(vehicle)
37
+ print(f" Battery: {status.battery.soc}%")
38
+ print(f" Range: {status.battery.expected_mileage} km")
39
+ print(f" Odometer: {status.driving.total_mileage} km")
40
+
41
+ client.close()
42
+ ```
43
+
44
+ ## Typed Models vs Raw Data
45
+
46
+ The library exposes two ways to access vehicle data:
47
+
48
+ ### Typed models (recommended)
49
+
50
+ `get_vehicle_status()` returns a `VehicleStatus` dataclass with typed sub-objects:
51
+
52
+ ```python
53
+ status = client.get_vehicle_status(vehicle)
54
+
55
+ # Battery & charging
56
+ status.battery.soc # int | None — state of charge %
57
+ status.battery.expected_mileage # int | None — remaining range km
58
+ status.battery.is_charging # bool | None
59
+ status.battery.charging_power_kw # float | None
60
+ status.battery.dump_energy_kwh # float | None — available energy in kWh
61
+
62
+ # Driving
63
+ status.driving.total_mileage # int | None — odometer km
64
+ status.driving.speed # int | None
65
+ status.driving.is_parked # bool | None
66
+
67
+ # Location
68
+ status.location.latitude # float | None
69
+ status.location.longitude # float | None
70
+
71
+ # Climate
72
+ status.climate.ac_switch # bool | None
73
+ status.climate.outdoor_temp # int | None
74
+
75
+ # Doors & locks
76
+ status.doors.is_locked # bool | None
77
+
78
+ # Windows
79
+ status.windows.left_front_window_percent # int | None
80
+
81
+ # Tire pressure
82
+ status.tires.front_left_bar # float | None — pressure in bar
83
+ status.tires.all_ok # bool | None — all pressures normal
84
+
85
+ # Connectivity
86
+ status.connectivity.bluetooth_state # bool | None
87
+
88
+ # Timestamps
89
+ status.collect_time # datetime | None
90
+ ```
91
+
92
+ ### Raw API data
93
+
94
+ For forward-compatibility or debugging, use `get_vehicle_raw_status()`:
95
+
96
+ ```python
97
+ raw = client.get_vehicle_raw_status(vehicle)
98
+ # Returns the full API JSON dict with signal codes, config, etc.
99
+ # raw["data"]["signal"]["1204"] → battery SOC
100
+ # raw["data"]["config"]["3"] → charging plan
101
+ ```
102
+
103
+ The `VehicleStatus` object also retains the raw dict in `status.raw` for convenience.
104
+
105
+ ## Async Usage
106
+
107
+ ```python
108
+ from leapmotor_api import LeapmotorApiClient
109
+ from leapmotor_api.async_client import AsyncLeapmotorApiClient
110
+
111
+ sync_client = LeapmotorApiClient(
112
+ username="user@example.com",
113
+ password="password",
114
+ app_cert_path="/path/to/app_cert.pem",
115
+ app_key_path="/path/to/app_key.pem",
116
+ language="it-IT",
117
+ )
118
+ client = AsyncLeapmotorApiClient(sync_client)
119
+
120
+ await client.login()
121
+ vehicles = await client.get_vehicle_list()
122
+ status = await client.get_vehicle_status(vehicles[0])
123
+ await client.close()
124
+ ```
125
+
126
+ ## Remote Control
127
+
128
+ Remote actions require the vehicle PIN:
129
+
130
+ ```python
131
+ client = LeapmotorApiClient(
132
+ username="user@example.com",
133
+ password="password",
134
+ app_cert_path="/path/to/app_cert.pem",
135
+ app_key_path="/path/to/app_key.pem",
136
+ operation_password="1234",
137
+ language="de-DE",
138
+ )
139
+
140
+ client.login()
141
+ client.lock_vehicle("WLM...")
142
+ client.unlock_vehicle("WLM...")
143
+ client.open_trunk("WLM...")
144
+ client.close_trunk("WLM...")
145
+ client.find_vehicle("WLM...")
146
+ client.open_windows("WLM...")
147
+ client.close_windows("WLM...")
148
+ client.ac_switch("WLM...")
149
+ client.quick_cool("WLM...")
150
+ client.quick_heat("WLM...")
151
+ client.windshield_defrost("WLM...")
152
+ client.open_sunshade("WLM...")
153
+ client.close_sunshade("WLM...")
154
+ client.battery_preheat("WLM...")
155
+ client.set_charge_limit("WLM...", charge_limit_percent=80)
156
+ client.close()
157
+ ```
158
+
159
+ ## License
160
+
161
+ MIT
162
+
163
+ ## Configuration
164
+
165
+ | Parameter | Type | Default | Description |
166
+ |-----------|------|---------|-------------|
167
+ | `username` | `str` | — | Leapmotor account email |
168
+ | `password` | `str` | — | Leapmotor account password |
169
+ | `app_cert_path` | `str` | — | Path to app certificate PEM |
170
+ | `app_key_path` | `str` | — | Path to app private key PEM |
171
+ | `operation_password` | `str \| None` | `None` | Vehicle PIN (required for remote control) |
172
+ | `language` | `str` | `"en-GB"` | API language (`en-GB`, `it-IT`, `de-DE`, `fr-FR`, …) |
173
+ | `verify_ssl` | `bool` | `False` | Verify server TLS certificate |
174
+ | `base_url` | `str` | `DEFAULT_BASE_URL` | API base URL |
175
+ | `timeout` | `int` | `30` | HTTP timeout in seconds |
176
+ | `device_id` | `str \| None` | `None` | Custom device ID (auto-generated if omitted) |
@@ -0,0 +1,63 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "leapmotor-api"
7
+ version = "0.1.0"
8
+ description = "Unofficial Python client for the Leapmotor vehicle cloud API"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.12"
13
+ authors = [
14
+ { name = "markoceri" },
15
+ ]
16
+ keywords = ["leapmotor", "ev", "vehicle", "api", "iot"]
17
+ classifiers = [
18
+ "Development Status :: 4 - Beta",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Home Automation",
25
+ "Topic :: Software Development :: Libraries :: Python Modules",
26
+ "Typing :: Typed",
27
+ ]
28
+ dependencies = [
29
+ "requests>=2.32.4",
30
+ "cryptography>=42.0.0",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ image = [
35
+ "Pillow>=10.0.0",
36
+ ]
37
+ dev = [
38
+ "pytest>=8.0",
39
+ "pytest-cov>=5.0",
40
+ "mypy>=1.10",
41
+ "ruff>=0.4",
42
+ ]
43
+
44
+ [project.urls]
45
+ Homepage = "https://github.com/markoceri/leapmotor-api"
46
+ Issues = "https://github.com/markoceri/leapmotor-api/issues"
47
+
48
+ [tool.hatch.build.targets.wheel]
49
+ packages = ["src/leapmotor_api"]
50
+
51
+ [tool.mypy]
52
+ python_version = "3.12"
53
+ strict = true
54
+
55
+ [tool.ruff]
56
+ target-version = "py312"
57
+ line-length = 120
58
+
59
+ [tool.ruff.lint]
60
+ select = ["E", "F", "W", "I", "N", "UP", "S", "B", "A", "C4", "SIM", "TCH"]
61
+
62
+ [tool.pytest.ini_options]
63
+ testpaths = ["tests"]
@@ -0,0 +1,93 @@
1
+ """Leapmotor API — Unofficial Python client for the Leapmotor vehicle cloud API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __version__ = "0.1.0"
6
+
7
+ from .client import LeapmotorApiClient, normalize_vehicle
8
+ from .const import (
9
+ DEFAULT_BASE_URL,
10
+ DEFAULT_LANGUAGE,
11
+ REMOTE_ACTION_SPECS,
12
+ REMOTE_CTL_AC_SWITCH,
13
+ REMOTE_CTL_BATTERY_PREHEAT,
14
+ REMOTE_CTL_FIND_CAR,
15
+ REMOTE_CTL_LOCK,
16
+ REMOTE_CTL_QUICK_COOL,
17
+ REMOTE_CTL_QUICK_HEAT,
18
+ REMOTE_CTL_SUNSHADE,
19
+ REMOTE_CTL_SUNSHADE_CLOSE,
20
+ REMOTE_CTL_SUNSHADE_OPEN,
21
+ REMOTE_CTL_TRUNK,
22
+ REMOTE_CTL_TRUNK_CLOSE,
23
+ REMOTE_CTL_TRUNK_OPEN,
24
+ REMOTE_CTL_UNLOCK,
25
+ REMOTE_CTL_WINDSHIELD_DEFROST,
26
+ REMOTE_CTL_WINDOWS,
27
+ REMOTE_CTL_WINDOWS_CLOSE,
28
+ REMOTE_CTL_WINDOWS_OPEN,
29
+ )
30
+ from .exceptions import (
31
+ LeapmotorAccountCertError,
32
+ LeapmotorApiError,
33
+ LeapmotorAuthError,
34
+ LeapmotorMissingAppCertError,
35
+ )
36
+ from .models import (
37
+ BatteryStatus,
38
+ ClimateStatus,
39
+ ConnectivityStatus,
40
+ DoorStatus,
41
+ DrivingStatus,
42
+ IgnitionStatus,
43
+ LocationStatus,
44
+ RemoteActionResult,
45
+ RemoteActionSpec,
46
+ TirePressure,
47
+ Vehicle,
48
+ VehicleStatus,
49
+ WindowStatus,
50
+ )
51
+
52
+ __all__ = [
53
+ "__version__",
54
+ "BatteryStatus",
55
+ "ClimateStatus",
56
+ "ConnectivityStatus",
57
+ "DEFAULT_BASE_URL",
58
+ "DEFAULT_LANGUAGE",
59
+ "DoorStatus",
60
+ "DrivingStatus",
61
+ "IgnitionStatus",
62
+ "LeapmotorAccountCertError",
63
+ "LeapmotorApiClient",
64
+ "LeapmotorApiError",
65
+ "LeapmotorAuthError",
66
+ "LeapmotorMissingAppCertError",
67
+ "LocationStatus",
68
+ "REMOTE_ACTION_SPECS",
69
+ "REMOTE_CTL_AC_SWITCH",
70
+ "REMOTE_CTL_BATTERY_PREHEAT",
71
+ "REMOTE_CTL_FIND_CAR",
72
+ "REMOTE_CTL_LOCK",
73
+ "REMOTE_CTL_QUICK_COOL",
74
+ "REMOTE_CTL_QUICK_HEAT",
75
+ "REMOTE_CTL_SUNSHADE",
76
+ "REMOTE_CTL_SUNSHADE_CLOSE",
77
+ "REMOTE_CTL_SUNSHADE_OPEN",
78
+ "REMOTE_CTL_TRUNK",
79
+ "REMOTE_CTL_TRUNK_CLOSE",
80
+ "REMOTE_CTL_TRUNK_OPEN",
81
+ "REMOTE_CTL_UNLOCK",
82
+ "REMOTE_CTL_WINDSHIELD_DEFROST",
83
+ "REMOTE_CTL_WINDOWS",
84
+ "REMOTE_CTL_WINDOWS_CLOSE",
85
+ "REMOTE_CTL_WINDOWS_OPEN",
86
+ "RemoteActionResult",
87
+ "RemoteActionSpec",
88
+ "TirePressure",
89
+ "Vehicle",
90
+ "VehicleStatus",
91
+ "WindowStatus",
92
+ "normalize_vehicle",
93
+ ]