Skip to main content

lighthouse-ble

Async Bluetooth LE control of SteamVR Lighthouse base stations — Valve Index (V2, LHB-…) and HTC Vive (V1, HTC BS …). Built to back a Home Assistant integration, usable on its own.

V2 (Valve Index) V1 (HTC Vive)
Power on / standby / sleep on / sleep
State passive from advertisements (provisional), or GATT read not readable (optimistic)
Identify (blink LED) yes —
Channel 1–16 read / write —

Provisional: decoding V2 state from advertisements has not been confirmed on hardware yet. The raw payload is always exposed as LighthouseAdvertisement.raw so mismatches are visible.

Install

uv add lighthouse-ble            # as a library dependency
uvx lighthouse-ble scan          # run the CLI without installing

Command line

lighthouse-ble scan                      # list stations with passive state
lighthouse-ble scan --raw                # every advertisement with raw bytes and intervals
lighthouse-ble info LHB-1A2B3C4D         # device information + GATT state
lighthouse-ble on LHB-1A2B3C4D
lighthouse-ble standby LHB-1A2B3C4D
lighthouse-ble off LHB-1A2B3C4D
lighthouse-ble identify LHB-1A2B3C4D
lighthouse-ble channel LHB-1A2B3C4D 5
lighthouse-ble off "HTC BS 12AB34" --v1-id 1A2B   # V1: first 4 hex digits from the back label

Stations can be addressed by name or BLE address. --scan-time changes how long to look (default 10 s).

Library

import asyncio

from lighthouse_ble import PowerState, create_base_station, discover


async def main() -> None:
    for found in await discover(5):
        station = create_base_station(found.device, found.advertisement)
        print(station.name, station.state)
        await station.set_power(PowerState.ON)


asyncio.run(main())

In Home Assistant, feed advertisements from the bluetooth integration instead of scanning:

adv = parse_advertisement(service_info.name, service_info.manufacturer_data)
station.set_ble_device(service_info.device)
station.update_from_advertisement(adv)
unsubscribe = station.register_callback(lambda state: ...)

Every command opens a short connection and disconnects again, so no ESPHome proxy slot stays taken. Errors are always LighthouseError subclasses.

Development

uv sync
uv run pytest --cov=lighthouse_ble
uv run mypy
uv run ruff check . && uv run ruff format --check .

License

Apache-2.0

Release files for lighthouse-ble 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lighthouse-ble 0.1.0
File Size Uploaded
lighthouse_ble-0.1.0.tar.gz 67.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lighthouse-ble 0.1.0
File Interpreter ABI Platform
lighthouse_ble-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 85.3 kB

Release files / lighthouse_ble-0.1.0.tar.gz

Download URL lighthouse_ble-0.1.0.tar.gz
Size 67.0 kB
Tags Source
SHA-256 checksum
How to use checksums
9dbc1dcbbb22106c1266dd22300bec07ed926518e81a26d346ea3a3cfc208198
BLAKE2b-256 checksum
How to use checksums
c6b1adbc5696160ae622f2ebd0026aa3454e0d67164c2e0c7d198a5527ff4475
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.

Transparency log

Release files / lighthouse_ble-0.1.0-py3-none-any.whl

Download URL lighthouse_ble-0.1.0-py3-none-any.whl
Size 18.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d74e1628bbdadb2b5d31077dd00c409b0242aefc85337873896df0f5667db901
BLAKE2b-256 checksum
How to use checksums
a665ac60f4313fd28457306e43d272662a07980f6ceb26a9f19bdd00fbad9126
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page