srne-mqtt/srnemqtt/solar_types.py

122 lines
4.2 KiB
Python

# -*- 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)
def __str__(self):
return str(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"),
]