pysensorlinx
An async Python library for the SensorLinx API. It provides full control of HBX HVAC controllers (such as the ECO-0600) — reading sensor data, getting and setting device parameters, and managing heat-pump staging, tank temperatures, backup settings, and more.
Features
- Async — built on
aiohttpfor non-blocking I/O - Login & session management — authenticate, auto-refresh tokens, and close sessions
- Buildings & devices — list buildings and enumerate devices per building
- Get & set parameters — read and write every ECO-0600 configuration parameter
- Temperature objects —
TemperatureandTemperatureDeltaclasses with automatic °F ↔ °C conversion - Read sensor data — retrieve live temperature sensor readings and stage runtimes
- Exception hierarchy — typed exceptions for login failures and invalid parameters
Installation
pip install pysensorlinx
Development install
git clone https://github.com/sslivins/pysensorlinx.git
cd pysensorlinx
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
pip install -e .[tests]
Quick start
import asyncio
from pysensorlinx import Sensorlinx, SensorlinxDevice
async def main():
api = Sensorlinx()
try:
await api.login("your_username", "your_password")
# List buildings
buildings = await api.get_buildings()
building_id = buildings[0]["_id"]
# List devices in the first building
devices = await api.get_devices(building_id)
device_id = devices[0]["syncCode"]
# Create a device helper
device = SensorlinxDevice(api, building_id, device_id)
# Read parameters
mode = await device.get_hvac_mode_priority() # "heat", "cool", or "auto"
temps = await device.get_temperatures() # dict of sensor readings
max_temp = await device.get_hot_tank_max_temp() # Temperature(150.00, 'F')
# Write parameters
await device.set_hvac_mode_priority("auto")
await device.set_hot_tank_max_temp(160) # accepts int (°F) or Temperature
finally:
await api.close()
asyncio.run(main())
Temperature & TemperatureDelta
The library returns temperature values as Temperature or TemperatureDelta objects that handle unit conversion automatically. The API stores all values in °F.
from pysensorlinx import Temperature, TemperatureDelta
# Absolute temperatures (°F = °C × 9/5 + 32)
t = Temperature(212, "F")
print(t.to_celsius()) # 100.0
print(t.as_celsius()) # Temperature(100.00, 'C')
print(t) # 212.00°F
# Temperature differentials (ΔF = ΔC × 9/5, no +32 offset)
d = TemperatureDelta(9, "F")
print(d.to_celsius()) # 5.0
print(d.as_celsius()) # TemperatureDelta(5.00, 'C')
print(d) # 9.00Δ°F
Temperature methods
| Method | Returns | Description |
|---|---|---|
to_celsius() |
float |
Value converted to °C |
to_fahrenheit() |
float |
Value converted to °F |
as_celsius() |
Temperature |
New Temperature object in °C |
as_fahrenheit() |
Temperature |
New Temperature object in °F |
TemperatureDelta has the same methods (returns TemperatureDelta for as_*).
Some getters return 'off' when the feature is disabled:
shutdown = await device.get_warm_weather_shutdown() # Temperature(75.00, 'F') or 'off'
API reference
Sensorlinx
The low-level API client. Manages authentication and HTTP requests.
| Method | Description |
|---|---|
login(username, password) |
Authenticate with SensorLinx |
close() |
Close the HTTP session |
get_profile() |
Fetch the authenticated user's profile |
get_buildings(building_id=None) |
List all buildings, or fetch one by ID |
get_devices(building_id, device_id=None) |
List devices in a building, or fetch one |
set_device_parameter(building_id, device_id, **kwargs) |
Set one or more device parameters |
SensorlinxDevice
A high-level wrapper around a single device. All methods are async.
Getters
| Method | Returns | Notes |
|---|---|---|
get_hvac_mode_priority() |
str |
"heat", "cool", or "auto" |
get_permanent_heat_demand() |
bool |
|
get_permanent_cool_demand() |
bool |
|
get_weather_shutdown_lag_time() |
int |
hours |
get_heat_cool_switch_delay() |
int |
seconds |
get_wide_priority_differential() |
bool |
|
get_number_of_stages() |
int |
1–4 |
get_two_stage_heat_pump() |
bool |
|
get_stage_on_lag_time() |
int |
minutes |
get_stage_off_lag_time() |
int |
seconds |
get_rotate_cycles() |
int | 'off' |
|
get_rotate_time() |
int | 'off' |
hours |
get_off_staging() |
bool |
|
get_warm_weather_shutdown() |
Temperature | 'off' |
|
get_hot_tank_outdoor_reset() |
Temperature | 'off' |
|
get_hot_tank_differential() |
TemperatureDelta |
|
get_hot_tank_min_temp() |
Temperature |
|
get_hot_tank_max_temp() |
Temperature |
|
get_cold_weather_shutdown() |
Temperature | 'off' |
|
get_cold_tank_outdoor_reset() |
Temperature | 'off' |
|
get_cold_tank_differential() |
TemperatureDelta |
|
get_cold_tank_min_temp() |
Temperature |
|
get_cold_tank_max_temp() |
Temperature |
|
get_dhw_enabled() |
bool |
|
get_dhw_target_temp() |
Temperature |
|
get_dhw_differential() |
TemperatureDelta |
|
get_dhw_state() |
dict |
DHW demand state with activated, enabled, title |
get_demands() |
list[dict] |
All demand channels (hd, cd, dhw) with activated, enabled, name, title |
get_backup_lag_time() |
int | 'off' |
minutes |
get_backup_temp() |
Temperature | 'off' |
|
get_backup_differential() |
TemperatureDelta | 'off' |
|
get_backup_only_outdoor_temp() |
Temperature | 'off' |
|
get_backup_only_tank_temp() |
Temperature | 'off' |
|
get_firmware_version() |
str |
|
get_sync_code() |
str |
|
get_device_pin() |
str |
|
get_device_type() |
str |
e.g. "ECO" |
get_temperatures(temp_name=None) |
dict |
Dict of sensor dicts with actual and target as Temperature objects. Pass temp_name to get one sensor. |
get_runtimes() |
dict |
Stage runtimes as list[timedelta], backup runtime as timedelta |
get_heatpump_stages_state() |
list[dict] |
Stage info with activated, enabled, title, device, index, runTime |
get_backup_state() |
dict |
Backup state with activated, enabled, title, runTime |
get_current_weather() |
dict |
Current conditions: temp, feelsLike, min, max as Temperature; pressure, humidity, wind, windDir, clouds, snow, rain, description, icon, weatherId |
get_forecast() |
list[dict] |
Forecast periods: time as datetime, temp/min/max as Temperature, pop, snow, description, icon, weatherId |
get_system_state() |
dict |
Bundled runtime state: demands, temperatures, stages, backup, pumps, reversingValve, weatherShutdown |
Weather conditions
The description and weatherId fields in weather and forecast data come from OpenWeatherMap. Use weatherId for programmatic checks — it is more reliable than parsing the description string.
| Group | weatherId range |
Example descriptions |
|---|---|---|
| Thunderstorm | 200–232 | "thunderstorm with light rain", "heavy thunderstorm" |
| Drizzle | 300–321 | "light intensity drizzle", "drizzle rain" |
| Rain | 500–531 | "light rain", "moderate rain", "heavy intensity rain" |
| Snow | 600–622 | "light snow", "heavy snow", "sleet" |
| Atmosphere | 701–781 | "mist", "smoke", "haze", "fog", "tornado" |
| Clear | 800 | "clear sky" |
| Clouds | 801–804 | "few clouds", "scattered clouds", "broken clouds", "overcast clouds" |
Setters
All setters accept the value as the first argument. Temperature setters accept int (°F), Temperature, or 'off' where applicable.
| Method | Accepts |
|---|---|
set_hvac_mode_priority(value) |
"heat", "cool", "auto" |
set_permanent_hd(value) |
bool |
set_permanent_cd(value) |
bool |
set_wide_priority_differential(value) |
bool |
set_weather_shutdown_lag_time(value) |
int (0–240 hours) |
set_number_of_stages(value) |
int (1–4) |
set_two_stage_heat_pump(value) |
bool |
set_stage_on_lag_time(value) |
int (1–240 min) |
set_stage_off_lag_time(value) |
int (1–240 sec) |
set_rotate_cycles(value) |
int (1–240) or "off" |
set_rotate_time(value) |
int (1–240 hours) or "off" |
set_off_staging(value) |
bool |
set_heat_cool_switch_delay(value) |
int (30–600 sec) |
set_warm_weather_shutdown(value) |
int (34–180 °F) or "off" |
set_hot_tank_outdoor_reset(value) |
int (-40–127 °F) or "off" |
set_hot_tank_differential(value) |
int (2–100 °F) |
set_hot_tank_min_temp(value) |
int (2–180 °F) |
set_hot_tank_max_temp(value) |
int (2–180 °F) |
set_hot_tank_target_temp(value) |
Alias for set_hot_tank_min_temp |
set_cold_weather_shutdown(value) |
int (33–119 °F) or "off" |
set_cold_tank_outdoor_reset(value) |
int (0–119 °F) or "off" |
set_cold_tank_differential(value) |
int (2–100 °F) |
set_cold_tank_min_temp(value) |
int (2–180 °F) |
set_cold_tank_max_temp(value) |
int (2–180 °F) |
set_cold_tank_target_temp(value) |
Alias for set_cold_tank_min_temp |
set_dhw_enabled(value) |
bool |
set_dhw_target_temp(value) |
Temperature (33–180 °F) |
set_dhw_differential(value) |
TemperatureDelta (2–100 °F) |
set_backup_lag_time(value) |
int (1–240 min) or "off" |
set_backup_temp(value) |
int (2–100 °F) or "off" |
set_backup_differential(value) |
int (2–100 °F) or "off" |
set_backup_only_outdoor_temp(value) |
int (-40–127 °F) or "off" |
set_backup_only_tank_temp(value) |
int (33–200 °F) or "off" |
Exceptions
| Exception | When raised |
|---|---|
LoginError |
Base class for login failures |
InvalidCredentialsError |
Wrong username or password |
LoginTimeoutError |
Login request timed out |
InvalidParameterError |
A setter received an out-of-range or invalid value |
Testing
pip install -e .[tests]
pytest
License
Metadata
Release files for pysensorlinx 0.5.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pysensorlinx-0.5.6.tar.gz | 37.6 kB | With provenance | Details for pysensorlinx-0.5.6.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pysensorlinx-0.5.6-py3-none-any.whl | Python 3 | none | any | Details for pysensorlinx-0.5.6-py3-none-any.whl |
Total release size: 71.3 kB
Release files / pysensorlinx-0.5.6.tar.gz
| Download URL | pysensorlinx-0.5.6.tar.gz |
|---|---|
| Size | 37.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2bcb2aed9527a45a7c49d80e7f639fce7bfabb302a4e83d6b8cc7334dc342ee0
|
|
BLAKE2b-256 checksum How to use checksums |
34f279e8d0dfa222ce751ff5a7bdf9f96e93642e90faa112f0c4c37197f526d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 May 2, 2026.
Transparency logRelease files / pysensorlinx-0.5.6-py3-none-any.whl
| Download URL | pysensorlinx-0.5.6-py3-none-any.whl |
|---|---|
| Size | 33.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8a3719ddea18e7c640eb8b3806b1b485da411f3d78f04b30b1f5062948102148
|
|
BLAKE2b-256 checksum How to use checksums |
f3eeb6b2ef6c8163e05c872974f7f187d524151f90a49380dcedf7f211d1c279
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 May 2, 2026.
Transparency logSecurity for pysensorlinx 0.5.6
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pysensorlinx-0.5.6.tar.gz
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 May 2, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.