Water Meter

CPAU Water Meter Implementation

This module provides the CpauWaterMeter class for retrieving water meter usage data from paloalto.watersmart.com.

class cpau.water_meter.CpauWaterMeter(username, password, headless=True, cache_dir=None)[source]

Bases: object

Represents a CPAU water meter and provides methods to retrieve usage data.

Supports four interval types: - billing: Billing period data (CPAU’s billing periods, roughly monthly) - monthly: Calendar month aggregation (sum of daily data by month) - daily: Daily aggregated usage - hourly: Hourly usage data

Note: Water meter data comes from paloalto.watersmart.com and requires browser automation (Playwright) for SAML/SSO authentication.

Example

>>> meter = CpauWaterMeter(username='user', password='pass')
>>> usage = meter.get_usage('daily', start_date, end_date)
>>> for record in usage:
...     print(f"{record.date}: {record.import_kwh} gallons")
__init__(username, password, headless=True, cache_dir=None)[source]

Initialize water meter with CPAU credentials.

Parameters:
  • username (str) – CPAU username

  • password (str) – CPAU password

  • headless (bool) – Run browser in headless mode (default: True)

  • cache_dir (Optional[str]) – Directory for caching authentication cookies (default: ~/.cpau) Set to None to disable caching.

Note

First API call will trigger Playwright authentication (~15 seconds). Subsequent calls within 10 minutes reuse cached cookies (<1 second).

get_available_intervals()[source]

Get list of supported interval types for water meters.

Return type:

list[str]

Returns:

[‘billing’, ‘monthly’, ‘daily’, ‘hourly’]

get_usage(interval, start_date, end_date=None)[source]

Retrieve water usage data for the specified interval and date range.

Parameters:
  • interval (str) – One of ‘billing’, ‘monthly’, ‘daily’, ‘hourly’

  • start_date (date) – Start date (inclusive)

  • end_date (Optional[date]) – End date (inclusive). If None, defaults to today.

Return type:

list[UsageRecord]

Returns:

List of UsageRecord objects sorted by date

Raises:

ValueError – If interval is invalid or date range is invalid

Notes

  • First call authenticates via Playwright (~15s)

  • Subsequent calls reuse session (~1s each)

  • import_kwh field contains gallons (not kWh)

  • export_kwh is always 0 for water

  • net_kwh equals import_kwh

get_billing_usage(start_date, end_date=None)[source]

Convenience method for billing period data.

Return type:

list[UsageRecord]

get_monthly_usage(start_date, end_date=None)[source]

Convenience method for monthly aggregated data.

Return type:

list[UsageRecord]

get_daily_usage(start_date, end_date=None)[source]

Convenience method for daily data.

Return type:

list[UsageRecord]

get_hourly_usage(start_date, end_date=None)[source]

Convenience method for hourly data.

Return type:

list[UsageRecord]

get_availability_window(interval)[source]

Find the earliest and latest dates for which data is available.

Parameters:

interval (str) – One of ‘billing’, ‘monthly’, ‘daily’, ‘hourly’

Return type:

tuple[Optional[date], Optional[date]]

Returns:

Tuple of (earliest_date, latest_date) or (None, None) if no data found

Notes

  • For water meter, all intervals make a single API call that returns all available data

  • For ‘monthly’: Returns the daily data availability window (since monthly aggregates daily)

  • Total execution time: typically 1-2 seconds (after initial authentication)

Raises:

ValueError – If interval is invalid

__repr__()[source]

String representation.

Return type:

str

CpauWaterMeter

class cpau.water_meter.CpauWaterMeter(username, password, headless=True, cache_dir=None)[source]

Bases: object

Represents a CPAU water meter and provides methods to retrieve usage data.

Supports four interval types: - billing: Billing period data (CPAU’s billing periods, roughly monthly) - monthly: Calendar month aggregation (sum of daily data by month) - daily: Daily aggregated usage - hourly: Hourly usage data

Note: Water meter data comes from paloalto.watersmart.com and requires browser automation (Playwright) for SAML/SSO authentication.

Example

>>> meter = CpauWaterMeter(username='user', password='pass')
>>> usage = meter.get_usage('daily', start_date, end_date)
>>> for record in usage:
...     print(f"{record.date}: {record.import_kwh} gallons")

Supported Intervals

  • billing - Billing period data

  • monthly - Monthly aggregated usage

  • daily - Daily usage data

  • hourly - Hourly usage data

Authentication

Water meter authentication uses Playwright for SAML/SSO flow:

  • First authentication: ~15 seconds (Playwright/SAML)

  • Cached authentication: ~1 second (10-minute cache window)

  • Cache location: ~/.cpau/watersmart_cookies.json (default)

Example

from cpau import CpauWaterMeter
from datetime import date

# Create water meter (handles SAML/SSO authentication automatically)
meter = CpauWaterMeter(
    username='user@example.com',
    password='password',
    cache_dir='~/.cpau'  # Optional: cache cookies for fast re-auth
)

# Get usage data
records = meter.get_usage(
    interval='daily',
    start_date=date(2024, 12, 1),
    end_date=date(2024, 12, 31)
)

# Water usage is in the import_kwh field (gallons, not kWh)
for record in records:
    print(f"{record.date}: {record.import_kwh} gallons")

# Check data availability
earliest, latest = meter.get_availability_window('daily')
print(f"Water data available from {earliest} to {latest}")

Note

Water meter data is stored in the import_kwh field of UsageRecord, but contains gallons instead of kWh. The export_kwh and net_kwh fields are always 0.0 for water meters.

__init__(username, password, headless=True, cache_dir=None)[source]

Initialize water meter with CPAU credentials.

Parameters:
  • username (str) – CPAU username

  • password (str) – CPAU password

  • headless (bool) – Run browser in headless mode (default: True)

  • cache_dir (Optional[str]) – Directory for caching authentication cookies (default: ~/.cpau) Set to None to disable caching.

Note

First API call will trigger Playwright authentication (~15 seconds). Subsequent calls within 10 minutes reuse cached cookies (<1 second).

get_available_intervals()[source]

Get list of supported interval types for water meters.

Return type:

list[str]

Returns:

[‘billing’, ‘monthly’, ‘daily’, ‘hourly’]

get_usage(interval, start_date, end_date=None)[source]

Retrieve water usage data for the specified interval and date range.

Parameters:
  • interval (str) – One of ‘billing’, ‘monthly’, ‘daily’, ‘hourly’

  • start_date (date) – Start date (inclusive)

  • end_date (Optional[date]) – End date (inclusive). If None, defaults to today.

Return type:

list[UsageRecord]

Returns:

List of UsageRecord objects sorted by date

Raises:

ValueError – If interval is invalid or date range is invalid

Notes

  • First call authenticates via Playwright (~15s)

  • Subsequent calls reuse session (~1s each)

  • import_kwh field contains gallons (not kWh)

  • export_kwh is always 0 for water

  • net_kwh equals import_kwh

get_billing_usage(start_date, end_date=None)[source]

Convenience method for billing period data.

Return type:

list[UsageRecord]

get_monthly_usage(start_date, end_date=None)[source]

Convenience method for monthly aggregated data.

Return type:

list[UsageRecord]

get_daily_usage(start_date, end_date=None)[source]

Convenience method for daily data.

Return type:

list[UsageRecord]

get_hourly_usage(start_date, end_date=None)[source]

Convenience method for hourly data.

Return type:

list[UsageRecord]

get_availability_window(interval)[source]

Find the earliest and latest dates for which data is available.

Parameters:

interval (str) – One of ‘billing’, ‘monthly’, ‘daily’, ‘hourly’

Return type:

tuple[Optional[date], Optional[date]]

Returns:

Tuple of (earliest_date, latest_date) or (None, None) if no data found

Notes

  • For water meter, all intervals make a single API call that returns all available data

  • For ‘monthly’: Returns the daily data availability window (since monthly aggregates daily)

  • Total execution time: typically 1-2 seconds (after initial authentication)

Raises:

ValueError – If interval is invalid

__repr__()[source]

String representation.

Return type:

str

WatersmartSessionManager

Watersmart.com session manager with automatic cookie handling.

This module provides a session manager that: 1. Authenticates using Playwright (headless) 2. Extracts and manages session cookies 3. Provides requests.Session for API calls 4. Automatically re-authenticates on 401 errors

class cpau.watersmart_session.WatersmartSessionManager(username, password, headless=True, cache_dir=None)[source]

Bases: object

Manages authenticated sessions for paloalto.watersmart.com.

Handles SAML/SSO authentication via Playwright and provides a requests.Session with valid cookies for API access.

Example

>>> manager = WatersmartSessionManager('username', 'password')
>>> session = manager.get_session()
>>> response = session.get('https://paloalto.watersmart.com/index.php/rest/v1/Chart/RealTimeChart')
>>> data = response.json()
__init__(username, password, headless=True, cache_dir=None)[source]

Initialize session manager.

Parameters:
  • username (str) – CPAU username

  • password (str) – CPAU password

  • headless (bool) – Run Playwright in headless mode (default: True)

  • cache_dir (Optional[str]) – Directory for caching cookies (default: ~/.cpau)

authenticate()[source]

Authenticate with watersmart.com using Playwright.

Performs SAML/SSO login flow and extracts session cookies.

Raises:

Exception – If authentication fails

Return type:

None

is_authenticated()[source]

Check if we have valid authentication cookies.

Returns:

True if authenticated, False otherwise

Return type:

bool

get_session(force_refresh=False)[source]

Get a requests.Session with authenticated cookies.

Parameters:

force_refresh (bool) – Force re-authentication even if already authenticated

Returns:

Session with valid cookies

Return type:

requests.Session

Raises:

Exception – If authentication fails

get_authentication_age()[source]

Get time since last authentication.

Returns:

Time since authentication, or None if not authenticated

Return type:

timedelta

class cpau.watersmart_session.WatersmartSessionManager(username, password, headless=True, cache_dir=None)[source]

Bases: object

Manages authenticated sessions for paloalto.watersmart.com.

Handles SAML/SSO authentication via Playwright and provides a requests.Session with valid cookies for API access.

Example

>>> manager = WatersmartSessionManager('username', 'password')
>>> session = manager.get_session()
>>> response = session.get('https://paloalto.watersmart.com/index.php/rest/v1/Chart/RealTimeChart')
>>> data = response.json()

Low-level session manager for WaterSmart portal authentication. Most users should use CpauWaterMeter instead.

__init__(username, password, headless=True, cache_dir=None)[source]

Initialize session manager.

Parameters:
  • username (str) – CPAU username

  • password (str) – CPAU password

  • headless (bool) – Run Playwright in headless mode (default: True)

  • cache_dir (Optional[str]) – Directory for caching cookies (default: ~/.cpau)

authenticate()[source]

Authenticate with watersmart.com using Playwright.

Performs SAML/SSO login flow and extracts session cookies.

Raises:

Exception – If authentication fails

Return type:

None

is_authenticated()[source]

Check if we have valid authentication cookies.

Returns:

True if authenticated, False otherwise

Return type:

bool

get_session(force_refresh=False)[source]

Get a requests.Session with authenticated cookies.

Parameters:

force_refresh (bool) – Force re-authentication even if already authenticated

Returns:

Session with valid cookies

Return type:

requests.Session

Raises:

Exception – If authentication fails

get_authentication_age()[source]

Get time since last authentication.

Returns:

Time since authentication, or None if not authenticated

Return type:

timedelta