steamloop¶
Async Python library for local control of thermostat devices over mTLS (port 7878).
Installation¶
pip install steamloop
CLI¶
Pairing¶
Put the thermostat in pairing mode (Menu > Settings > Network > Advanced Setup > Remote Connection > Pair), then:
steamloop 192.168.1.100 --pair
This saves a pairing file in the current directory with the secret key.
Monitoring¶
steamloop 192.168.1.100
If already paired, you can pass the secret key directly to skip the pairing file:
steamloop 192.168.1.100 --key YOUR_SECRET_KEY
Interactive commands: status, heat <temp>, cool <temp>, mode <off|auto|cool|heat>, fan <auto|on|circulate>, eheat <on|off>, help.
Library Usage¶
import asyncio
from steamloop import ThermostatConnection, ZoneMode, FanMode
async def main():
conn = ThermostatConnection(
"192.168.1.100",
secret_key="your-secret-key-from-pairing",
)
async with conn:
# State is populated automatically from thermostat events
for zone_id, zone in conn.state.zones.items():
print(f"{zone.name}: {zone.indoor_temperature}°F")
# Send commands (sync — no await needed)
conn.set_temperature_setpoint("1", heat_setpoint="72")
conn.set_zone_mode("1", ZoneMode.COOL)
conn.set_fan_mode(FanMode.AUTO)
asyncio.run(main())
Pairing Programmatically¶
pair() returns the secret key directly — store it however you like:
from steamloop import ThermostatConnection
async def pair(ip: str) -> str:
conn = ThermostatConnection(ip, secret_key="")
try:
await conn.connect()
ssk = await conn.pair()
return ssk["secret_key"] # store in a database, config entry, etc.
finally:
await conn.disconnect()
Or use the built-in file helpers to save/load pairing data to disk:
from steamloop import ThermostatConnection, save_pairing, load_pairing
# Save after pairing
await save_pairing(ip, {
"secret_key": secret_key,
"device_type": "automation",
"device_id": "module",
})
# Load later
pairing = await load_pairing(ip)
conn = ThermostatConnection(ip, secret_key=pairing["secret_key"])
Event Callbacks¶
def on_event(msg):
print("Received:", msg)
remove = conn.add_event_callback(on_event)
# later: remove() to unregister
Home Assistant Integration¶
Key design points for using steamloop in a Home Assistant integration:
Commands are sync —
set_zone_mode(),set_fan_mode(),set_temperature_setpoint()usetransport.write()internally, so they won’t block the event loop. Noawaitneeded.State is always fresh — the
asyncio.Protocolreceives events viadata_received()and updatesconn.stateautomatically. Just read properties directly.Auto-reconnect — after calling
start_background_tasks(), the connection automatically reconnects with exponential backoff (5s, 10s, 20s, … up to 5 min).Event callbacks — use
add_event_callback()to triggerasync_write_ha_state()when the thermostat pushes updates.Multi-zone — create one
ClimateEntityperconn.state.zonesentry. Zones are populated automatically after login.
API Reference¶
ThermostatConnection(ip, port=7878, *, secret_key, cert_set=None, device_type="automation", device_id="module")¶
Method |
Async |
Description |
|---|---|---|
|
yes |
Establish mTLS connection |
|
yes |
Authenticate with secret key |
|
yes |
Pair and receive secret key |
|
no |
Start heartbeat + auto-reconnect |
|
yes |
Close connection and stop tasks |
|
no |
Set zone temperature |
|
no |
Set zone HVAC mode |
|
no |
Set fan mode |
|
no |
Toggle emergency heat |
|
no |
Register event listener (returns unregister callable) |
Supports async with for automatic connect/login/disconnect:
async with ThermostatConnection(ip, secret_key=key) as conn:
... # connected, logged in, background tasks running
# automatically disconnected
Enums¶
ZoneMode—OFF,AUTO,COOL,HEATFanMode—AUTO,ALWAYS_ON,CIRCULATEHoldType—UNDEFINED,MANUAL,SCHEDULE,HOLD
State¶
conn.state.zones—dict[str, Zone]with temperature, setpoints, mode per zoneconn.state.fan_mode— currentFanModeconn.state.supported_modes—list[ZoneMode]conn.state.emergency_heat/relative_humidity/cooling_active/heating_active
Contributors¶
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!
Credits¶
This package was created with Copier and the browniebroke/pypackage-template project template.
Installation & Usage
Project Info
API Reference
- steamloop package
AuthenticationErrorCommandErrorFanModeHoldTypePairingErrorSteamloopConnectionErrorSteamloopErrorThermostatConnectionThermostatStateZoneZoneModeload_pairing()save_pairing()- Submodules
- steamloop.certs module
- steamloop.cli module
- steamloop.connection module
- steamloop.const module
- steamloop.exceptions module
- steamloop.models module