PyAxencoAPI
An asynchronous Python client for MyNeomitis connected devices using the REST API and WebSocket.
Installation
pip install pyaxencoapi
Python 3.14 or later is required. Python 3.11, 3.12, and 3.13 are no longer supported.
Public objects and migration
This release breaks the public contract: device dictionaries are replaced with
AxencoDevice objects, and network, authentication, and response errors become
explicit exceptions. These breaking changes are versioned as 2.0.0.
Availability on PyPI depends on a maintainer publishing this version.
get_devices(force=False) returns a list of AxencoDevice objects and uses a
five-minute cache based on a monotonic clock; an empty list means the inventory
is genuinely empty. get_device_state() returns AxencoState.
subscribe(callback) returns an idempotent unsubscribe function, supports
multiple callbacks, and isolates callback failures. Patches apply only to the
affected device. Each child's physical connection remains independent;
is_device_available(id) combines its connection with those of its known
parents without modifying snapshots. Consumers combine this result with the
transport status and reevaluate children when a parent event arrives.
link, discover, and incomplete events trigger REST inventory reconciliation.
Every connection or reconnection reconciles states before announcing that the
transport is available. Socket.IO headers are rebuilt using the current tokens.
Transient reconciliation failures after reconnection are retried with backoff
until success, shutdown, or authentication rejection.
REST requests have a ten-second timeout. Socket.IO setup has a forty-five-second
timeout and waits for the initial reconciliation. Only an explicit namespace
rejection or an HTTP 401/403 during the handshake triggers at most one shared
refresh per rejected token before retrying. Successfully establishing a namespace
with that token resets the counter, allowing another refresh after a later
expiration. Network failures and HTTP 5xx responses do not refresh the token:
they report AxencoConnectionError and allow automatic reconnection after an
interruption. A permanent rejection stops reconnection attempts and emits
ConnectionChanged(connected=False, error=AxencoAuthError(...)).
An HTTP 401 triggers at most one shared refresh followed by a single retry;
a rejected refresh requires reauthentication.
The supplied aiohttp session belongs to the caller and is never closed by the
library. disconnect_websocket() also stops active handlers, inventory retrieval,
and reconnection tasks. logout() unsubscribes and clears the cache even if the
server rejects the logout request.
Socket.IO >= 5.12 is required for its reconnection task shutdown API.
With Socket.IO 5.12, each namespace rejection can take ten seconds;
a persistent rejection during setup can therefore take twenty seconds.
Action methods raise public exceptions rather than returning booleans.
Programs and the inner response of get_sub_device_state() remain mutable JSON
objects; they must not be used as domain snapshots.
register_listener() and register_removal_callback() are deprecated adapters
that support unsubscribing. The listener receives a partial state dictionary,
but no longer receives states arbitrarily copied from the parent.
register_discovery_callback() is deprecated and provides a projected dictionary
for each device, without raw JSON or an ambiguous list; migrate to DeviceAdded.
from pyaxencoapi import AxencoDevice, AxencoStatePatch
device = AxencoDevice.from_json({
"_id": "device-1",
"model": "NTD",
"connected": True,
"parents": ",gateway-1,",
"state": {"currentTemp": 21.5, "targetTemp": 22, "targetMode": 2},
})
patch = AxencoStatePatch.from_json({"currentTemp": None})
updated_state = patch.apply(device.state)
assert updated_state.current_temperature is None
assert updated_state.target_temperature == 22
assert device.preset_modes.reverse[2] == "eco"
Snapshots are immutable. _id becomes id, and state field names become
explicit (current_temperature, target_temperature,
override_temperature, min_temperature, max_temperature,
comfort_temperature, eco_temperature, target_mode, change_over_user,
device_type). parents is an ordered tuple parsed from the protocol's
comma-delimited string; rfid remains an optional string.
Nonempty IDs and models are required; unknown models remain strings without
invented capabilities.
from_json() validates objects at the protocol boundary: numeric strings and
booleans are not converted to numbers, temperatures must be finite, and codes
must be integers. Unknown integer codes are preserved for extensibility.
Missing or null optional fields become None in a snapshot, including an unknown
physical connection. A missing or null device state produces an unknown state.
Unknown keys are ignored, and no raw JSON is retained. Typed constructors do not
replace this validation. Undocumented program and sub-device schemas are not
defined here.
In AxencoStatePatch, an absent field means UNSET (leave unchanged), while
null means None (clear the value). apply() creates a new state without
changing the previous one. A patch is a state object, not the Socket.IO envelope.
An incomplete inventory event must trigger reconciliation, not be converted into
an artificial device.
AxencoEvent is the union of DeviceUpdated (ID, patch, and optional physical
connection), DeviceAdded (complete device), DeviceRemoved (confirmed removal),
and ConnectionChanged (client transport).
A transport interruption does not change a device's physical connection, and a
parent patch must not be copied to its children.
AxencoError is the base class for AxencoAuthError, AxencoConnectionError,
and AxencoResponseError. Conversions raise AxencoResponseError without
including sensitive payloads; any underlying error is preserved as the cause
(raise ... from ...).
Modes and legacy compatibility
PRESET_MODE_MODELS[model] and ModelPresetMap.reverse are the source of truth.
Code 1 means comfort for NTD, on for EWS relays, and cooling for UFH:
never invert a global mapping. For EWS, device_type set to 0 selects
EWS_RELAIS, and 1 selects EWS_PILOTE; a missing, null, or unknown value
provides no capabilities. device.preset_modes returns a copy.
The legacy constants PRESET_MODE_MAP, PRESET_MODE_SELECT_EXTRAS,
PRESET_MODE_MAP_RELAIS, REVERSE_PRESET_MODE_MAP_RELAIS,
PRESET_MODE_MAP_UFH, and REVERSE_PRESET_MODE_MAP_UFH are available from
pyaxencoapi and pyaxencoapi.const, with a DeprecationWarning.
Reverse mappings remain strictly specific to their family; no ambiguous global
reverse mapping is provided. Preset and its codes remain available.
Compared with version 1.0.7, pinned by Home Assistant:
PRESET_MODE_MAPretains exactly its eight thermostat keys; relay, UFH, andeco_1/eco_2modes remain in their dedicated mappings. For additional models, usePRESET_MODE_MODELS[model]directly rather than looking them up in the legacy thermostat mapping.PRESET_BY_KEYremains available from both modules with aDeprecationWarning; it maps each unique key to itsPreset, including the new relay, UFH, andeco_1/eco_2modes.PRESET_BY_CODEandREVERSE_PRESET_MODE_MAPhave been removed because their global reverse mappings would be ambiguous. Use the model'sreverseproperty.PRESET_MODE_MODELSchanges fromdict[str, list[str]]todict[str, ModelPresetMap]: each value now maps keys to codes.list(PRESET_MODE_MODELS[model])provides the keys, andPRESET_MODE_MODELS[model][key]provides the model-specific code.
Development and validation
python3 --version # 3.14+
python3 -m pip install -e '.[dev]'
python3 -m pytest
python3 -m mypy
python3 -m build
python3 scripts/check_distribution.py dist/*.whl dist/*.tar.gz
Type checking covers the entire library and a consumer of its exports.
The wheel and source distribution include py.typed (PEP 561). REST and Socket.IO
tests use real local servers and work with aiohttp 3.14 without aioresponses or
an upper version bound on the development dependency.
Metadata
Release files for pyaxencoapi 2.0.1
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 | |
|---|---|---|---|---|
| pyaxencoapi-2.0.1.tar.gz | 30.4 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyaxencoapi-2.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 48.2 kB
Release files / pyaxencoapi-2.0.1.tar.gz
| Download URL | pyaxencoapi-2.0.1.tar.gz |
|---|---|
| Size | 30.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cec980696b65507d025a11b5dd0ed36760a25ea6897316f6adda51a097593b08
|
|
BLAKE2b-256 checksum How to use checksums |
5f4a6ad4169f9966a057405dbfb02d106f52cc8d50a1bde029105f27ea18cc08
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 21, 2026.
Transparency logRelease files / pyaxencoapi-2.0.1-py3-none-any.whl
| Download URL | pyaxencoapi-2.0.1-py3-none-any.whl |
|---|---|
| Size | 17.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b99cacc1fe472876090b248df1f0c9d1a677474aef5d3632cb9694cd76fd1382
|
|
BLAKE2b-256 checksum How to use checksums |
bb2127923d418378e9167d2177e69e081abee9ba67b14d6e6afd03c717201333
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 21, 2026.
Transparency logSecurity for pyaxencoapi 2.0.1
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 pyaxencoapi-2.0.1.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 21, 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.