Skip to main content

Unofficial Python client for Caldera Spa API

Project description

pycaldera

Python client library for controlling Caldera spas via their cloud API.

Installation

pip install pycaldera

Usage

Asynchronous API

import asyncio
from pycaldera import AsyncCalderaClient, PUMP_OFF, PUMP_LOW, PUMP_HIGH


async def main():
    async with AsyncCalderaClient("email@example.com", "password") as spa:
        # Get current spa status
        status = await spa.get_spa_status()
        print(f"Current temperature: {status.water_temperature}°F")

        # Get detailed live settings
        settings = await spa.get_live_settings()
        print(f"Target temperature: {settings.ctrl_head_set_temperature}°F")

        # Control the spa
        await spa.set_temperature(102)  # Set temperature to 102°F
        await spa.set_pump(1, PUMP_HIGH)  # Set pump 1 to high speed
        await spa.set_lights(True)  # Turn on the lights


asyncio.run(main())

Synchronous API

For simpler use cases, a synchronous wrapper is also available:

from pycaldera import CalderaClient, PUMP_OFF, PUMP_LOW, PUMP_HIGH

with CalderaClient("email@example.com", "password") as spa:
    # Get current spa status
    status = spa.get_spa_status()
    print(f"Current temperature: {status.water_temperature}°F")

    # Get detailed live settings
    settings = spa.get_live_settings()
    print(f"Target temperature: {settings.ctrl_head_set_temperature}°F")

    # Control the spa
    spa.set_temperature(102)  # Set temperature to 102°F
    spa.set_pump(1, PUMP_HIGH)  # Set pump 1 to high speed
    spa.set_lights(True)  # Turn on the lights

Both clients provide identical functionality, with the synchronous client simply wrapping the async one for convenience.

API Reference

AsyncCalderaClient

The main async client class for interacting with the spa. All operations must be performed within an async context manager:

async with AsyncCalderaClient(
    email="email@example.com",
    password="password",
    timeout=10.0,  # Optional: request timeout in seconds
    debug=False,  # Optional: enable debug logging
) as spa:
    # All spa operations must be inside this block
    await spa.get_spa_status()
    await spa.set_temperature(102)
    # etc...

CalderaClient

A synchronous wrapper around AsyncCalderaClient that provides the same functionality without requiring async/await:

with CalderaClient(
    email="email@example.com",
    password="password",
    timeout=10.0,  # Optional: request timeout in seconds
    debug=False,  # Optional: enable debug logging
) as spa:
    # All spa operations can be called synchronously
    spa.get_spa_status()
    spa.set_temperature(102)
    # etc...

Error Handling

All operations can raise these base exceptions:

  • AuthenticationError: When authentication fails or token expires
  • ConnectionError: When network connection fails or API is unreachable
  • SpaControlError: When the API returns an error response

Temperature Control

async with spa as client:
    # Set temperature (80-104°F or 26.5-40°C)
    try:
        # Basic temperature setting
        await client.set_temperature(102)  # Fahrenheit
        await client.set_temperature(39, "C")  # Celsius

        # Wait for spa to acknowledge the temperature change
        await client.set_temperature(102, wait_for_ack=True)

        # Control polling behavior when waiting for acknowledgment
        await client.set_temperature(
            102,
            wait_for_ack=True,
            polling_interval=5.0,  # Check every 5 seconds
            polling_timeout=120.0,  # Time out after 2 minutes
        )

        # Manually wait for temperature acknowledgment
        settings = await client.wait_for_temperature_ack(
            expected_temp=102,  # Expected temperature in Fahrenheit
            interval=5.0,  # Check every 5 seconds
            timeout=120.0,  # Time out after 2 minutes
        )
    except InvalidParameterError:
        # Raised when temperature is outside valid range
        # (80-104°F or 26.5-40°C)
        pass
    except SpaControlError:
        # Raised when polling times out waiting for acknowledgment
        pass

Pump Control

async with spa as client:
    try:
        await client.set_pump(1, PUMP_HIGH)  # Set pump 1 to high speed
        await client.set_pump(2, PUMP_LOW)  # Set pump 2 to low speed
        await client.set_pump(3, PUMP_OFF)  # Turn off pump 3
    except InvalidParameterError:
        # Raised when:
        # - pump_number is not 1, 2, or 3
        # - speed is not PUMP_OFF (0), PUMP_LOW (1), or PUMP_HIGH (2)
        pass

Light Control

async with spa as client:
    try:
        await client.set_lights(True)  # Turn lights on
        await client.set_lights(False)  # Turn lights off
    except SpaControlError:
        # Raised when light control fails
        pass

Status & Settings

async with spa as client:
    try:
        # Get basic spa status
        status = await client.get_spa_status()
        print(f"Online: {status.status == 'ONLINE'}")

        # Get detailed live settings
        settings = await client.get_live_settings()
        print(f"Target temp: {settings.ctrl_head_set_temperature}°F")
    except ConnectionError:
        # Raised when spa is offline or unreachable
        pass
    except SpaControlError:
        # Raised when API returns invalid data
        pass

## Development

1. Clone the repository
2. Create a virtual environment:
   ```bash
   python -m venv venv
   source venv/bin/activate  # or `venv\Scripts\activate` on Windows
  1. Install development dependencies:
    pip install -r requirements-dev.txt
    
  2. Install pre-commit hooks:
    pre-commit install
    

The pre-commit hooks will run automatically on git commit, checking:

  • Code formatting (Black)
  • Import sorting (isort)
  • Type checking (mypy)
  • Linting (pylint, ruff)
  • YAML/TOML syntax
  • Trailing whitespace and file endings

License

MIT License - see LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pycaldera-0.1.1.tar.gz (24.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pycaldera-0.1.1-py3-none-any.whl (15.8 kB view details)

Uploaded Python 3

File details

Details for the file pycaldera-0.1.1.tar.gz.

File metadata

  • Download URL: pycaldera-0.1.1.tar.gz
  • Upload date:
  • Size: 24.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pycaldera-0.1.1.tar.gz
Algorithm Hash digest
SHA256 115e4e50bbc9f40c29adae166190fc3ba1b00067558748aa948677c62fbd071b
MD5 376778e3c0f80a55a8c4e9b38174d75b
BLAKE2b-256 6b5ed74addb027748008c02f2a72a5af4d6fa6268d1bb849699c6322b0495a4b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pycaldera-0.1.1.tar.gz:

Publisher: release.yaml on mwatson2/pycaldera

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pycaldera-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: pycaldera-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 15.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pycaldera-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 13b0a13b1a76be6fb38a6d26da879950ab2dd05f16e549b03da387caa7ae4d25
MD5 1bd96b682520bf4e04ca098081adf0e6
BLAKE2b-256 15988e4a2057cb38db96ef583b877125bfef10275b57940c08cc64071e508c1c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pycaldera-0.1.1-py3-none-any.whl:

Publisher: release.yaml on mwatson2/pycaldera

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page