ActronAirAPI
The ActronAirAPI library provides an interface to communicate with Actron Air systems, enabling integration with Home Assistant or other platforms. This Python library offers methods for authentication, token management, and interacting with AC systems, zones, and settings.
Features
- Authentication:
- OAuth2 device code flow for secure authentication.
- Automatic and proactive token refresh.
- Token expiration tracking.
- System Information:
- Retrieve system details, statuses, and events.
- Strongly-typed data models with Pydantic.
- Control Features:
- Set system modes (e.g., COOL, HEAT, AUTO, FAN).
- Enable/disable zones.
- Adjust fan modes, continuous mode, and temperatures.
- Object-Oriented API:
- Call control methods directly on model objects.
- Intuitive interface for AC system, settings and zone management.
- More natural integration with object-oriented code.
- Advanced State Management:
- Efficient incremental state updates.
- Event-based state tracking.
- Type-safe access to device properties.
Installation
pip install actron-neo-api
Supported Platforms
The library supports multiple Actron Air product lines:
- Neo: Standard Actron Air systems (default platform)
- Que (NX-Gen): NX Gen systems using the Que platform
The API automatically detects the correct platform based on your system type. You can also explicitly specify the platform:
# Auto-detect platform (recommended)
api = ActronAirAPI(refresh_token="your_token")
# Or explicitly specify platform
api = ActronAirAPI(refresh_token="your_token", platform="neo") # Neo platform
api = ActronAirAPI(refresh_token="your_token", platform="que") # NX-Gen platform
Realtime transport selection is automatic when push is enabled:
- Neo systems use the MQTT realtime transport.
- Que (NX-Gen) systems use the SignalR (SSE) realtime transport.
- If realtime startup fails,
start_push()returnsFalseand your existing polling flow remains available. - If the credentials are rejected,
start_push()raisesActronAirAuthErrorinstead, so callers can trigger re-authentication rather than silently falling back to polling.
Realtime Push Updates
Use realtime push when you want status updates delivered as events instead of polling loops.
import asyncio
from actron_neo_api import ActronAirAPI
async def main() -> None:
api = ActronAirAPI(refresh_token="your_refresh_token")
systems = await api.get_ac_systems()
serial = systems[0].serial
started = await api.start_push([serial])
if not started:
# Realtime unavailable for this session; keep using polling.
await api.update_status(serial)
return
def on_update(status):
print(f"Push update for {status.serial_number}")
def on_connection(event):
print(f"Realtime transport is now {event.state.value}")
# Both subscribe calls return a callable that removes the subscription.
unsubscribe = api.subscribe_system_updates(serial, on_update)
unsubscribe_connection = api.subscribe_connection_state(on_connection)
async for status in api.stream_system_updates(serial):
print(f"Mode: {status.user_aircon_settings.mode}")
break
unsubscribe()
unsubscribe_connection()
await api.stop_push()
asyncio.run(main())
Home Assistant integration impact:
- Consumers continue to receive the same typed
ActronAirStatusmodel. - Consumer code does not need to handle MQTT/SignalR directly.
- Existing polling flows remain valid and can continue to be used when push is unavailable.
Detailed implementation/handoff notes are available in docs/rt_push_implementation.md.
Quick Start
See example.py for a comprehensive demonstration including OAuth2 authentication and API usage.
import asyncio
from actron_neo_api import ActronAirAPI
async def main():
# Initialize with refresh token - token will be refreshed on first API call
api = ActronAirAPI(refresh_token="your_refresh_token")
# Get systems and update status
systems = await api.get_ac_systems()
api.systems = systems
await api.update_status()
# Get the status object
serial = systems[0].get("serial")
status = api.state_manager.get_status(serial)
# Control your AC system using object-oriented methods
# Through the AC system object
await status.ac_system.set_system_mode(mode="COOL")
# Through the settings object
await status.user_aircon_settings.set_temperature(23.0) # Mode inferred automatically
await status.user_aircon_settings.set_fan_mode("HIGH")
# Control zones directly
zone = status.remote_zone_info[0]
await zone.enable(is_enabled=True)
await zone.set_temperature(22.0) # Mode inferred from parent AC unit
if __name__ == "__main__":
asyncio.run(main())
OAuth2 Device Code Flow
The ActronAirAPI uses OAuth2 device code flow for secure authentication without storing passwords.
Basic OAuth2 Setup
import asyncio
from actron_neo_api import ActronAirAPI
async def oauth2_flow():
# Initialize API
async with ActronAirAPI() as api:
# Request device code
device_code_response = await api.request_device_code()
device_code = device_code_response.device_code
user_code = device_code_response.user_code
verification_uri = device_code_response.verification_uri
verification_uri_complete = device_code_response.verification_uri_complete
expires_in = device_code_response.expires_in
interval = device_code_response.interval
# Display instructions to user
print("1. Open: %s" % verification_uri)
print("2. Enter code: %s" % user_code)
print("3. Or use direct link: %s" % verification_uri_complete)
# Poll for authorization (automatic polling)
print("Waiting for authorization...")
token_data = await api.poll_for_token(
device_code,
interval=interval,
timeout=expires_in
)
if token_data:
print("Authorization successful!")
# Get user info
user_info = await api.get_user_info()
print(f"Authenticated as: {user_info}")
# Use API normally
systems = await api.get_ac_systems()
await api.update_status()
# Save tokens for future use
access_token = api.access_token
refresh_token = api.refresh_token_value
print(f"Save these tokens: {access_token}, {refresh_token}")
asyncio.run(oauth2_flow())
Polling Method Improvements
The poll_for_token() method now includes automatic polling with intelligent retry logic:
- Automatic polling loop: No need to implement your own polling loop
- Smart interval handling: Automatically increases polling interval when server requests "slow down"
- Configurable timeout: Set maximum waiting time (default: 10 minutes)
- Proper error handling: Distinguishes between authorization denied, expired tokens, and network errors
- Logging: Detailed logging for debugging authentication issues
New signature:
token_data = await api.poll_for_token(
device_code,
interval=5, # Polling interval in seconds (default: 5)
timeout=600 # Maximum wait time in seconds (default: 600 = 10 minutes)
)
Backward compatibility: The old single-shot polling is still available via poll_for_token_once() if you need to implement custom polling logic.
Restoring Saved Tokens
async def restore_session():
# Initialize with refresh token - token will be refreshed on first API call
api = ActronAirAPI(refresh_token="your_saved_refresh_token")
# API will automatically refresh tokens as needed
systems = await api.get_ac_systems()
OAuth2 Endpoints
The library uses these OAuth2 endpoints:
- Token URL:
https://nimbus.actronair.com.au/api/v0/oauth/token - Authorize URL:
https://nimbus.actronair.com.au/authorize - Device Auth URL:
https://nimbus.actronair.com.au/connect - User Info URL:
https://nimbus.actronair.com.au/api/v0/client/account
System Information
# Get all AC systems
systems = await api.get_ac_systems()
for system in systems:
print(f"System: {system.get('name')} (Serial: {system.get('serial')})")
# Update status to get the latest data
await api.update_status()
# Access typed status for a system
serial = systems[0].get("serial")
status = api.state_manager.get_status(serial)
# Access system properties
if status and status.user_aircon_settings:
print(f"Power: {'ON' if status.user_aircon_settings.is_on else 'OFF'}")
print(f"Mode: {status.user_aircon_settings.mode}")
print(f"Cool Setpoint: {status.user_aircon_settings.temperature_setpoint_cool_c}°C")
Object-Oriented Control API (Recommended)
The object-oriented API allows you to call methods directly on the model objects for a more intuitive developer experience:
AC System Control
# Get the status object
status = api.state_manager.get_status("AC_SERIAL")
# Direct AC system control
ac_system = status.ac_system
# Change system name
await ac_system.set_name("Living Room AC")
# Turn the system on and set mode
await ac_system.set_system_mode(mode="COOL")
# Get system information
firmware_version = await ac_system.get_firmware_version()
outdoor_unit_model = await ac_system.get_outdoor_unit_model()
# Reboot the system when needed
await ac_system.reboot()
# Force status update for this specific system
updated_status = await ac_system.update_status()
System Settings Control
# Get the status object
status = api.state_manager.get_status("AC_SERIAL")
# Settings control
settings = status.user_aircon_settings
# Turn the system on/off and set mode
await settings.set_system_mode(mode="COOL")
# Set temperature (mode is automatically inferred from current system mode)
await settings.set_temperature(23.0)
# Fan control
# Check continuous mode status
is_continuous = settings.continuous_fan_enabled
base_mode = settings.base_fan_mode
# Set fan mode (preserves current continuous mode setting)
await settings.set_fan_mode("HIGH")
# Enable/disable continuous fan mode
await settings.set_continuous_mode(enabled=True)
# Enable/disable features
await settings.set_quiet_mode(enabled=True)
await settings.set_turbo_mode(enabled=False)
await settings.set_away_mode(enabled=False)
Zone Control
# Get the status object
status = api.state_manager.get_status("AC_SERIAL")
# Enable/disable a zone directly
zone = status.remote_zone_info[0] # First zone
await zone.enable(is_enabled=True)
# Set zone temperature (mode is automatically inferred from the parent AC unit)
await zone.set_temperature(22.0)
# Check zone temperature limits
print(f"Zone min temp: {zone.min_temp}°C")
print(f"Zone max temp: {zone.max_temp}°C")
# Enable/disable multiple zones
zones = status.remote_zone_info
for i, zone in enumerate(zones):
if i == 0 or i == 2: # Enable zones 0 and 2
await zone.enable(is_enabled=True)
else: # Disable other zones
await zone.enable(is_enabled=False)
Error Handling
from actron_neo_api import ActronAirAPI, ActronAirAuthError, ActronAirAPIError
try:
api = ActronAirAPI(refresh_token="your_refresh_token")
# API operations...
systems = await api.get_ac_systems()
except ActronAirAuthError as e:
print(f"Authentication error: {e}")
except ActronAirAPIError as e:
print(f"API error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
Logging
import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger("actron_neo_api").setLevel(logging.DEBUG) # For more detailed logging
Contributing
Contributions are welcome! Please submit issues and pull requests on GitHub.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Disclaimer
This library is not affiliated with or endorsed by Actron Air. Use it at your own risk.
Metadata
Release files for actron-neo-api 0.5.16
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 | |
|---|---|---|---|---|
| actron_neo_api-0.5.16.tar.gz | 124.2 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| actron_neo_api-0.5.16-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 183.8 kB
Release files / actron_neo_api-0.5.16.tar.gz
| Download URL | actron_neo_api-0.5.16.tar.gz |
|---|---|
| Size | 124.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0d4880efed1f6cfb5d8f93a99bd9a3362230d6b6c55cf71864648f85dc900376
|
|
BLAKE2b-256 checksum How to use checksums |
a0cd53ceab84530f58ad24dcc646ef08cca2a44a0ce6653e0c8daafa4ccbaa6d
|
| 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 Sep 8, 2026.
Transparency logRelease files / actron_neo_api-0.5.16-py3-none-any.whl
| Download URL | actron_neo_api-0.5.16-py3-none-any.whl |
|---|---|
| Size | 59.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e5a4f37d4dfb1b7a170ec12319c01e57dac93bafcbab009a1639fad7bcb2d9b8
|
|
BLAKE2b-256 checksum How to use checksums |
05d6cc8ecdd86e5d2f901e307c59d52eb6a68f07f25c1b076f629592a1650f35
|
| 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 Sep 8, 2026.
Transparency logSecurity for actron-neo-api 0.5.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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for actron_neo_api-0.5.16.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 Sep 8, 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.