An async Python client library for the LoJack API, designed for Home Assistant integrations.
Project description
lojack_api
An async Python client library for the Spireon LoJack API, designed for Home Assistant integrations.
Features
- Async-first design - Built with
asyncioandaiohttpfor non-blocking I/O - No httpx dependency - Uses
aiohttpto avoid version conflicts with Home Assistant - Spireon LoJack API - Full support for the Spireon identity and services APIs
- Session management - Automatic token refresh and session resumption support
- Type hints - Full typing support with
py.typedmarker - Clean device abstractions - Device and Vehicle wrappers with convenient methods
Installation
# From the repository
pip install .
# With development dependencies
pip install .[dev]
Quick Start
Basic Usage
import asyncio
from lojack_api import LoJackClient
async def main():
# Create and authenticate (uses default Spireon URLs)
async with await LoJackClient.create(
"your_username",
"your_password"
) as client:
# List all devices/vehicles
devices = await client.list_devices()
for device in devices:
print(f"Device: {device.name} ({device.id})")
# Get current location
location = await device.get_location()
if location:
print(f" Location: {location.latitude}, {location.longitude}")
asyncio.run(main())
Session Resumption (for Home Assistant)
For Home Assistant integrations, you can persist authentication across restarts:
from lojack_api import LoJackClient, AuthArtifacts
# First time - login and save auth
async def initial_login(username, password):
client = await LoJackClient.create(username, password)
auth_data = client.export_auth().to_dict()
# Save auth_data to Home Assistant storage
await client.close()
return auth_data
# Later - resume without re-entering password
async def resume_session(auth_data, username=None, password=None):
auth = AuthArtifacts.from_dict(auth_data)
# Pass credentials for auto-refresh if token expires
client = await LoJackClient.from_auth(auth, username=username, password=password)
return client
Using External aiohttp Session
For Home Assistant integrations, pass the shared session:
from aiohttp import ClientSession
from lojack_api import LoJackClient
async def setup(hass_session: ClientSession, username, password):
client = await LoJackClient.create(
username,
password,
session=hass_session # Won't be closed when client closes
)
return client
Working with Vehicles
Vehicles have additional properties and commands:
from lojack_api import Vehicle
async def vehicle_example(client):
devices = await client.list_devices()
for device in devices:
if isinstance(device, Vehicle):
print(f"Vehicle: {device.name}")
print(f" VIN: {device.vin}")
print(f" Make: {device.make} {device.model} ({device.year})")
# Vehicle-specific commands
await device.start_engine()
await device.honk_horn()
await device.flash_lights()
Device Commands
# All devices support these commands
await device.lock(message="Please return this device")
await device.unlock()
await device.ring(duration=30)
await device.request_location_update()
# Get location history
async for location in device.get_history(limit=100):
print(f"{location.timestamp}: {location.latitude}, {location.longitude}")
API Reference
LoJackClient
The main entry point for the API.
# Factory methods (using default Spireon URLs)
client = await LoJackClient.create(username, password)
client = await LoJackClient.from_auth(auth_artifacts)
# With custom URLs
client = await LoJackClient.create(
username,
password,
identity_url="https://identity.spireon.com",
services_url="https://services.spireon.com/v0/rest"
)
# Properties
client.is_authenticated # bool
client.user_id # Optional[str]
# Methods
devices = await client.list_devices() # List[Device | Vehicle]
device = await client.get_device(device_id) # Device | Vehicle
locations = await client.get_locations(device_id, limit=10)
success = await client.send_command(device_id, "locate")
auth = client.export_auth() # AuthArtifacts
await client.close()
Device
Wrapper for tracked devices.
# Properties
device.id # str
device.name # Optional[str]
device.info # DeviceInfo
device.last_seen # Optional[datetime]
device.cached_location # Optional[Location]
# Methods
await device.refresh(force=True)
location = await device.get_location(force=False)
async for loc in device.get_history(limit=100):
...
await device.lock(message="...", passcode="...")
await device.unlock()
await device.ring(duration=30)
await device.request_location_update()
await device.send_command("custom_command")
Vehicle (extends Device)
Additional properties and methods for vehicles.
# Properties
vehicle.vin # Optional[str]
vehicle.make # Optional[str]
vehicle.model # Optional[str]
vehicle.year # Optional[int]
vehicle.license_plate # Optional[str]
vehicle.odometer # Optional[float]
# Methods
await vehicle.start_engine()
await vehicle.stop_engine()
await vehicle.honk_horn()
await vehicle.flash_lights()
Data Models
from lojack_api import Location, DeviceInfo, VehicleInfo
# Location
location.latitude # Optional[float]
location.longitude # Optional[float]
location.timestamp # Optional[datetime]
location.accuracy # Optional[float]
location.speed # Optional[float]
location.heading # Optional[float]
location.address # Optional[str]
location.raw # Dict[str, Any] # Original API response
Exceptions
from lojack_api import (
LoJackError, # Base exception
AuthenticationError, # 401 errors, invalid credentials
AuthorizationError, # 403 errors, permission denied
ApiError, # Other API errors (has status_code)
ConnectionError, # Network connectivity issues
TimeoutError, # Request timeouts
DeviceNotFoundError, # Device not found (has device_id)
CommandError, # Command failed (has command, device_id)
InvalidParameterError, # Invalid parameter (has parameter, value)
)
Spireon API Details
The library uses the Spireon LoJack API:
- Identity Service:
https://identity.spireon.com- For authentication - Services API:
https://services.spireon.com/v0/rest- For device/asset management
Authentication uses HTTP Basic Auth with the following headers:
X-Nspire-Apptoken- Application tokenX-Nspire-Correlationid- Unique request IDX-Nspire-Usertoken- User token (after authentication)
Development
# Install dev dependencies
pip install .[dev]
# Run tests
pytest
# Run tests with coverage
pytest --cov=lojack_api
# Type checking
mypy lojack_api
# Linting
# Preferred: ruff for quick fixes
ruff check .
# Use flake8 for strict style checks (reports shown in CI)
# Match ruff's line length setting
flake8 lojack_api/ tests/ --count --show-source --statistics --max-line-length=100
License
MIT License - see LICENSE for details.
Contributing
Contributions are welcome! This library is designed to be vendored into Home Assistant integrations to avoid dependency conflicts.
Credits
This library was inspired by the original lojack-clients package and uses the Spireon LoJack API endpoints.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lojack_api-0.6.0.tar.gz.
File metadata
- Download URL: lojack_api-0.6.0.tar.gz
- Upload date:
- Size: 27.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
203a66d10aa00fa5261f7a2cf33aa207e508a8e34de598cf8111f9bf485004cf
|
|
| MD5 |
2eb7b9005212daf00e908600e7f93590
|
|
| BLAKE2b-256 |
761cbb0c0f3eeeeaa6916575693421317bbbece83366f2f74502ed0b3e945db8
|
Provenance
The following attestation bundles were made for lojack_api-0.6.0.tar.gz:
Publisher:
publish.yml on devinslick/lojack_api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lojack_api-0.6.0.tar.gz -
Subject digest:
203a66d10aa00fa5261f7a2cf33aa207e508a8e34de598cf8111f9bf485004cf - Sigstore transparency entry: 873120510
- Sigstore integration time:
-
Permalink:
devinslick/lojack_api@7e9e167923d8dc96efb8d51bc085ece6652751ac -
Branch / Tag:
refs/tags/0.6.0 - Owner: https://github.com/devinslick
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e9e167923d8dc96efb8d51bc085ece6652751ac -
Trigger Event:
release
-
Statement type:
File details
Details for the file lojack_api-0.6.0-py3-none-any.whl.
File metadata
- Download URL: lojack_api-0.6.0-py3-none-any.whl
- Upload date:
- Size: 21.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a309adb9802e667307757327ac29406c89f28ad23e37ff3af0fe98e9e445e59
|
|
| MD5 |
f6cd0b982c41e01173ed4017ee5f5681
|
|
| BLAKE2b-256 |
28b9cb83e77d536631fc5029c5526df69ca4d746a00ec7ea6b17b50a95f58b2d
|
Provenance
The following attestation bundles were made for lojack_api-0.6.0-py3-none-any.whl:
Publisher:
publish.yml on devinslick/lojack_api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lojack_api-0.6.0-py3-none-any.whl -
Subject digest:
3a309adb9802e667307757327ac29406c89f28ad23e37ff3af0fe98e9e445e59 - Sigstore transparency entry: 873120594
- Sigstore integration time:
-
Permalink:
devinslick/lojack_api@7e9e167923d8dc96efb8d51bc085ece6652751ac -
Branch / Tag:
refs/tags/0.6.0 - Owner: https://github.com/devinslick
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e9e167923d8dc96efb8d51bc085ece6652751ac -
Trigger Event:
release
-
Statement type: