pybticino
Async Python library for the BTicino/Netatmo API. Controls BTicino Classe 100X/300X video intercom systems via the Netatmo cloud.
Used by the bticino_intercom Home Assistant integration.
Installation
pip install pybticino
Requires Python 3.13 or later.
Features
- Authentication: OAuth2 password grant with automatic token refresh and persistence support
- Home topology: fetch homes, modules, and their configuration
- Device control: lock/unlock doors, turn lights on/off
- Events: fetch call history with snapshots and vignettes
- WebSocket: real-time push notifications (call events, connection status, state changes)
- Re-subscribe: refresh OAuth token on existing connection without reconnecting
- WebRTC signaling: offer/answer/ICE exchange for live video calls (experimental)
Quick start
import asyncio
from pybticino import AuthHandler, AsyncAccount
async def on_token_change(tokens):
"""Called when tokens are refreshed — persist them to avoid re-auth."""
print(f"New token expires at {tokens['expires_at']}")
async def main():
auth = AuthHandler(
"your_email@example.com",
"your_password",
token_callback=on_token_change, # optional: persist tokens
)
account = AsyncAccount(auth)
await account.async_update_topology()
for home_id, home in account.homes.items():
print(f"Home: {home.name} ({len(home.modules)} modules)")
status = await account.async_get_home_status(home_id)
events = await account.async_get_events(home_id, size=5)
await auth.close_session()
asyncio.run(main())
To restore tokens from a previous session (skip initial auth):
auth = AuthHandler("email", "password", token_callback=on_token_change)
auth.set_tokens(
access_token=saved["access_token"],
refresh_token=saved["refresh_token"],
expires_at=saved["expires_at"],
)
WebSocket (real-time events)
import asyncio
from pybticino import AuthHandler, WebsocketClient
async def on_message(message):
print(f"Event: {message.get('push_type')} - {message}")
async def main():
auth = AuthHandler("your_email@example.com", "your_password")
ws = WebsocketClient(auth, on_message)
# Option 1: run forever with auto-reconnect (recommended)
await ws.run_forever(reconnect_delay=30)
# Option 2: manual connect + listen
await ws.connect()
task = ws.get_listener_task()
if task:
await task
await ws.disconnect()
await auth.close_session()
asyncio.run(main())
Re-subscribe (keep connection alive)
# Refresh token on existing connection without disconnecting.
# Call this periodically (e.g., every hour) to prevent token expiry.
await ws.resubscribe()
API endpoints
| Method | Endpoint | Description |
|---|---|---|
async_update_topology() |
/api/homesdata |
Fetch homes and modules |
async_get_home_status(home_id) |
/syncapi/v1/homestatus |
Get module status |
async_set_module_state(home_id, module_id, state) |
/syncapi/v1/setstate |
Control devices |
async_get_events(home_id, size) |
/api/getevents |
Get event history |
async_get_turn_servers() |
/turn |
Fetch TURN/STUN ICE server credentials for WebRTC |
WebSocket event types
Events are delivered with push_type in format {DEVICE_TYPE}-{EVENT_TYPE}:
| push_type | Description |
|---|---|
BNC1-rtc |
Incoming WebRTC call (with SDP offer) |
BNC1-incoming_call |
Doorbell ring (with snapshot URL) |
BNC1-missed_call |
Unanswered call |
BNC1-accepted_call |
Call answered |
BNC1-connection |
Bridge connected |
BNC1-disconnection |
Bridge disconnected |
Documentation
Full documentation at k-the-hidden-hero.github.io/pybticino
Key guides from reverse engineering:
- WebRTC Signaling Protocol — complete offer/answer/ICE flow, message formats, session state, two call modes
- WebRTC Audio Mechanism — how to activate the device microphone (requires real RTP audio packets)
- WebSocket Events — all push notification types and their JSON structures
- Reverse Engineering Notes — findings from decompiling the official BTicino/Netatmo app
Examples
Working example scripts in examples/:
| Script | Description |
|---|---|
webrtc_offer_mode.py |
On-demand video: send offer → receive answer → ICE → connected |
webrtc_answer_mode.py |
Answer incoming call: wait for doorbell → answer via signaling |
webrtc_audio_test.html |
Browser-based audio test with silence oscillator |
websocket_test.py |
Real-time push notification listener |
Related projects
- bticino_intercom — Home Assistant custom integration
- bticino_ha_extras — Blueprints, Lovelace cards, and companion resources
Contributing
pip install -e ".[test,dev]"
pytest tests/ -v
ruff check src/ tests/
License
MIT
Metadata
Release files for pybticino 1.9.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pybticino-1.9.0.tar.gz | 83.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pybticino-1.9.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 113.4 kB
Release files / pybticino-1.9.0.tar.gz
| Download URL | pybticino-1.9.0.tar.gz |
|---|---|
| Size | 83.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
763da124daacecb98dc145fe02682625b9a8ca8db0dc1fcdd8e83b3ce7781f21
|
|
BLAKE2b-256 checksum How to use checksums |
24cb8864da3dab8242519e9763ed536700c4f6eb0a4bd59c48761f25c8531616
|
| 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 15, 2026.
Transparency logRelease files / pybticino-1.9.0-py3-none-any.whl
| Download URL | pybticino-1.9.0-py3-none-any.whl |
|---|---|
| Size | 29.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9ed41218a2b6f2a81847d4282b2858d10c83ecc4d5e15c2363502051cfb372d6
|
|
BLAKE2b-256 checksum How to use checksums |
a6cd15d7b3571bfe932c0e92d050d1b1c92c9285fef1453c7252fee2fdb40356
|
| 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 15, 2026.
Transparency log