Asynchronous library for Jandy iAqualink
Project description
🏊 iaqualink-py
Asynchronous Python library for Jandy iAqualink pool control systems
📖 Overview
iaqualink-py is a modern, fully asynchronous Python library for interacting with Jandy iAqualink pool and spa control systems. It provides a clean, Pythonic interface to monitor and control your pool equipment from your Python applications.
✨ Features
- 🔄 Fully Asynchronous - Built with
asyncioandhttpxfor efficient, non-blocking I/O - 🔁 HTTP Retry Transport - Uses
httpx-retriesfor 429 backoff andRetry-Afterhandling - 🔐 401 Replay for Auth-Bearing Requests - Rebuilds and replays systems discovery and iaqua/exo system requests after auth refresh
- 🏗️ Multi-System Support
- iAqua systems (iaqualink.net API)
- eXO systems (zodiac-io.com API)
- 🌡️ Comprehensive Device Support
- Temperature sensors (pool, spa, air)
- Thermostats with adjustable set points
- Pumps and heaters
- Lights with toggle control
- Auxiliary switches
- Water chemistry sensors (pH, ORP, salinity)
- Freeze protection monitoring
- 🔌 Context Manager Support - Automatic resource cleanup
- 🛡️ Type Safe - Full type hints for modern Python development
- ⚡ Rate Limiting - Built-in throttling to respect API limits
📦 Installation
pip install iaqualink
Or using uv:
uv add iaqualink
🚀 Quick Start
Basic Usage
from iaqualink import AqualinkClient
async with AqualinkClient('user@example.com', 'password') as client:
# Discover your pool systems
systems = await client.get_systems()
# Get the first system
system = list(systems.values())[0]
print(f"Found system: {system.name}")
# Get all devices
devices = await system.get_devices()
# Access specific devices
pool_temp = devices.get('pool_temp')
if pool_temp:
print(f"Pool temperature: {pool_temp.state}°F")
spa_heater = devices.get('spa_heater')
if spa_heater:
print(f"Spa heater: {'ON' if spa_heater.is_on else 'OFF'}")
Controlling Devices
# Turn on pool pump
pool_pump = devices.get('pool_pump')
if pool_pump:
await pool_pump.turn_on()
# Set spa temperature
spa_thermostat = devices.get('spa_set_point')
if spa_thermostat:
await spa_thermostat.set_temperature(102)
# Toggle pool light
pool_light = devices.get('aux_3')
if pool_light:
await pool_light.toggle()
Monitoring System Status
# Update system state
await system.update()
# Check if system is online
if system.online:
print(f"System {system.name} is online")
# Get all temperature readings
for device_name, device in devices.items():
if 'temp' in device_name and device.state:
print(f"{device.label}: {device.state}°")
🔧 Advanced Usage
Working with Multiple Systems
async with AqualinkClient('user@example.com', 'password') as client:
systems = await client.get_systems()
for serial, system in systems.items():
print(f"System: {system.name} ({serial})")
print(f"Type: {system.data.get('device_type')}")
devices = await system.get_devices()
print(f"Devices: {len(devices)}")
Custom Update Intervals
The library automatically rate-limits updates to once every 5 seconds per system to respect API limits. Subsequent calls within this window return cached data.
# First call - fetches from API
await system.update()
# Immediate second call - returns cached data
await system.update()
# After 5+ seconds - fetches fresh data
await asyncio.sleep(5)
await system.update()
🏗️ Architecture
The library uses a plugin-style architecture with base classes and system-specific implementations:
- AqualinkClient - Authentication and system discovery
- AqualinkSystem - Base class with iAqua and eXO implementations
- AqualinkDevice - Device hierarchy with type-specific subclasses
See CLAUDE.md for detailed architecture documentation.
🧪 Development
Setup Development Environment
# Clone the repository
git clone https://github.com/flz/iaqualink-py.git
cd iaqualink-py
# Install dependencies
uv sync --group dev --group test
Running Tests
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov-report=xml --cov=iaqualink
# Run specific test file
uv run pytest tests/test_client.py
Code Quality
# Run all pre-commit hooks (ruff, mypy)
uv run pre-commit run --all-files
# Auto-fix linting issues
uv run ruff check --fix .
# Format code
uv run ruff format .
# Type checking
uv run mypy src/
📋 Requirements
- Python 3.14 or higher
- httpx with HTTP/2 support
- httpx-retries for transport-level 429 retry handling
📄 License
This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
🔗 Links
⚠️ Disclaimer
This is an unofficial library and is not affiliated with or endorsed by Jandy, Zodiac Pool Systems, or Fluidra. Use at your own risk.
Made with ❤️ by Florent Thoumie
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file iaqualink-0.7.0rc1.tar.gz.
File metadata
- Download URL: iaqualink-0.7.0rc1.tar.gz
- Upload date:
- Size: 84.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84a805e5ae1ceec64bcfed1d759ae057441b9fd6029b5613b89c1736b46865db
|
|
| MD5 |
287151b92f8ca7af176634dc3856daf2
|
|
| BLAKE2b-256 |
70d2d5f119264cc4a5e1fe8c7bc7375deefc6658605c925f561be5b8a1fe2e64
|
Provenance
The following attestation bundles were made for iaqualink-0.7.0rc1.tar.gz:
Publisher:
release.yaml on flz/iaqualink-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
iaqualink-0.7.0rc1.tar.gz -
Subject digest:
84a805e5ae1ceec64bcfed1d759ae057441b9fd6029b5613b89c1736b46865db - Sigstore transparency entry: 1346277051
- Sigstore integration time:
-
Permalink:
flz/iaqualink-py@1a06b18d21ad96f62d0b8da2b37b6bf934fe8493 -
Branch / Tag:
refs/tags/v0.7.0-rc.1 - Owner: https://github.com/flz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@1a06b18d21ad96f62d0b8da2b37b6bf934fe8493 -
Trigger Event:
push
-
Statement type:
File details
Details for the file iaqualink-0.7.0rc1-py3-none-any.whl.
File metadata
- Download URL: iaqualink-0.7.0rc1-py3-none-any.whl
- Upload date:
- Size: 21.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18b33e7c665c310628b8b62def45c5468b2cc066cb25284534856f8d4bae9842
|
|
| MD5 |
00321616e42b0470d73cce013b29bf13
|
|
| BLAKE2b-256 |
2ad35da21e613f0e640e5fd45952fbae98f9489432bc61275449637534a4f6ab
|
Provenance
The following attestation bundles were made for iaqualink-0.7.0rc1-py3-none-any.whl:
Publisher:
release.yaml on flz/iaqualink-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
iaqualink-0.7.0rc1-py3-none-any.whl -
Subject digest:
18b33e7c665c310628b8b62def45c5468b2cc066cb25284534856f8d4bae9842 - Sigstore transparency entry: 1346277060
- Sigstore integration time:
-
Permalink:
flz/iaqualink-py@1a06b18d21ad96f62d0b8da2b37b6bf934fe8493 -
Branch / Tag:
refs/tags/v0.7.0-rc.1 - Owner: https://github.com/flz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@1a06b18d21ad96f62d0b8da2b37b6bf934fe8493 -
Trigger Event:
push
-
Statement type: