### Hydrawise 5-Minute Example Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/README.md A complete asynchronous example showing authentication, controller and zone retrieval, and starting a zone. ```python import asyncio from pydrawise import Auth, Hydrawise async def main(): # Authenticate auth = Auth("user@example.com", "password") client = Hydrawise(auth) # Get controllers controllers = await client.get_controllers() for controller in controllers: print(f"Controller: {controller.name}") # Get zones zones = await client.get_zones(controller) for zone in zones: print(f" Zone: {zone.name}") # Start first zone if zones: await client.start_zone(zones[0], custom_run_duration=600) print(f" Started {zones[0].name} for 10 minutes") asyncio.run(main()) ``` -------------------------------- ### Setup HybridClient Instance Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Example demonstrating how to authenticate and initialize the HybridClient for use in an asynchronous environment. ```python from pydrawise.auth import HybridAuth from pydrawise.hybrid import HybridClient async def setup(): auth = HybridAuth( username="user@example.com", password="password", api_key="rest_api_key" ) client = HybridClient(auth) user = await client.get_user() return client client = asyncio.run(setup()) ``` -------------------------------- ### Setup and Authenticate RestClient Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Example of initializing the client with RestAuth and performing an initial request. ```python from pydrawise.auth import RestAuth from pydrawise.rest import RestClient async def setup(): auth = RestAuth("your_api_key") client = RestClient(auth) user = await client.get_user() return client client = asyncio.run(setup()) ``` -------------------------------- ### LegacyHydrawise Full Usage Example Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/legacy-client.md Demonstrates initializing the client, listing zones, and performing zone control actions like starting, suspending, and stopping. ```python from pydrawise.legacy import LegacyHydrawise import time # Initialize h = LegacyHydrawise("your_api_key_here") print(f"Controller: {h.name}") print(f"Status: {h.status}") print(f"Number of zones: {h.num_relays}") # List all zones print("\nAvailable zones:") for zone in h.relays: print(f" Zone {zone['relay']}: {zone['name']} (ID: {zone['relay_id']})") # Start zone 1 for 5 minutes print("\nStarting zone 1 for 5 minutes...") h.run_zone(minutes=5, zone=1) # Check status after delay time.sleep(2) h.update_controller_info() print(f"Status after start: {h.status}") # Suspend zone 1 for 2 days print("\nSuspending zone 1 for 2 days...") h.suspend_zone(days=2, zone=1) # Resume zone 1 print("\nResuming zone 1...") h.suspend_zone(days=0, zone=1) # Stop all zones print("\nStopping all zones...") h.run_zone(minutes=0) print("\nDone!") ``` -------------------------------- ### Install Pydrawise from source Source: https://github.com/dknowles2/pydrawise/blob/main/README.md Commands to install the package after navigating to the source directory. ```sh $ cd pydrawise $ python -m pip install . ``` -------------------------------- ### Install Pydrawise via Pip Source: https://github.com/dknowles2/pydrawise/blob/main/README.md Standard installation command for the library. ```sh $ pip install pydrawise ``` -------------------------------- ### Enable Debug Logging Example Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Full example demonstrating how to enable debug logging for the Pydrawise library during client execution. ```python import logging import asyncio from pydrawise import Auth, Hydrawise logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger("pydrawise") async def main(): auth = Auth("user", "pass") client = Hydrawise(auth) # Logs will now include pydrawise debug messages user = await client.get_user() asyncio.run(main()) ``` -------------------------------- ### Authenticate with Auth Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/authentication.md Example of initializing the Auth class and validating credentials. ```python import asyncio from pydrawise import Auth async def setup(): auth = Auth("user@example.com", "password123") is_valid = await auth.check() print(f"Authentication valid: {is_valid}") asyncio.run(setup()) ``` -------------------------------- ### start_zone() Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hydrawise-client.md Starts a zone's run cycle. ```APIDOC ## start_zone(zone, mark_run_as_scheduled=False, custom_run_duration=0) ### Description Starts a zone's run cycle. ### Parameters - **zone** (Zone) - Required - The zone to start - **mark_run_as_scheduled** (bool) - Optional - Mark run as scheduled (affects water tracking) - **custom_run_duration** (int) - Optional - Duration in seconds; 0 uses zone default ### Raises - **MutationError** - If the API returns an error status. ``` -------------------------------- ### start_zone() Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Starts a zone's run cycle. ```APIDOC ## start_zone() ### Description Starts a zone's run cycle. ### Parameters - **zone** (Zone) - Required - The zone to start - **mark_run_as_scheduled** (bool) - Optional - Default: False - Ignored by REST API - **custom_run_duration** (int) - Optional - Default: 0 - Duration in seconds; 0 uses zone default ### Endpoint setzone.php?action=run&relay_id=&period_id=999&custom= ``` -------------------------------- ### Multi-Controller Setup Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/README.md Initialize HybridClient to automatically manage multiple controllers with fallback support. ```python # HybridClient automatically handles multi-controller with fallback auth = HybridAuth(username, password, api_key) client = HybridClient(auth) controllers = await client.get_controllers() for controller in controllers: zones = await client.get_zones(controller) # REST API key may only work for primary controller # HybridClient gracefully degrades for secondary ``` -------------------------------- ### Start all zones Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Starts all zones for a given controller. This is a mutation operation and is not throttled. ```python async def start_all_zones( self, controller: Controller, mark_run_as_scheduled: bool = False, custom_run_duration: int = 0, ) -> None ``` -------------------------------- ### Initialize HybridClient Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/getting-started.md Recommended for production systems, home automation, and multi-controller setups requiring intelligent caching and rate limit management. ```python from pydrawise.auth import HybridAuth from pydrawise.hybrid import HybridClient auth = HybridAuth("email@example.com", "password", "api_key") client = HybridClient(auth) ``` -------------------------------- ### Start a zone Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Starts a specific zone. This is a mutation operation and is not throttled. ```python async def start_zone( self, zone: Zone, mark_run_as_scheduled: bool = False, custom_run_duration: int = 0, ) -> None ``` -------------------------------- ### Use RestClient directly Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Example of initializing the RestClient with RestAuth and fetching controller and zone data. ```python from pydrawise.auth import RestAuth from pydrawise.rest import RestClient async def simple_example(): auth = RestAuth("api_key_here") client = RestClient(auth) controllers = await client.get_controllers() for controller in controllers: zones = await client.get_zones(controller) for zone in zones: print(f"{zone.name}: {zone.status}") ``` -------------------------------- ### start_all_zones() Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Starts all zones attached to a controller. ```APIDOC ## start_all_zones() ### Description Starts all zones attached to a controller. ### Parameters - **controller** (Controller) - Required - The controller whose zones to start - **mark_run_as_scheduled** (bool) - Optional - Default: False - Ignored by REST API - **custom_run_duration** (int) - Optional - Default: 0 - Duration in seconds for all zones ### Endpoint setzone.php?action=runall&controller_id=&period_id=999&custom= ``` -------------------------------- ### Define Program Start Time Application Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/watering-programs.md Specifies which zones are affected by a start time, supporting either all zones or a specific subset. ```python @dataclass class ProgramStartTimeApplication: all: bool = False zones: list[BaseZone] = field(default_factory=list) ``` -------------------------------- ### start_all_zones() Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hydrawise-client.md Starts all zones attached to a controller. ```APIDOC ## start_all_zones(controller, mark_run_as_scheduled=False, custom_run_duration=0) ### Description Starts all zones attached to a controller. ### Parameters - **controller** (Controller) - Required - The controller whose zones to start - **mark_run_as_scheduled** (bool) - Optional - Mark runs as scheduled - **custom_run_duration** (int) - Optional - Duration in seconds for all zones ``` -------------------------------- ### Start All Zones Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Starts all zones attached to a controller for a specified duration. ```python # Start all zones for 10 minutes await client.start_all_zones(controller, custom_run_duration=600) ``` -------------------------------- ### Usage of LegacyHydrawiseAsync Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/legacy-client.md Example of initializing the asynchronous client and fetching controller data. ```python import asyncio from pydrawise.legacy import LegacyHydrawiseAsync async def example(): h = LegacyHydrawiseAsync("api_key") controllers = await h.get_controllers() print(f"Found {len(controllers)} controllers") asyncio.run(example()) ``` -------------------------------- ### Usage of LegacyHydrawise Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/legacy-client.md Example of initializing the synchronous client and accessing controller properties. ```python from pydrawise.legacy import LegacyHydrawise h = LegacyHydrawise("api_key", load_on_init=True) print(f"Controller: {h.name}") print(f"Status: {h.status}") ``` -------------------------------- ### Apply Throttling Strategies Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Examples of configuring aggressive or lenient throttling for the HybridClient. ```python from datetime import timedelta from pydrawise.hybrid import Throttler # Only 1 request per hour aggressive = Throttler( epoch_interval=timedelta(hours=1), tokens_per_epoch=1 ) client = HybridClient(auth, gql_throttle=aggressive) ``` ```python # 10 requests per 10 minutes lenient = Throttler( epoch_interval=timedelta(minutes=10), tokens_per_epoch=10 ) client = HybridClient(auth, gql_throttle=lenient) ``` -------------------------------- ### Install pydrawise via pip Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/getting-started.md Install the library using pip. Requires Python 3.11 or higher. ```bash pip install pydrawise ``` -------------------------------- ### Start all zones Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hydrawise-client.md Starts all zones attached to a controller, optionally setting a duration or scheduling flag. ```python async def start_all_zones( self, controller: Controller, mark_run_as_scheduled: bool = False, custom_run_duration: int = 0, ) -> None ``` ```python # Start all zones for 15 minutes await client.start_all_zones(controller, custom_run_duration=900) ``` -------------------------------- ### Use LegacyHydrawiseAsync Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Example of using the legacy interface to interact with controllers and zones. ```python from pydrawise.legacy import LegacyHydrawiseAsync async def legacy_example(): client = LegacyHydrawiseAsync("api_key_here") controllers = await client.get_controllers() zones = await client.get_zones(controllers[0]) await client.start_zone(zones[0]) ``` -------------------------------- ### Define Program Start Time Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/watering-programs.md Represents the daily start time configuration for a watering program, including specific days and zone applications. ```python @dataclass class ProgramStartTime: id: int = 0 time: time = field(metadata=_time_conversion(), ...) watering_days: list[AdvancedProgramDayPatternEnum] = field(...) application: ProgramStartTimeApplication = field(...) ``` -------------------------------- ### Retrieve Formatted Token Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/authentication.md Example of obtaining the Bearer token string. ```python auth = Auth("user@example.com", "password") token = await auth.token() # Token is something like: "Bearer eyJ0eXAiOiJKV1QiLCJhbGc..." ``` -------------------------------- ### Refresh and Retrieve Token Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/authentication.md Example of ensuring the token is valid before retrieval. ```python await auth.check_token() # Refresh if needed token_str = await auth.token() print(f"Current token: {token_str}") ``` -------------------------------- ### run_zone() Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/legacy-client.md Starts or stops a specific zone or all zones for a set duration. ```APIDOC ## run_zone(minutes: int, zone: int | None = None) ### Description Starts a zone for a specified number of minutes. If `minutes` is 0, the zone is stopped. ### Parameters - **minutes** (int) - Required - Minutes to run (0 to stop). - **zone** (int) - Optional - Zone number to run (None for all). ### Returns - **dict** - Raw API response dictionary. ### Raises - **NotInitializedError** - If no zones are loaded and a zone number is provided. ``` -------------------------------- ### Control Irrigation Zones Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/getting-started.md Demonstrates how to start and stop a specific irrigation zone using the Hydrawise client. ```python async def control_zone(auth): client = Hydrawise(auth) # Get first controller and zone controllers = await client.get_controllers() if not controllers: return zones = await client.get_zones(controllers[0]) if not zones: return zone = zones[0] # Start zone for 10 minutes await client.start_zone(zone, custom_run_duration=600) print(f"Started {zone.name} for 10 minutes") # Stop zone await client.stop_zone(zone) print(f"Stopped {zone.name}") asyncio.run(control_zone(auth)) ``` -------------------------------- ### Interact with Hydrawise controllers Source: https://github.com/dknowles2/pydrawise/blob/main/README.md Demonstrates authenticating with credentials, listing controllers and zones, and starting a specific zone. ```python import asyncio from pydrawise import Auth, Hydrawise async def main(): # Create a Hydrawise object and authenticate with your credentials. h = Hydrawise(Auth("username", "password")) # List the controllers attached to your account. controllers = await h.get_controllers() # List the zones controlled by the first controller. zones = await h.get_zones(controllers[0]) # Start the first zone. await h.start_zone(zones[0]) if __name__ == "__main__": asyncio.run(main()) ``` -------------------------------- ### Start a zone Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hydrawise-client.md Initiates a run cycle for a specific zone, with optional duration and scheduling flags. ```python async def start_zone( self, zone: Zone, mark_run_as_scheduled: bool = False, custom_run_duration: int = 0, ) -> None ``` ```python # Run for default duration await client.start_zone(zone) # Run for 10 minutes (600 seconds) await client.start_zone(zone, custom_run_duration=600) # Run as scheduled (affects water tracking) await client.start_zone(zone, mark_run_as_scheduled=True) ``` -------------------------------- ### Get water use summary Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Retrieves a water use summary for a controller. This is an unthrottled query. ```python async def get_water_use_summary( self, controller: Controller, start: datetime, end: datetime ) -> ControllerWaterUseSummary ``` -------------------------------- ### Start a Zone Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Initiates a run cycle for a specific zone. If custom_run_duration is 0, the zone's default duration is used. ```python # Run for default duration await client.start_zone(zone) # Run for 5 minutes (300 seconds) await client.start_zone(zone, custom_run_duration=300) ``` -------------------------------- ### Handle UnknownError Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/errors.md Example of catching an unexpected error during controller information retrieval. ```python from pydrawise.legacy import LegacyHydrawise from pydrawise import UnknownError try: info = h._get_controller_info() except UnknownError as e: print(f"Unexpected error: {e}") # Check Hydrawise service status or API response format ``` -------------------------------- ### Get watering report Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Retrieves a watering report for a controller. This is an unthrottled query. ```python async def get_watering_report( self, controller: Controller, start: datetime, end: datetime ) -> list[WateringReportEntry] ``` -------------------------------- ### Get Controller Method Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Raises NotImplementedError as the REST API does not support fetching a single controller by ID. Use get_controllers() instead. ```python async def get_controller(self, controller_id: int) -> Controller ``` -------------------------------- ### Configure .env File and HybridClient Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/getting-started.md Loads credentials from a .env file to initialize the HybridClient. ```bash # .env file HYDRAWISE_USERNAME=user@example.com HYDRAWISE_PASSWORD=password HYDRAWISE_API_KEY=rest_api_key ``` ```python import os from dotenv import load_dotenv from pydrawise.auth import HybridAuth from pydrawise.hybrid import HybridClient load_dotenv() auth = HybridAuth( username=os.getenv("HYDRAWISE_USERNAME"), password=os.getenv("HYDRAWISE_PASSWORD"), api_key=os.getenv("HYDRAWISE_API_KEY"), ) client = HybridClient(auth) ``` -------------------------------- ### Get Water Use Summary Method Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Raises NotImplementedError as the REST API does not support water use summaries. Use the GraphQL Hydrawise client instead. ```python async def get_water_use_summary( self, controller: Controller, start: datetime, end: datetime ) -> ControllerWaterUseSummary ``` -------------------------------- ### Get water flow summary Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Retrieves a water flow summary for a specific sensor. This is an unthrottled query. ```python async def get_water_flow_summary( self, controller: Controller, sensor: Sensor, start: datetime, end: datetime ) -> SensorFlowSummary ``` -------------------------------- ### Get Sensors Method Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Raises NotImplementedError as the REST API does not provide sensor information. Use the GraphQL Hydrawise client instead. ```python async def get_sensors(self, controller: Controller) -> list[Sensor] ``` -------------------------------- ### Initialize Client Classes Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Constructors for the primary Hydrawise and Hybrid clients. ```python client = Hydrawise(auth: Auth, app_id: str = DEFAULT_APP_ID) ``` ```python client = RestClient(auth: RestAuth) ``` ```python client = HybridClient( auth: HybridAuth, app_id: str = DEFAULT_APP_ID, gql_client: Hydrawise | None = None, gql_throttle: Throttler | None = None, rest_throttle: Throttler | None = None, ) ``` -------------------------------- ### Perform Authenticated GET Request Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/authentication.md Execute a GET request to a relative API endpoint path and return the JSON response. ```python response = await rest_auth.get("customerdetails.php") print(response) # {"customer_id": 123, "controllers": [...]} ``` -------------------------------- ### Initialize legacy synchronous client Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/module-architecture.md Uses the synchronous requests library for legacy support; note that network calls will block the event loop. ```python from pydrawise.legacy import LegacyHydrawise h = LegacyHydrawise(api_key) # Blocks on network h.update_controller_info() # Synchronous ``` -------------------------------- ### Initialize Auth Classes Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Constructors for different authentication methods supported by the library. ```python auth = Auth(username: str, password: str) ``` ```python auth = RestAuth(api_key: str) ``` ```python auth = HybridAuth(username: str, password: str, api_key: str) ``` -------------------------------- ### Initialize LegacyHydrawise Client Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/README.md Initialize the synchronous client for backwards compatibility with v1 code. ```python from pydrawise.legacy import LegacyHydrawise h = LegacyHydrawise("api_key") h.run_zone(10, zone=1) # 10 minutes on zone 1 ``` -------------------------------- ### Initialize HybridClient Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/README.md Initialize the production-ready client that combines GraphQL and REST APIs with automatic throttling and caching. ```python from pydrawise.auth import HybridAuth from pydrawise.hybrid import HybridClient auth = HybridAuth("email", "password", "api_key") client = HybridClient(auth) ``` -------------------------------- ### Handle Authentication Errors Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/authentication.md Example of catching NotAuthorizedError during credential validation. ```python try: await auth.check() print("Credentials are valid") except NotAuthorizedError as e: print(f"Invalid credentials: {e}") ``` -------------------------------- ### Initialize Hydrawise GraphQL Client Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/getting-started.md Use for full-featured applications requiring sensors, water flow data, and modern async support. ```python from pydrawise import Auth, Hydrawise auth = Auth("email@example.com", "password") client = Hydrawise(auth) ``` -------------------------------- ### Initialize Client via Environment Variables Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/getting-started.md Uses system environment variables to authenticate and initialize the Hydrawise client. ```python import os import asyncio from pydrawise import Auth, Hydrawise async def from_env(): username = os.getenv("HYDRAWISE_USERNAME") password = os.getenv("HYDRAWISE_PASSWORD") if not username or not password: raise ValueError("Missing credentials in environment") auth = Auth(username, password) client = Hydrawise(auth) # Verify connection await auth.check() return client # Usage: # export HYDRAWISE_USERNAME="user@example.com" # export HYDRAWISE_PASSWORD="password" client = asyncio.run(from_env()) ``` -------------------------------- ### Initialize Client from Environment Variables Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Helper function to instantiate the Hydrawise client using credentials stored in environment variables. ```python import os from pydrawise import Auth, Hydrawise async def from_env(): """Initialize client from environment variables.""" auth = Auth( username=os.getenv("HYDRAWISE_USERNAME"), password=os.getenv("HYDRAWISE_PASSWORD"), ) return Hydrawise(auth) ``` -------------------------------- ### Initialize Custom GraphQL Client Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/module-architecture.md Override the default GraphQL client by providing a custom implementation to the HybridClient. ```python client = HybridClient( auth, gql_client=Hydrawise(auth, app_id="my_app") ) ``` -------------------------------- ### Initialize HybridClient Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Constructor signature for the HybridClient class, defining dependencies for authentication and rate limiting. ```python class HybridClient(HydrawiseBase): def __init__( self, auth: HybridAuth, app_id: str = DEFAULT_APP_ID, gql_client: Hydrawise | None = None, gql_throttle: Throttler | None = None, rest_throttle: Throttler | None = None, ) -> None ``` -------------------------------- ### GraphQL Schema Loading Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/module-architecture.md Initializes the DSL schema from the resource file for type-safe GraphQL access. ```python TYPE_SCHEMA = resources.files(__package__).joinpath("hydrawise.graphql").read_text() DSL_SCHEMA = DSLSchema(build_ast_schema(parse(TYPE_SCHEMA))) ``` -------------------------------- ### Monitor Controllers with HybridClient Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Initializes HybridClient with HybridAuth and iterates through controllers to retrieve zone and sensor status. ```python import asyncio from pydrawise.auth import HybridAuth from pydrawise.hybrid import HybridClient async def monitor_controller(): auth = HybridAuth( username="user@example.com", password="password", api_key="rest_api_key" ) client = HybridClient(auth) # Get all controllers controllers = await client.get_controllers(fetch_zones=True) for controller in controllers: print(f"\n{controller.name} ({controller.id})") # Get zones with current status (updated via REST fallback if available) zones = await client.get_zones(controller) for zone in zones: status = "running" if zone.scheduled_runs.current_run else "idle" print(f" Zone {zone.number.value}: {zone.name} ({status})") # Get sensors if not throttled try: sensors = await client.get_sensors(controller) print(f" Sensors: {len(sensors)}") except ThrottledError: print(f" Sensors: throttled (using cache)") asyncio.run(monitor_controller()) ``` -------------------------------- ### Zone Dataclass Definition Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/module-architecture.md Example of a Python dataclass using apischema metadata for serialization. ```python @dataclass class Zone(BaseZone): watering_settings: Union[Advanced, Standard] = field(...) scheduled_runs: ScheduledZoneRuns = field(...) # ... more fields ``` -------------------------------- ### RestAuth.get(path: str, **kwargs) Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/authentication.md Performs an authenticated GET request to the REST API. ```APIDOC ## RestAuth.get(path: str, **kwargs) ### Description Performs an authenticated GET request to the REST API and returns the JSON response. ### Parameters - **path** (str) - Required - API endpoint path (relative) - **kwargs** (dict) - Optional - Additional query parameters ``` -------------------------------- ### Migrate from Legacy Synchronous to Modern Async Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/legacy-client.md Transition from the synchronous LegacyHydrawise client to the asynchronous LegacyHydrawiseAsync client. ```python h = LegacyHydrawise(api_key) h.run_zone(10, 1) ``` ```python import asyncio from pydrawise.legacy import LegacyHydrawiseAsync async def main(): h = LegacyHydrawiseAsync(api_key) controllers = await h.get_controllers() zone = controllers[0].zones[0] await h.start_zone(zone, custom_run_duration=600) asyncio.run(main()) ``` -------------------------------- ### Define StandardProgramPeriodicity dataclass Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/watering-programs.md Configures the frequency and start date for a standard watering program cycle. ```python @dataclass class StandardProgramPeriodicity: period: int = 0 series_start: datetime = field(metadata=DateTime.conversion(), ...) ``` -------------------------------- ### Client Architecture Structures Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/module-architecture.md Class structures and internal components for the different client implementations. ```text Hydrawise ├── _auth: Auth ├── _app_id: str ├── _client(): Creates gql.Client with auth headers ├── _query(): Executes DSL GraphQL queries ├── _mutation(): Executes DSL GraphQL mutations └── Public methods (get_user, get_controllers, etc.) ``` ```text RestClient ├── _auth: RestAuth ├── next_poll: timedelta (from API responses) ├── _get(): Performs authenticated REST calls └── Public methods (get_user, get_controllers, etc.) ``` ```text HybridClient ├── _gql_client: Hydrawise (inner GraphQL client) ├── _auth: HybridAuth ├── _lock: asyncio.Lock ├── _gql_throttle: Throttler (5/30min) ├── _rest_throttle: Throttler (2/1min) ├── Cache: _user, _controllers, _zones dicts ├── _update_zones(): REST API fallback for zone updates └── Public methods with throttling & caching ``` -------------------------------- ### Setting Environment Variables Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/README.md Configure authentication credentials via shell environment variables. ```bash export HYDRAWISE_USERNAME="user@example.com" export HYDRAWISE_PASSWORD="password" export HYDRAWISE_API_KEY="api_key" ``` -------------------------------- ### HybridClient Data Flow (Unthrottled) Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/module-architecture.md Illustrates the logic for zone retrieval in HybridClient when quota is available. ```text client.get_zones(controller) ↓ _gql_throttle.check()? (Do we have quota?) ↓ Yes: Query GraphQL → deserialize → cache ↓ No: _update_zones() → REST API → update cache ↓ Return self._controllers[controller.id].zones ``` -------------------------------- ### Initialize RestClient Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/getting-started.md Use for basic zone control and lightweight operations where REST API compatibility is preferred. ```python from pydrawise.auth import RestAuth from pydrawise.rest import RestClient auth = RestAuth("api_key") client = RestClient(auth) ``` -------------------------------- ### Define StandardProgram dataclass Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/watering-programs.md Represents a standard watering program with fixed start times and day-of-week scheduling. ```python @dataclass class StandardProgram(Program): start_times: list[time] = field(...) time_range: TimeRange = field(default_factory=TimeRange) ignore_rain_sensor: bool = False days_run: list[DaysOfWeekEnum] = field(default_factory=list) standard_program_day_pattern: str = "" periodicity: StandardProgramPeriodicity = field(...) ``` -------------------------------- ### RestAuth.__init__(api_key: str) Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/authentication.md Initializes the RestAuth class with a Hydrawise REST API key. ```APIDOC ## RestAuth.__init__(api_key: str) ### Description Initializes the RestAuth class with a Hydrawise REST API key. ### Parameters - **api_key** (str) - Required - Hydrawise REST API key ``` -------------------------------- ### HybridAuth.__init__(username: str, password: str, api_key: str) Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/authentication.md Initializes the HybridAuth class with credentials for both GraphQL and REST APIs. ```APIDOC ## HybridAuth.__init__(username: str, password: str, api_key: str) ### Description Initializes the HybridAuth class with Hydrawise account username, password, and REST API key. ### Parameters - **username** (str) - Required - Hydrawise account username - **password** (str) - Required - Hydrawise account password - **api_key** (str) - Required - Hydrawise REST API key ``` -------------------------------- ### Zone Control Mutations Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Methods for controlling zone states including start, stop, suspend, and resume operations. ```APIDOC ## Zone Control Methods - **start_zone(zone: Zone, mark_run_as_scheduled: bool = False, custom_run_duration: int = 0)**: Starts a specific zone. - **stop_zone(zone: Zone)**: Stops a specific zone. - **start_all_zones(controller: Controller, mark_run_as_scheduled: bool = False, custom_run_duration: int = 0)**: Starts all zones on a controller. - **stop_all_zones(controller: Controller)**: Stops all zones on a controller. - **suspend_zone(zone: Zone, until: datetime)**: Suspends a specific zone until a given time. - **resume_zone(zone: Zone)**: Resumes a suspended zone. - **suspend_all_zones(controller: Controller, until: datetime)**: Suspends all zones on a controller. - **resume_all_zones(controller: Controller)**: Resumes all zones on a controller. - **delete_zone_suspension(suspension: ZoneSuspension)**: Deletes an existing zone suspension. ``` -------------------------------- ### Initialize RestClient Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Constructor signature for the RestClient class. ```python class RestClient(HydrawiseBase): def __init__(self, auth: RestAuth) -> None ``` -------------------------------- ### Initialize LegacyHydrawiseAsync Constructor Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/legacy-client.md Constructor definition for the asynchronous legacy client. ```python class LegacyHydrawiseAsync(RestClient): def __init__(self, user_token: str) -> None ``` -------------------------------- ### Define Program Time Range Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/watering-programs.md Sets the valid operational window for a program using start and end timestamps. ```python @dataclass @type_name("Unit") class TimeRange: valid_from: datetime = field(metadata=_timestamp_conversion(), ...) valid_to: datetime = field(metadata=_timestamp_conversion(), ...) ``` -------------------------------- ### Set Environment Variables Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Recommended shell commands to export credentials for the Pydrawise client. ```bash export HYDRAWISE_USERNAME="user@example.com" export HYDRAWISE_PASSWORD="password" export HYDRAWISE_API_KEY="rest_api_key" export HYDRAWISE_APP_ID="my_app" # Optional ``` -------------------------------- ### Initialize Hydrawise Client Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hydrawise-client.md Instantiate the client using an Auth object and an optional application ID. ```python import asyncio from pydrawise import Auth, Hydrawise async def example(): auth = Auth("username@example.com", "password") client = Hydrawise(auth, app_id="my_app") user = await client.get_user() print(f"Authenticated as: {user.name}") asyncio.run(example()) ``` -------------------------------- ### Initialize LegacyHydrawise Constructor Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/legacy-client.md Constructor definition for the synchronous legacy client. ```python class LegacyHydrawise: def __init__(self, user_token: str, load_on_init: bool = True) -> None ``` -------------------------------- ### Run or stop a zone Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/legacy-client.md Starts or stops a zone for a specified duration. Raises NotInitializedError if no zones are loaded when a specific zone number is provided. ```python def run_zone(self, minutes: int, zone: int | None = None) -> dict ``` ```python # Run zone 1 for 10 minutes h.run_zone(minutes=10, zone=1) # Run all zones for 15 minutes h.run_zone(minutes=15) # Stop zone 1 h.run_zone(minutes=0, zone=1) # Stop all zones h.run_zone(minutes=0) ``` -------------------------------- ### Get Watering Report Method Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Raises NotImplementedError as the REST API does not support watering reports. Use the GraphQL Hydrawise client instead. ```python async def get_watering_report( self, controller: Controller, start: datetime, end: datetime ) -> list[WateringReportEntry] ``` -------------------------------- ### Hydrawise(auth, app_id) Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Initializes the GraphQL client. ```APIDOC ## Hydrawise(auth, app_id) ### Description Initializes the GraphQL client for interacting with Hydrawise. ### Parameters - **auth** (Auth) - Required - OAuth2 auth handler - **app_id** (str) - Optional - App identifier for API (Default: "pydrawise") ``` -------------------------------- ### Initialize HybridAuth Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/authentication.md Configure HybridAuth with username, password, and API key to support both GraphQL and REST APIs. ```python from pydrawise.auth import HybridAuth from pydrawise.hybrid import HybridClient async def setup(): auth = HybridAuth( username="user@example.com", password="password123", api_key="your_api_key" ) client = HybridClient(auth) user = await client.get_user() print(user) asyncio.run(setup()) ``` -------------------------------- ### Get Zone Method Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Raises NotImplementedError as the REST API does not support fetching a single zone by ID. Use get_zones(controller) instead. ```python async def get_zone(self, zone_id: int) -> Zone ``` -------------------------------- ### Get Water Flow Summary Method Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Raises NotImplementedError as the REST API does not support water flow queries. Use the GraphQL Hydrawise client instead. ```python async def get_water_flow_summary( self, controller: Controller, sensor: Sensor, start: datetime, end: datetime ) -> SensorFlowSummary ``` -------------------------------- ### Perform REST API GET Request Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/legacy-client.md Low-level method for making REST API requests. Automatically includes the API key and raises errors for non-200 status codes. ```python def _get(self, path: str, **kwargs) -> dict ``` -------------------------------- ### Initialize Auth Class Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/authentication.md Constructor definition for the Auth class. ```python class Auth(BaseAuth): def __init__(self, username: str, password: str) -> None ``` -------------------------------- ### Configuring GraphQL Throttling Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Defines the GraphQL throttle token bucket and demonstrates custom configuration during client initialization. ```python _gql_throttle: Throttler ``` ```python client = HybridClient( auth, gql_throttle=Throttler( epoch_interval=timedelta(minutes=60), tokens_per_epoch=10 ) ) ``` -------------------------------- ### RestClient Constructor Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/rest-client.md Initializes the RestClient with a required authentication handler. ```APIDOC ## RestClient.__init__ ### Description Initializes a new instance of the RestClient class using the provided authentication handler. ### Signature `def __init__(self, auth: RestAuth) -> None` ### Parameters - **auth** (RestAuth) - Required - The REST API authentication handler. ``` -------------------------------- ### Handling Multi-Controller REST Fallbacks Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Demonstrates how to safely handle zone updates across multiple controllers where REST API access is limited to the primary controller. ```python async def safe_multi_controller(): controllers = await client.get_controllers() # GraphQL works for all for controller in controllers: try: zones = await client.get_zones(controller) # Works for both primary and secondary via GraphQL # REST fallback only works for primary except NotAuthorizedError: # Secondary controller REST fallback failed # Zone data from GraphQL is still available print(f"REST unavailable for {controller.name}; using GraphQL only") ``` -------------------------------- ### Check monthly watering adjustments Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/watering-programs.md Iterates through monthly adjustment percentages for a standard program and prints non-zero values. ```python program = zone.watering_settings.standard_program_applications[0].standard_program months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] for month, adjustment in zip(months, program.monthly_watering_adjustments): if adjustment != 0: print(f"{month}: {adjustment:+d}%") ``` -------------------------------- ### Initialize Hydrawise for One-Shot Applications Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Use the standard Hydrawise client for single-execution scripts where rate limiting is not a concern. ```python from pydrawise import Auth, Hydrawise # Don't care about rate limits; just fetch once auth = Auth(username, password) client = Hydrawise(auth) ``` -------------------------------- ### Check zone cycle-and-soak settings Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/watering-programs.md Accesses the cycle-and-soak configuration for a specific zone and prints the duration if configured. ```python zone = controllers[0].zones[0] settings = zone.watering_settings if settings.cycle_and_soak_settings: c_and_s = settings.cycle_and_soak_settings print(f"Cycle: {c_and_s.cycle_duration.total_seconds()} seconds") print(f"Soak: {c_and_s.soak_duration.total_seconds()} seconds") else: print("No cycle-and-soak configured") ``` -------------------------------- ### Auth(username, password) Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Initializes the GraphQL authentication handler using Hydrawise account credentials. ```APIDOC ## Auth(username, password) ### Description Initializes the GraphQL authentication handler for the Hydrawise API. ### Parameters - **username** (str) - Required - Hydrawise account email/username - **password** (str) - Required - Hydrawise account password ``` -------------------------------- ### get_controllers(fetch_zones: bool = True, fetch_sensors: bool = True) -> list[Controller] Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Retrieves all controllers associated with the account, with options to include zones and sensors. ```APIDOC ## get_controllers(fetch_zones: bool = True, fetch_sensors: bool = True) -> list[Controller] ### Description Retrieves all controllers. Uses GraphQL for full data fetch and caches controllers by ID. ### Parameters - **fetch_zones** (bool) - Optional - Default: True - Include zones in response - **fetch_sensors** (bool) - Optional - Default: True - Include sensors in response ### Returns - **list[Controller]** (list) - A list of Controller objects. ``` -------------------------------- ### HybridClient Constructor Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Initializes a new HybridClient instance with authentication and optional custom throttlers or GraphQL clients. ```APIDOC ## HybridClient Constructor ### Description Initializes the HybridClient, which manages communication with Hydrawise services using provided authentication credentials. ### Signature `HybridClient(auth: HybridAuth, app_id: str = "pydrawise", gql_client: Hydrawise | None = None, gql_throttle: Throttler | None = None, rest_throttle: Throttler | None = None)` ### Parameters - **auth** (HybridAuth) - Required - Hybrid authentication handler. - **app_id** (str) - Optional - Application ID for GraphQL API (default: "pydrawise"). - **gql_client** (Hydrawise) - Optional - Custom GraphQL client instance. - **gql_throttle** (Throttler) - Optional - Rate limiter for GraphQL requests. - **rest_throttle** (Throttler) - Optional - Rate limiter for REST requests. ### Usage Example ```python from pydrawise.auth import HybridAuth from pydrawise.hybrid import HybridClient auth = HybridAuth( username="user@example.com", password="password", api_key="rest_api_key" ) client = HybridClient(auth) ``` ``` -------------------------------- ### HybridClient(auth, app_id, gql_client, gql_throttle, rest_throttle) Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Initializes the hybrid client for both GraphQL and REST API interactions. ```APIDOC ## HybridClient(auth, app_id, gql_client, gql_throttle, rest_throttle) ### Description Initializes a client that manages both GraphQL and REST API interactions with optional custom throttling. ### Parameters - **auth** (HybridAuth) - Required - Combined auth handler - **app_id** (str) - Optional - GraphQL app ID (Default: "pydrawise") - **gql_client** (Hydrawise) - Optional - Custom GraphQL client - **gql_throttle** (Throttler) - Optional - Custom GQL throttler - **rest_throttle** (Throttler) - Optional - Custom REST throttler ``` -------------------------------- ### Manage Multiple Controllers Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/getting-started.md Iterates through all available controllers to retrieve zones and sensors. Uses HybridClient to handle multi-controller environments. ```python async def multi_controller(auth): client = HybridClient(auth) # Use hybrid for multi-controller # Fetch all controllers controllers = await client.get_controllers() for controller in controllers: print(f"\n{controller.name}") zones = await client.get_zones(controller) for zone in zones: print(f" {zone.name}") try: sensors = await client.get_sensors(controller) print(f" Sensors: {len(sensors)}") except ThrottledError: print(f" Sensors: throttled") asyncio.run(multi_controller(auth)) ``` -------------------------------- ### Initialize RestAuth Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/authentication.md Instantiate the RestAuth class using a valid Hydrawise REST API key. ```python from pydrawise.auth import RestAuth auth = RestAuth("your_api_key_here") ``` -------------------------------- ### Configure Throttler Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Initializes a Throttler instance to control request frequency. ```python throttle = Throttler( epoch_interval: timedelta, tokens_per_epoch: int = 1, tokens: int = 0, last_epoch: datetime = datetime.min, ) ``` -------------------------------- ### HybridClient Data Flow (Throttled) Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/module-architecture.md Illustrates the logic for zone retrieval in HybridClient when quota is exhausted. ```text client.get_zone(zone_id) # Different method; uses @throttle decorator ↓ @throttle check quota ↓ No quota, but cached? Return cached ↓ No quota, no cache? Raise ThrottledError ↓ Caller may retry, use cache, or skip ``` -------------------------------- ### Define CycleAndSoakSettings Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/watering-programs.md Configuration for cycle-and-soak watering strategies, requiring duration conversions for cycle and soak times. ```python @dataclass class CycleAndSoakSettings: cycle_duration: timedelta = field(metadata=_duration_conversion("minutes"), ...) soak_duration: timedelta = field(metadata=_duration_conversion("minutes"), ...) ``` -------------------------------- ### Implement Modern GraphQL Client Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/legacy-client.md Use the recommended GraphQL-based Hydrawise client for full feature support, including sensors and reports. ```python import asyncio from pydrawise import Auth, Hydrawise async def main(): auth = Auth("email", "password") client = Hydrawise(auth) user = await client.get_user() sensors = await client.get_sensors(user.controllers[0]) # Additional features: sensors, water usage, detailed reports asyncio.run(main()) ``` -------------------------------- ### Implement Custom Authentication Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/module-architecture.md Create a custom authentication provider by inheriting from the BaseAuth interface and implementing the check method. ```python class CustomAuth(BaseAuth): async def check(self) -> bool: # Custom validation pass ``` -------------------------------- ### Define ControllerFirmware dataclass Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/types.md Represents a specific firmware version and its type. ```python @dataclass class ControllerFirmware: type: str = "" version: str = "" ``` -------------------------------- ### Fetch Controller Information Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/legacy-client.md Retrieves controller details from the customerdetails.php endpoint. ```python def _get_controller_info(self) -> dict ``` -------------------------------- ### Authentication Flow Diagrams Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/module-architecture.md Visual representations of the authentication processes for GraphQL, REST, and Hybrid modes. ```text User → Auth("email", "password") ↓ _fetch_token_locked(refresh=False) ↓ POST TOKEN_URL with password grant ↓ Token stored, auto-refreshes when < 5 min expires ↓ Client uses token() to get "Bearer " ``` ```text User → RestAuth("api_key") ↓ API key stored directly ↓ Every request includes api_key parameter ↓ No token refresh needed ``` ```text User → HybridAuth("email", "password", "api_key") ↓ Inherits from both Auth and RestAuth ↓ Uses GraphQL for queries, REST for fallback polling ``` -------------------------------- ### Configure Library Logging Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/configuration.md Adjust logging levels for the main library and the underlying GraphQL transport. ```python import logging # Pydrawise logger logger = logging.getLogger("pydrawise") logger.setLevel(logging.DEBUG) # GraphQL library is quiet by default gql_logger = logging.getLogger("gql.transport.aiohttp") gql_logger.setLevel(logging.WARNING) ``` -------------------------------- ### Authenticate with Hydrawise Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/getting-started.md Initializes the Auth object and verifies credentials against the Hydrawise API. ```python import asyncio from pydrawise import Auth async def main(): # Verify credentials auth = Auth("user@example.com", "password") if await auth.check(): print("Authenticated!") return auth auth = asyncio.run(main()) ``` -------------------------------- ### Retrieve Controllers Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/hybrid-client.md Method signature and usage for fetching all controllers with optional zones and sensors. ```python async def get_controllers( self, fetch_zones: bool = True, fetch_sensors: bool = True ) -> list[Controller] ``` ```python controllers = await client.get_controllers() print(f"Found {len(controllers)} controller(s)") for controller in controllers: print(f" {controller.name}: {len(controller.zones)} zones, online={controller.online}") ``` -------------------------------- ### Library Usage Import Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/module-architecture.md Standard import pattern for accessing primary library components. ```python from pydrawise import Auth, Hydrawise, Controller, Zone, Error ``` -------------------------------- ### Handling NotInitializedError Source: https://github.com/dknowles2/pydrawise/blob/main/_autodocs/errors.md Catch errors when attempting to use the legacy client before controller information is loaded. ```python from pydrawise.legacy import LegacyHydrawise from pydrawise import NotInitializedError h = LegacyHydrawise(api_key, load_on_init=False) try: h.suspend_zone(days=1, zone=1) except NotInitializedError: print("Must call update_controller_info() first") h.update_controller_info() h.suspend_zone(days=1, zone=1) ```