# -*- coding: utf-8 -*- import struct from enum import Enum, unique from typing import Callable, Optional @unique class DataName(str, Enum): BATTERY_CHARGE = "battery_charge" BATTERY_VOLTAGE = "battery_voltage" BATTERY_CURRENT = "battery_current" INTERNAL_TEMPERATURE = "internal_temperature" BATTERY_TEMPERATURE = "battery_temperature" LOAD_VOLTAGE = "load_voltage" LOAD_CURRENT = "load_current" LOAD_POWER = "load_power" PANEL_VOLTAGE = "panel_voltage" PANEL_CURRENT = "panel_current" PANEL_POWER = "panel_power" LOAD_ENABLED = "load_enabled" BATTERY_VOLTAGE_MIN = "battery_voltage_min" BATTERY_VOLTAGE_MAX = "battery_voltage_max" CHARGE_MAX_CURRENT = "charge_max_current" _DISCHARGE_MAX_CURRENT = "_discharge_max_current?" CHARGE_MAX_POWER = "charge_max_power" DISCHARGE_MAX_POWER = "discharge_max_power" CHARGE_AMP_HOUR = "charge_amp_hour" DISCHARGE_AMP_HOUR = "discharge_amp_hour" PRODUCTION_ENERGY = "production_energy" CONSUMPTION_ENERGY = "consumption_energy" RUN_DAYS = "run_days" DISCHARGE_COUNT = "discharge_count" FULL_CHARGE_COUNT = "full_charge_count" TOTAL_CHARGE_AMP_HOURS = "total_charge_amp_hours" TOTAL_DISCHARGE_AMP_HOURS = "total_discharge_amp_hours" TOTAL_PRODUCTION_ENERGY = "total_production_energy" TOTAL_CONSUMPTION_ENERGY = "total_consumption_energy" CALCULATED_BATTERY_POWER = "calculated_battery_power" CALCULATED_PANEL_POWER = "calculated_panel_power" CALCULATED_LOAD_POWER = "calculated_load_power" def __repr__(self): return repr(self.value) class DataItem: name: DataName st_format: str unit: Optional[str] transformation: Optional[Callable] def __init__( self, name: DataName, st_format: str, unit: Optional[str] = None, transform: Optional[Callable] = None, ): self.name = name self.st_format = st_format self.unit = unit self.transformation = transform if self.st_format[0] not in "@=<>!": self.st_format = "!" + self.st_format @property def st_size(self) -> int: return struct.calcsize(self.st_format) def transform(self, data): if self.transformation is None: return data return self.transformation(data) def parse_temperature(bin): if bin & 0x80: return (bin & 0x7F) * -1 return bin & 0x7F DATA_BATTERY_STATE = [ DataItem(DataName.BATTERY_CHARGE, "H", "%"), DataItem(DataName.BATTERY_VOLTAGE, "H", "V", lambda n: n / 10), DataItem(DataName.BATTERY_CURRENT, "H", "A", lambda n: n / 100), DataItem(DataName.INTERNAL_TEMPERATURE, "B", "°C", parse_temperature), DataItem(DataName.BATTERY_TEMPERATURE, "B", "°C", parse_temperature), DataItem(DataName.LOAD_VOLTAGE, "H", "V", lambda n: n / 10), DataItem(DataName.LOAD_CURRENT, "H", "A", lambda n: n / 100), DataItem(DataName.LOAD_POWER, "H", "W"), DataItem(DataName.PANEL_VOLTAGE, "H", "V", lambda n: n / 10), DataItem(DataName.PANEL_CURRENT, "H", "A", lambda n: n / 100), DataItem(DataName.PANEL_POWER, "H", "W"), DataItem(DataName.LOAD_ENABLED, "x?", transform=bool), ] HISTORICAL_DATA = [ DataItem(DataName.BATTERY_VOLTAGE_MIN, "H", "V", lambda n: n / 10), DataItem(DataName.BATTERY_VOLTAGE_MAX, "H", "V", lambda n: n / 10), DataItem(DataName.CHARGE_MAX_CURRENT, "H", "A", lambda n: n / 100), DataItem(DataName._DISCHARGE_MAX_CURRENT, "H", "A", lambda n: n / 100), DataItem(DataName.CHARGE_MAX_POWER, "H", "W"), DataItem(DataName.DISCHARGE_MAX_POWER, "H", "W"), DataItem(DataName.CHARGE_AMP_HOUR, "H", "Ah"), DataItem(DataName.DISCHARGE_AMP_HOUR, "H", "Ah"), DataItem(DataName.PRODUCTION_ENERGY, "H", "Wh"), DataItem(DataName.CONSUMPTION_ENERGY, "H", "Wh"), DataItem(DataName.RUN_DAYS, "H"), DataItem(DataName.DISCHARGE_COUNT, "H"), DataItem(DataName.FULL_CHARGE_COUNT, "H"), DataItem(DataName.TOTAL_CHARGE_AMP_HOURS, "L", "Ah"), DataItem(DataName.TOTAL_DISCHARGE_AMP_HOURS, "L", "Ah"), DataItem(DataName.TOTAL_PRODUCTION_ENERGY, "L", "Wh"), DataItem(DataName.TOTAL_CONSUMPTION_ENERGY, "L", "Wh"), ]