Skip to main content

smartbox

build PyPI version codecov PyPI license PyPI pyversions

Python API to control heating 'smart boxes' (Helki and its resellers: Elnur, Haverland, Climastar, Technotherm, HJM, ...). It wraps the REST API and the socket.io channel, and ships a smartbox command line tool.

Installation

pip install smartbox

The package is importable as smartbox and ships py.typed.

Library usage

AsyncSmartboxSession is the entry point. Use it as an async context manager so its HTTP client is closed for you; when you already have an aiohttp.ClientSession (for example Home Assistant's shared one) pass it as websession= and it will not be closed on exit.

import asyncio
from smartbox import AsyncSmartboxSession

async def main() -> None:
    async with AsyncSmartboxSession(
        api_name="api",            # or SMARTBOX_API_NAME
        username="you@example.com",
        password="secret",
        raw_response=False,        # return Pydantic models instead of dicts
    ) as session:
        for device in await session.get_devices():
            for node in await session.get_nodes(device.dev_id):
                status = await session.get_node_status(device.dev_id, node.model_dump())
                print(device.name, node.name, status.mtemp, status.stemp)

asyncio.run(main())

With raw_response=True (the default) every method returns the raw dict/list from the API. With raw_response=False they return models from smartbox.models (HtrNodeStatus, DefaultNodeSetup, ...); the models are lenient (unknown keys kept, fields optional) because the API is undocumented and varies by reseller.

Constructor options worth knowing: retry_attempts/backoff_factor (transient 5xx / connection errors are retried with exponential backoff), x_referer / x_serial_id / basic_auth_credentials for a reseller that is not built in.

For live updates over socket.io use UpdateManager:

from smartbox import AsyncSmartboxSession, UpdateManager

async with AsyncSmartboxSession(...) as session:
    manager = UpdateManager(session, device_id)
    manager.subscribe_to_node_status(
        lambda node_type, addr, status: print(node_type, addr, status)
    )
    await manager.run()   # runs until cancelled

Websocket transports

Status updates arrive over one of two transports; both are implemented in this library and verified live (api-notes.md, "Transports — socket_io vs ws_user"):

  • socket_io (default): a per-device socket.io connection. The UpdateManager owns it; run() runs the loop, cancel() is terminal.
  • ws_user (the vendor web apps' channel): ONE plain-WebSocket connection (WsUserSocketSession) serves every device of the account. Its server-side proxy PINGs keep the session supervised, and sockets are cut by the server exactly at the access token's 4 h expiry (close code 1006) — the reconnect with a fresh token is mandatory and part of the steady state.

Caller contract for the shared ws_user socket:

socket_ = WsUserSocketSession(session)
# The caller owns run() — and must SUPERVISE it: run() exits on any
# failure (it is re-runnable; only cancel() is terminal), and a
# parked UpdateManager never observes a shared-socket death, so
# without a supervisor the transport dies silently. Exceptions
# surface when the task is awaited, so keep and await it.
task = asyncio.create_task(supervise(socket_.run()))
socket_.add_device(dev_id, dev_data_cb, update_cb)   # register (any time)
socket_.remove_device(dev_id)                        # unregister
await socket_.cancel()          # TERMINAL: later run() calls no-op

run() raises InvalidAuthError (rejected credentials — start a reauthentication flow) and WsUserUnsupportedError (deterministic 404/410 — the host does not serve ws_user; fall back to socket_io).

UpdateManager(session, dev_id, ws_user_socket=socket_) switches an individual manager onto the shared connection: run() registers the manager's device and parks until cancel() (the shared socket's own restarts are handled by its supervisor, not by per-device consumers). Pass-through SocketSession kwargs are ignored in this mode (warned).

smartbox command line tool

Use the smartbox tool to read status information from your heaters (nodes) and change settings.

Options

-u/--username and -p/--password (your mobile-app / web-app credentials) are required for every command except resellers. -v/--verbose enables debug logging.

These are only needed when your reseller is not built into the package:

  • -a/--api-name: the API name for your heater vendor, from the 'API Host' entry under the 'Version' menu of the mobile/web app. For a host api-foo.xxxx or api.xxxx use api-foo or api.
  • -b/--basic-auth-creds: the HTTP Basic Auth credential used for the initial authentication, as a base64 string. See Basic Auth Credential in api-notes.md for how to capture it.
  • -r/--x-referer: the x-referer header value.
  • -i/--x-serial-id: the x-serialid header value.

Configuration via environment variables / .env

Every option above can be supplied through an environment variable instead of being typed on each invocation. The command line always takes precedence over the environment.

Option Environment variable
-a/--api-name SMARTBOX_API_NAME
-b/--basic-auth-creds SMARTBOX_BASIC_AUTH_CREDS
-u/--username SMARTBOX_USERNAME
-p/--password SMARTBOX_PASSWORD
-r/--x-referer SMARTBOX_X_REFERER
-i/--x-serial-id SMARTBOX_X_SERIAL_ID

The smartbox command also reads a .env file (searched for in the working directory and its parents) before parsing options, so the usual workflow is to copy .env.example to .env, fill it in once, and then run commands without any auth flags:

cp .env.example .env
# edit .env
smartbox devices

Commands

In the examples below <auth options...> stands for the options above (or nothing, when they come from .env).

Read-only, across every device/node:

Command What it shows
devices the devices the account can see
homes devices grouped into homes
nodes the nodes of each device
status live status of every node
setup configuration of every node
prog weekly heating schedule of every node
device-away-status away status of every device
device-connected-status whether each device is online
device-power-limit power limit (watts) of every device
health-check whether the API is alive
api-version API build info
resellers resellers with a built-in configuration
smartbox <auth options...> status
smartbox <auth options...> prog

guests needs a home id:

smartbox <auth options...> guests -h <home id>

node-samples reads the temperature/consumption history of one node (-s/-e default to one hour before/after now):

smartbox <auth options...> node-samples -d <device id> -n <node addr> [-s <start unix ts>] [-e <end unix ts>]

Writes take named options, one per field to change:

smartbox <auth options...> set-status -d <device id> -n <node addr> [--mode auto] [--stemp 21.5 --units C] [--locked false]
smartbox <auth options...> set-setup  -d <device id> -n <node addr> [--control-mode 1] [--offset 0.0] [--units C] [--true-radiant-enabled true] [--window-mode-enabled false] [--priority low]
smartbox <auth options...> set-prog -d <device id> -n <node addr> '{"prog": {"0": [2, 2, ...], ...}}'
smartbox <auth options...> set-device-away-status -d <device id> [--away true] [--enabled true] [--forced false]
smartbox <auth options...> set-device-power-limit -d <device id> <watts>

socket opens a long-lived socket.io connection and prints dev_data and update events until interrupted:

smartbox <auth options...> socket -d <device id>

See api-notes.md for notes on the REST and socket.io endpoints.

Development

Prerequisites:

uv
python >=3.14.2

Clone the repo, install dependencies and install pre-commit hooks:

git clone https://github.com/ajtudela/smartbox
cd smartbox
uv sync
pre-commit install

Testing

Run the full suite:

uv run pytest

Generate a coverage XML (e.g. for use in an editor):

uv run pytest --cov-report xml:cov.xml --cov smartbox --cov-append tests/

tox runs the tests against the installed package:

uv run tox
uv run tox -e py           # the single environment declared in pyproject.toml

Changelog

Release notes are kept in CHANGELOG.md.

Support

This is a community project, maintained on a best-effort basis and provided without warranty.

Getting help and reporting problems

Open an issue at https://github.com/ajtudela/smartbox/issues. Templates are provided for the common cases:

  • Bug report — a command or method misbehaves. Include the smartbox command you ran (or the code), the full output with -v/--verbose, and your reseller. Redact the access token and any Basic Auth credential before pasting logs.
  • Feature request — a missing endpoint or option.
  • New reseller — your heater vendor is not in the built-in list. The template asks for api-name, x-referer, x-serial-id and the Basic Auth credential; see "Capturing it from the reseller's web app" in api-notes.md for how to read them from the login request. Once added, everyone using that vendor benefits.

For questions about the API itself rather than this library, see api-notes.md.

Supporting the maintainers

If this library is useful to you, you can buy the maintainers a coffee:

Buy a coffee to ajtudela Buy a coffee to delmael

Metadata

Release files for smartbox 2.7.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 smartbox 2.7.0
File Size Uploaded Provenance Actions
smartbox-2.7.0.tar.gz 253.6 kB With provenance Details for smartbox-2.7.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for smartbox 2.7.0
File Interpreter ABI Platform Actions
smartbox-2.7.0-py3-none-any.whl Python 3 none any Details for smartbox-2.7.0-py3-none-any.whl

Total release size: 311.0 kB

Release files / smartbox-2.7.0.tar.gz

Download URL smartbox-2.7.0.tar.gz
Size 253.6 kB
Tags Source
SHA-256 checksum
How to use checksums
66ef74b5a933b72cb49a1c103c8b1f64f3824d97925e50ce330025b54b6c2792
BLAKE2b-256 checksum
How to use checksums
27f1410f8a3f8116bbe299c01156d9d01b26cb8b585ab8cd6759e751a309eb21
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 Oct 12, 2026.

Transparency log

Release files / smartbox-2.7.0-py3-none-any.whl

Download URL smartbox-2.7.0-py3-none-any.whl
Size 57.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e6e988c5252646dbf66a4369f728d918baceb71fec13957ea78d1056d8ee2a9d
BLAKE2b-256 checksum
How to use checksums
8860b95bf32ae2a53e62d209c9c2a4fab8ff57980aaa416c9cde03aa3dea5b6d
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 Oct 12, 2026.

Transparency log

Security for smartbox 2.7.0

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.

Select from 2 files

Attestation for smartbox-2.7.0.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 Oct 12, 2026.

Transparency log

A 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.

Release history Release notifications | RSS feed

This release

2.7.0 This release

2 release files Full provenance

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