Danfoss Ally API
Async-first Python client for the Danfoss Ally OpenAPI.
Installation
pip install pydanfossally
Local development
For local development with Poetry and VS Code debugging, this repository is configured to use
an in-project virtual environment at .venv.
poetry install
poetry run python example.py
If you already created a Poetry environment before this setting was added, recreate it once so
Poetry installs dependencies into .venv for this repository.
Async usage
Long-lived client
This is the recommended pattern for smart-home systems and other integrations that keep one client alive and reuse it across many calls.
from pydanfossally import DanfossAlly
ally = DanfossAlly(
timeout=30,
refresh_device_concurrency=5,
refresh_device_min_interval=0.10,
hot_refresh_timeout=300,
user_agent_prefix="HomeAssistant-DanfossAlly/2026.3.0",
)
authorized = await ally.initialize(key, secret)
if not authorized:
raise RuntimeError("Authorization failed")
devices = await ally.get_devices()
print(devices)
await ally.aclose()
Context-managed client
This is a good fit for small scripts, one-off tools, and examples where you want automatic resource cleanup.
import asyncio
import os
from pydanfossally import DanfossAlly
async def main() -> None:
async with DanfossAlly(
timeout=30,
refresh_device_concurrency=5,
refresh_device_min_interval=0.10,
hot_refresh_timeout=300,
user_agent_prefix="HomeAssistant-DanfossAlly/2026.3.0",
) as ally:
authorized = await ally.initialize(os.environ["KEY"], os.environ["SECRET"])
if not authorized:
raise RuntimeError("Authorization failed")
devices = await ally.get_devices()
print(devices)
asyncio.run(main())
Supported OpenAPI endpoints
POST /oauth2/tokenGET /ally/devicesGET /ally/devices/{device_id}GET /ally/devices/{device_id}/sub-devicesGET /ally/devices/{device_id}/statusPOST /ally/devices/{device_id}/commands
Notes about the data model
The transport layer follows the OpenAPI file in docs/openapi-spec.
The parsed devices mapping is a best-effort convenience model built from observed status
codes. The OpenAPI file documents generic {code, value} pairs, but it does not define all
device-specific status or command codes. That means:
- request/response transport compatibility is covered by the library
- friendly parsed fields are based on current observed API behavior
- some status fields may vary between device types
Known gaps
- The OpenAPI file does not fully document which command
codevalues are supported for all device types. - The
POST /commandsresponse shape is inconsistent between schema and examples; this client accepts both{"result": true, "t": ...}and{"t": ...}. - Live verification should be performed against read-only endpoints before enabling write flows in production integrations.
Refresh behavior
Each refresh_devices() call always starts with a bulk read from GET /ally/devices.
After successful write operations (set_mode(...) and send_command(...)), the target device is
tracked as pending hot refresh. While pending, refresh_devices() also calls
GET /ally/devices/{device_id}/status for that device.
Hot refresh for a pending device stops when either of these conditions is met:
- the latest bulk snapshot differs from the baseline state captured when the write succeeded
- the hot refresh timeout is reached (default: 300 seconds / 5 minutes)
The refresh tuning knobs are configurable through DanfossAlly(...):
refresh_device_concurrencycontrols how many status hot refresh calls may run at oncerefresh_device_min_intervalcontrols the minimum delay in seconds between starting two status hot refresh callshot_refresh_timeoutcontrols how long a device stays in pending hot refresh mode
User-Agent
By default, the client sends a User-Agent header in the form pydanfossally/<version>.
Integrations can prepend their own identifier through user_agent_prefix, resulting in a final
header such as HomeAssistant-DanfossAlly/2026.3.0 pydanfossally/<version>.
Writable temperature helpers
The client includes explicit helpers for several writable temperature-like settings:
set_upper_temp(device_id, temp)set_lower_temp(device_id, temp)set_at_home_setting(device_id, temp)set_leaving_home_setting(device_id, temp)set_holiday_setting(device_id, temp)set_pause_setting(device_id, temp)
These helpers validate values before writing them:
- minimum
5.0 - maximum
35.0 - only
0.5degree steps
Example:
devices = await ally.get_devices()
device = devices["device-1"]
await ally.set_upper_temp("device-1", 28.0)
await ally.set_lower_temp("device-1", 7.0)
await ally.set_at_home_setting("device-1", 21.5)
await ally.set_leaving_home_setting("device-1", 17.0)
await ally.set_holiday_setting("device-1", 15.0)
await ally.set_pause_setting("device-1", 8.0)
await ally.refresh_device("device-1")
device = ally.devices["device-1"]
print(device["upper_temp"])
print(device["lower_temp"])
print(device["at_home_setting"])
print(device["leaving_home_setting"])
print(device["holiday_setting"])
print(device["pause_setting"])
Read access for these values is exposed through the parsed device state returned by
get_devices(), get_device(), refresh_device(), and refresh_devices(). The library does
not currently include dedicated getter methods for these fields because they are already part of
the normal device model.
Local verification
The repository includes example.py as a small async read-only example that uses credentials
from the environment.
Metadata
Release files for pydanfossally 1.3.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 | Provenance | |
|---|---|---|---|---|
| pydanfossally-1.3.0.tar.gz | 26.7 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pydanfossally-1.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 54.2 kB
Release files / pydanfossally-1.3.0.tar.gz
| Download URL | pydanfossally-1.3.0.tar.gz |
|---|---|
| Size | 26.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
aec8a409ca6c352d22a612a9b26e502a0d6fc18c3a82db2a8447299ca28a6cb3
|
|
BLAKE2b-256 checksum How to use checksums |
83be243253b16f8b08793281862f7b709bc88da9264f78da73843eeef6337536
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Apr 1, 2026.
Transparency logRelease files / pydanfossally-1.3.0-py3-none-any.whl
| Download URL | pydanfossally-1.3.0-py3-none-any.whl |
|---|---|
| Size | 27.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c4505f851e062ad60b58e9f5a8e896703ced61d0f2ab694a54bcc15c7d68db88
|
|
BLAKE2b-256 checksum How to use checksums |
188126d335fcdd8efdf96a598aafb04ad378f18041f7fdc06b66c310e33dbdfc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Apr 1, 2026.
Transparency logSecurity for pydanfossally 1.3.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.
Attestation for pydanfossally-1.3.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 Apr 1, 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.