Skip to main content

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 asyncio and aiohttp for non-blocking I/O
  • No httpx dependency - Uses aiohttp to 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.typed marker
  • 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 token
  • X-Nspire-Correlationid - Unique request ID
  • X-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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lojack_api-0.5.0.tar.gz (26.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lojack_api-0.5.0-py3-none-any.whl (20.1 kB view details)

Uploaded Python 3

File details

Details for the file lojack_api-0.5.0.tar.gz.

File metadata

  • Download URL: lojack_api-0.5.0.tar.gz
  • Upload date:
  • Size: 26.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for lojack_api-0.5.0.tar.gz
Algorithm Hash digest
SHA256 567742e8cdb18c9a3358728f4c547af01e7c2df980f831ef2f8fef474885b5f6
MD5 c4aac26a369c5e303215e237f85a999a
BLAKE2b-256 6642d7bfb8edde5773b8493da92483d968d2298b0f69bac13ba3a6ba0fe70481

See more details on using hashes here.

Provenance

The following attestation bundles were made for lojack_api-0.5.0.tar.gz:

Publisher: publish.yml on devinslick/lojack_api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lojack_api-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: lojack_api-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 20.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for lojack_api-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b4d5aeb1e654f62e437ef342d00c8829251a1ab31c31eb5318142ea36be26b46
MD5 7aa08399309fdb97d45cb101af7aadd0
BLAKE2b-256 c942890c520aef90342314ebe5389aa2bf1bf4bc087262535983aa9cbb0954f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for lojack_api-0.5.0-py3-none-any.whl:

Publisher: publish.yml on devinslick/lojack_api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page