power-compare/app/config.py
dlawler489 84c4922bbc Initial commit: solar usage vs AER plan comparison app
FastAPI app that pulls interval usage from Sungrow iSolarCloud (OAuth2),
caches AER Consumer Data Right electricity plan data, and compares actual
metered usage against every available plan to estimate real annual cost
(TOU, tiered feed-in, and flat tariffs).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 11:07:01 +10:00

55 lines
2.2 KiB
Python

from pathlib import Path
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
# Storage
db_path: str = "power_compare.db"
# iSolarCloud. "v1" = plain username/password login app; "oauth2" = a
# separate app type using the browser authorization-code flow. See
# SETUP.md -- these are two distinct developer-portal app registrations
# with different credentials, not two ways of using the same one.
isolarcloud_auth_mode: str = "v1" # "v1" | "oauth2"
isolarcloud_app_key: str = "" # "Appkey" from the developer portal
isolarcloud_app_secret: str = "" # "Secret key" / x-access-key from the developer portal
isolarcloud_region: str = "australia" # australia | europe | china | international
isolarcloud_plant_id: str = ""
# -- v1 auth mode only --
isolarcloud_username: str = "" # your regular iSolarCloud account (email/username)
isolarcloud_password: str = ""
# PEM-formatted RSA public key from the developer portal (Settings ->
# Open API), if your application was issued one. Some V1-login apps
# require the password to be RSA-encrypted before it's sent; when this
# is blank, the password is sent as plain text over HTTPS instead.
isolarcloud_rsa_public_key: str = ""
# -- oauth2 auth mode only --
isolarcloud_oauth_app_id: str = "" # "applicationId" from the developer portal
isolarcloud_oauth_redirect_uri: str = "https://localhost:8000/isolarcloud/callback"
# Set to true until real credentials are configured; the scheduler then
# polls app.isolarcloud.mock_client instead of the real API.
use_mock_isolarcloud: bool = True
# Household / AER plan scoping -- must match a substring of the
# distributor name AER plan data uses (e.g. "Energex" or "Ergon").
distributor: str = "Energex"
postcode: str = ""
# Scheduler cadence
isolarcloud_poll_interval_minutes: int = 10
aer_refresh_interval_hours: int = 24
aer_base_url: str = "https://cdr.energymadeeasy.gov.au"
@property
def db_url(self) -> str:
return f"sqlite:///{Path(self.db_path).resolve()}"
settings = Settings()