"""Model for the Envoy tariff data.""" from __future__ import annotations from dataclasses import dataclass from enum import StrEnum from typing import Any class EnvoyStorageMode(StrEnum): BACKUP = "backup" SELF_CONSUMPTION = "self-consumption" SAVINGS = "economy" LEGACY_SAVINGS = "savings-mode" @dataclass class EnvoyTariff: """Model for the Envoy tariff data.""" currency: dict[str, Any] logger: str | None date: str | None storage_settings: EnvoyStorageSettings | None single_rate: dict[str, Any] seasons: list[Any] seasons_sell: list[Any] | None @classmethod def from_api(cls, data: dict[str, Any]) -> EnvoyTariff: """Initialize from the API.""" return cls( currency=data["currency"], logger=data.get("logger"), date=data.get("date"), storage_settings=( EnvoyStorageSettings.from_api(data["storage_settings"]) if data.get("storage_settings") else None ), single_rate=data["single_rate"], seasons=data["seasons"], seasons_sell=data.get("seasons_sell"), ) def to_api(self) -> dict[str, Any]: """Convert to API format.""" retval = { "currency": self.currency, "single_rate": self.single_rate, "seasons": self.seasons, } if self.logger: retval["logger"] = self.logger if self.date: retval["date"] = self.date if self.seasons_sell: retval["seasons_sell"] = self.seasons_sell if self.storage_settings: retval["storage_settings"] = self.storage_settings.to_api() return retval @dataclass class EnvoyStorageSettings: """Model for the Envoy storage settings.""" mode: EnvoyStorageMode | None operation_mode_sub_type: str reserved_soc: float very_low_soc: int charge_from_grid: bool date: str | None opt_schedules: bool | None @classmethod def from_api(cls, data: dict[str, Any]) -> EnvoyStorageSettings: """Initialize from the API.""" return cls( # It appears a `mode` value of `economy` and `savings-mode` is interchangeable # However, the Enlighten app is using the `economy` value, so we will convert # `savings-mode` to `economy` # some fw return None in storage_settings["data"] mode=( EnvoyStorageMode.SAVINGS if data["mode"] == EnvoyStorageMode.LEGACY_SAVINGS.value else EnvoyStorageMode(data["mode"]) if data.get("mode") else None ), operation_mode_sub_type=data["operation_mode_sub_type"], reserved_soc=data["reserved_soc"], very_low_soc=data["very_low_soc"], charge_from_grid=data["charge_from_grid"], # Some firmware versions don't return date date=data.get("date"), # opt_schedules was added in 8.2.42xx opt_schedules=data.get("opt_schedules"), ) def to_api(self) -> dict[str, Any]: """Convert to API format.""" retval = { "mode": self.mode.value if self.mode else None, "operation_mode_sub_type": self.operation_mode_sub_type, "reserved_soc": self.reserved_soc, "very_low_soc": self.very_low_soc, "charge_from_grid": self.charge_from_grid, } if self.date is not None: retval["date"] = self.date # opt_schedules was added in 8.2.42xx if self.opt_schedules is not None: retval["opt_schedules"] = self.opt_schedules return retval