lojack-api 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lojack_api/__init__.py +73 -0
- lojack_api/api.py +465 -0
- lojack_api/auth.py +285 -0
- lojack_api/device.py +343 -0
- lojack_api/exceptions.py +93 -0
- lojack_api/models.py +285 -0
- lojack_api/py.typed +0 -0
- lojack_api/transport.py +184 -0
- lojack_api-0.5.0.dist-info/METADATA +317 -0
- lojack_api-0.5.0.dist-info/RECORD +13 -0
- lojack_api-0.5.0.dist-info/WHEEL +5 -0
- lojack_api-0.5.0.dist-info/licenses/LICENSE +14 -0
- lojack_api-0.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lojack_api
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: An async Python client library for the LoJack API, designed for Home Assistant integrations.
|
|
5
|
+
Author: LoJack Clients Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/devinslick/lojack_api
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/devinslick/lojack_api/issues
|
|
9
|
+
Keywords: lojack,home-assistant,async,api-client,vehicle-tracking
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Framework :: AsyncIO
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Home Automation
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: aiohttp<4.0,>=3.8
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
30
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff>=0.1; extra == "dev"
|
|
32
|
+
Requires-Dist: flake8>=4.0; extra == "dev"
|
|
33
|
+
Requires-Dist: aioresponses>=0.7; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# lojack_api
|
|
37
|
+
|
|
38
|
+
An async Python client library for the Spireon LoJack API, designed for Home Assistant integrations.
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
- **Async-first design** - Built with `asyncio` and `aiohttp` for non-blocking I/O
|
|
43
|
+
- **No httpx dependency** - Uses `aiohttp` to avoid version conflicts with Home Assistant
|
|
44
|
+
- **Spireon LoJack API** - Full support for the Spireon identity and services APIs
|
|
45
|
+
- **Session management** - Automatic token refresh and session resumption support
|
|
46
|
+
- **Type hints** - Full typing support with `py.typed` marker
|
|
47
|
+
- **Clean device abstractions** - Device and Vehicle wrappers with convenient methods
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# From the repository
|
|
53
|
+
pip install .
|
|
54
|
+
|
|
55
|
+
# With development dependencies
|
|
56
|
+
pip install .[dev]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Quick Start
|
|
60
|
+
|
|
61
|
+
### Basic Usage
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import asyncio
|
|
65
|
+
from lojack_api import LoJackClient
|
|
66
|
+
|
|
67
|
+
async def main():
|
|
68
|
+
# Create and authenticate (uses default Spireon URLs)
|
|
69
|
+
async with await LoJackClient.create(
|
|
70
|
+
"your_username",
|
|
71
|
+
"your_password"
|
|
72
|
+
) as client:
|
|
73
|
+
# List all devices/vehicles
|
|
74
|
+
devices = await client.list_devices()
|
|
75
|
+
|
|
76
|
+
for device in devices:
|
|
77
|
+
print(f"Device: {device.name} ({device.id})")
|
|
78
|
+
|
|
79
|
+
# Get current location
|
|
80
|
+
location = await device.get_location()
|
|
81
|
+
if location:
|
|
82
|
+
print(f" Location: {location.latitude}, {location.longitude}")
|
|
83
|
+
|
|
84
|
+
asyncio.run(main())
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Session Resumption (for Home Assistant)
|
|
88
|
+
|
|
89
|
+
For Home Assistant integrations, you can persist authentication across restarts:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from lojack_api import LoJackClient, AuthArtifacts
|
|
93
|
+
|
|
94
|
+
# First time - login and save auth
|
|
95
|
+
async def initial_login(username, password):
|
|
96
|
+
client = await LoJackClient.create(username, password)
|
|
97
|
+
auth_data = client.export_auth().to_dict()
|
|
98
|
+
# Save auth_data to Home Assistant storage
|
|
99
|
+
await client.close()
|
|
100
|
+
return auth_data
|
|
101
|
+
|
|
102
|
+
# Later - resume without re-entering password
|
|
103
|
+
async def resume_session(auth_data, username=None, password=None):
|
|
104
|
+
auth = AuthArtifacts.from_dict(auth_data)
|
|
105
|
+
# Pass credentials for auto-refresh if token expires
|
|
106
|
+
client = await LoJackClient.from_auth(auth, username=username, password=password)
|
|
107
|
+
return client
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Using External aiohttp Session
|
|
111
|
+
|
|
112
|
+
For Home Assistant integrations, pass the shared session:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from aiohttp import ClientSession
|
|
116
|
+
from lojack_api import LoJackClient
|
|
117
|
+
|
|
118
|
+
async def setup(hass_session: ClientSession, username, password):
|
|
119
|
+
client = await LoJackClient.create(
|
|
120
|
+
username,
|
|
121
|
+
password,
|
|
122
|
+
session=hass_session # Won't be closed when client closes
|
|
123
|
+
)
|
|
124
|
+
return client
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Working with Vehicles
|
|
128
|
+
|
|
129
|
+
Vehicles have additional properties and commands:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from lojack_api import Vehicle
|
|
133
|
+
|
|
134
|
+
async def vehicle_example(client):
|
|
135
|
+
devices = await client.list_devices()
|
|
136
|
+
|
|
137
|
+
for device in devices:
|
|
138
|
+
if isinstance(device, Vehicle):
|
|
139
|
+
print(f"Vehicle: {device.name}")
|
|
140
|
+
print(f" VIN: {device.vin}")
|
|
141
|
+
print(f" Make: {device.make} {device.model} ({device.year})")
|
|
142
|
+
|
|
143
|
+
# Vehicle-specific commands
|
|
144
|
+
await device.start_engine()
|
|
145
|
+
await device.honk_horn()
|
|
146
|
+
await device.flash_lights()
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Device Commands
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
# All devices support these commands
|
|
153
|
+
await device.lock(message="Please return this device")
|
|
154
|
+
await device.unlock()
|
|
155
|
+
await device.ring(duration=30)
|
|
156
|
+
await device.request_location_update()
|
|
157
|
+
|
|
158
|
+
# Get location history
|
|
159
|
+
async for location in device.get_history(limit=100):
|
|
160
|
+
print(f"{location.timestamp}: {location.latitude}, {location.longitude}")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## API Reference
|
|
164
|
+
|
|
165
|
+
### LoJackClient
|
|
166
|
+
|
|
167
|
+
The main entry point for the API.
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
# Factory methods (using default Spireon URLs)
|
|
171
|
+
client = await LoJackClient.create(username, password)
|
|
172
|
+
client = await LoJackClient.from_auth(auth_artifacts)
|
|
173
|
+
|
|
174
|
+
# With custom URLs
|
|
175
|
+
client = await LoJackClient.create(
|
|
176
|
+
username,
|
|
177
|
+
password,
|
|
178
|
+
identity_url="https://identity.spireon.com",
|
|
179
|
+
services_url="https://services.spireon.com/v0/rest"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Properties
|
|
183
|
+
client.is_authenticated # bool
|
|
184
|
+
client.user_id # Optional[str]
|
|
185
|
+
|
|
186
|
+
# Methods
|
|
187
|
+
devices = await client.list_devices() # List[Device | Vehicle]
|
|
188
|
+
device = await client.get_device(device_id) # Device | Vehicle
|
|
189
|
+
locations = await client.get_locations(device_id, limit=10)
|
|
190
|
+
success = await client.send_command(device_id, "locate")
|
|
191
|
+
auth = client.export_auth() # AuthArtifacts
|
|
192
|
+
await client.close()
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Device
|
|
196
|
+
|
|
197
|
+
Wrapper for tracked devices.
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
# Properties
|
|
201
|
+
device.id # str
|
|
202
|
+
device.name # Optional[str]
|
|
203
|
+
device.info # DeviceInfo
|
|
204
|
+
device.last_seen # Optional[datetime]
|
|
205
|
+
device.cached_location # Optional[Location]
|
|
206
|
+
|
|
207
|
+
# Methods
|
|
208
|
+
await device.refresh(force=True)
|
|
209
|
+
location = await device.get_location(force=False)
|
|
210
|
+
async for loc in device.get_history(limit=100):
|
|
211
|
+
...
|
|
212
|
+
await device.lock(message="...", passcode="...")
|
|
213
|
+
await device.unlock()
|
|
214
|
+
await device.ring(duration=30)
|
|
215
|
+
await device.request_location_update()
|
|
216
|
+
await device.send_command("custom_command")
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Vehicle (extends Device)
|
|
220
|
+
|
|
221
|
+
Additional properties and methods for vehicles.
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
# Properties
|
|
225
|
+
vehicle.vin # Optional[str]
|
|
226
|
+
vehicle.make # Optional[str]
|
|
227
|
+
vehicle.model # Optional[str]
|
|
228
|
+
vehicle.year # Optional[int]
|
|
229
|
+
vehicle.license_plate # Optional[str]
|
|
230
|
+
vehicle.odometer # Optional[float]
|
|
231
|
+
|
|
232
|
+
# Methods
|
|
233
|
+
await vehicle.start_engine()
|
|
234
|
+
await vehicle.stop_engine()
|
|
235
|
+
await vehicle.honk_horn()
|
|
236
|
+
await vehicle.flash_lights()
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Data Models
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
from lojack_api import Location, DeviceInfo, VehicleInfo
|
|
243
|
+
|
|
244
|
+
# Location
|
|
245
|
+
location.latitude # Optional[float]
|
|
246
|
+
location.longitude # Optional[float]
|
|
247
|
+
location.timestamp # Optional[datetime]
|
|
248
|
+
location.accuracy # Optional[float]
|
|
249
|
+
location.speed # Optional[float]
|
|
250
|
+
location.heading # Optional[float]
|
|
251
|
+
location.address # Optional[str]
|
|
252
|
+
location.raw # Dict[str, Any] # Original API response
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Exceptions
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
from lojack_api import (
|
|
259
|
+
LoJackError, # Base exception
|
|
260
|
+
AuthenticationError, # 401 errors, invalid credentials
|
|
261
|
+
AuthorizationError, # 403 errors, permission denied
|
|
262
|
+
ApiError, # Other API errors (has status_code)
|
|
263
|
+
ConnectionError, # Network connectivity issues
|
|
264
|
+
TimeoutError, # Request timeouts
|
|
265
|
+
DeviceNotFoundError, # Device not found (has device_id)
|
|
266
|
+
CommandError, # Command failed (has command, device_id)
|
|
267
|
+
InvalidParameterError, # Invalid parameter (has parameter, value)
|
|
268
|
+
)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Spireon API Details
|
|
272
|
+
|
|
273
|
+
The library uses the Spireon LoJack API:
|
|
274
|
+
|
|
275
|
+
- **Identity Service**: `https://identity.spireon.com` - For authentication
|
|
276
|
+
- **Services API**: `https://services.spireon.com/v0/rest` - For device/asset management
|
|
277
|
+
|
|
278
|
+
Authentication uses HTTP Basic Auth with the following headers:
|
|
279
|
+
- `X-Nspire-Apptoken` - Application token
|
|
280
|
+
- `X-Nspire-Correlationid` - Unique request ID
|
|
281
|
+
- `X-Nspire-Usertoken` - User token (after authentication)
|
|
282
|
+
|
|
283
|
+
## Development
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
# Install dev dependencies
|
|
287
|
+
pip install .[dev]
|
|
288
|
+
|
|
289
|
+
# Run tests
|
|
290
|
+
pytest
|
|
291
|
+
|
|
292
|
+
# Run tests with coverage
|
|
293
|
+
pytest --cov=lojack_api
|
|
294
|
+
|
|
295
|
+
# Type checking
|
|
296
|
+
mypy lojack_api
|
|
297
|
+
|
|
298
|
+
# Linting
|
|
299
|
+
# Preferred: ruff for quick fixes
|
|
300
|
+
ruff check .
|
|
301
|
+
|
|
302
|
+
# Use flake8 for strict style checks (reports shown in CI)
|
|
303
|
+
# Match ruff's line length setting
|
|
304
|
+
flake8 lojack_api/ tests/ --count --show-source --statistics --max-line-length=100
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
310
|
+
|
|
311
|
+
## Contributing
|
|
312
|
+
|
|
313
|
+
Contributions are welcome! This library is designed to be vendored into Home Assistant integrations to avoid dependency conflicts.
|
|
314
|
+
|
|
315
|
+
## Credits
|
|
316
|
+
|
|
317
|
+
This library was inspired by the original [lojack-clients](https://github.com/scorgn/lojack-clients) package and uses the Spireon LoJack API endpoints.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
lojack_api/__init__.py,sha256=5VPVfFDY-hO3GcdP5k89PJSyXXxf2DfHREnb4SRjTD4,1784
|
|
2
|
+
lojack_api/api.py,sha256=BhDusVVtm-ppB3bE1e_l95g6a1mO_q1TcSHmQitLuRQ,15356
|
|
3
|
+
lojack_api/auth.py,sha256=dbUl2m3G72BPZO5qJn9dafv9VPZNzg7Splu2Agrr9yk,9327
|
|
4
|
+
lojack_api/device.py,sha256=zGo6fJvQBBSgdhVbDmFlYANbh7Q2l7i0ZNdO3W5_XBw,9913
|
|
5
|
+
lojack_api/exceptions.py,sha256=fVI69JADd0v1fjQvdAjG9XouKU__zslwzDb_O3zxFwA,2430
|
|
6
|
+
lojack_api/models.py,sha256=TLSrtoym8veUdBsLxtH4yLjLRZX7pDp6gKwN4a-xetM,8777
|
|
7
|
+
lojack_api/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
lojack_api/transport.py,sha256=Mhyv4LiehClevP0MvqrYW2S-xGRhqfPdy3Jnh6jAiBA,6080
|
|
9
|
+
lojack_api-0.5.0.dist-info/licenses/LICENSE,sha256=2raVXId8lZ1YAILtPjUzEy0IhxFXvqMoXqu35vLWszQ,669
|
|
10
|
+
lojack_api-0.5.0.dist-info/METADATA,sha256=hVppwSKbisXIOs8serhN_7eqmQsAUsvQUwc17921mlY,9200
|
|
11
|
+
lojack_api-0.5.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
12
|
+
lojack_api-0.5.0.dist-info/top_level.txt,sha256=J80LTW9G3zGoloSJ5MF21nZ48JD_VCjGFdhTja3Oguw,11
|
|
13
|
+
lojack_api-0.5.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
13
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
14
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
lojack_api
|