"""
CPAU Meter Base Classes
This module defines the abstract base class for all meter types and the
UsageRecord dataclass for representing usage data.
"""
from abc import ABC, abstractmethod
from dataclasses import dataclass
from datetime import datetime
from typing import Optional, TYPE_CHECKING
if TYPE_CHECKING:
from .session import CpauApiSession
[docs]
@dataclass
class UsageRecord:
"""
Represents a single usage data point.
Attributes:
date: Date (or datetime for hourly/15min) of the reading
import_kwh: Energy imported from grid (consumption)
export_kwh: Energy exported to grid (solar generation)
net_kwh: Net energy (import - export)
billing_period_start: Optional start date of billing period (billing interval only)
billing_period_end: Optional end date of billing period (billing interval only)
billing_period_length: Optional length of billing period in days (billing interval only)
"""
date: datetime
import_kwh: float
export_kwh: float
net_kwh: float
billing_period_start: Optional[str] = None
billing_period_end: Optional[str] = None
billing_period_length: Optional[int] = None
class CpauMeter(ABC):
"""
Abstract base class for CPAU meters.
This class defines the common interface for all meter types and should
not be instantiated directly. Use CpauElectricMeter or future meter
subclasses instead.
"""
def __init__(self, session: 'CpauApiSession', meter_info: dict):
"""
Initialize a meter object.
Args:
session: Authenticated CpauApiSession
meter_info: Dictionary containing meter details from API
Note: This should only be called by CpauApiSession factory methods,
not directly by library consumers.
"""
self._session = session
self._meter_info = meter_info
@property
def meter_number(self) -> str:
"""Get the meter number/identifier."""
return self._meter_info.get('MeterNumber', '')
@property
def meter_type(self) -> str:
"""Get the meter type ('E' for electric, 'W' for water)."""
return self._meter_info.get('MeterType', '')
@property
def address(self) -> str:
"""Get the service address for this meter."""
return self._meter_info.get('Address', '')
@property
def status(self) -> int:
"""Get the meter status (1 = active)."""
return self._meter_info.get('Status', 0)
@abstractmethod
def get_available_intervals(self) -> list[str]:
"""
Get list of supported interval types for this meter.
Returns:
List of interval type strings (e.g., ['monthly', 'daily', 'hourly', '15min'])
"""
pass
def __repr__(self) -> str:
"""String representation of the meter."""
return f"{self.__class__.__name__}(meter_number='{self.meter_number}', address='{self.address}')"