File: README.md

package info (click to toggle)
python-actron-neo-api 0.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 340 kB
  • sloc: python: 2,439; makefile: 3
file content (331 lines) | stat: -rw-r--r-- 9,757 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# 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

```bash
pip install actron-neo-api
```

---

## Quick Start

See `example.py` for a comprehensive demonstration including OAuth2 authentication and API usage.

```python
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

```python
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:**
```python
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

```python
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

```python
# 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

```python
# 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

```python
# 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

```python
# 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

```python
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

```python
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](https://github.com/kclif9/actronneoapi).

---

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