Project skeleton
This commit is contained in:
114
custom_components/pv_microinverter/units.py
Normal file
114
custom_components/pv_microinverter/units.py
Normal file
@@ -0,0 +1,114 @@
|
||||
from typing import Self
|
||||
|
||||
# SI prefix multipliers
|
||||
SI_PREFIXES = {
|
||||
"Y": 1e24,
|
||||
"Z": 1e21,
|
||||
"E": 1e18,
|
||||
"P": 1e15,
|
||||
"T": 1e12,
|
||||
"G": 1e9,
|
||||
"M": 1e6,
|
||||
"k": 1e3,
|
||||
"h": 1e2,
|
||||
"da": 1e1,
|
||||
"d": 1e-1,
|
||||
"c": 1e-2,
|
||||
"m": 1e-3,
|
||||
"µ": 1e-6,
|
||||
"u": 1e-6,
|
||||
"n": 1e-9,
|
||||
"p": 1e-12,
|
||||
"f": 1e-15,
|
||||
"a": 1e-18,
|
||||
"z": 1e-21,
|
||||
"y": 1e-24,
|
||||
}
|
||||
|
||||
|
||||
def _get_unit_symbol(unit_val: str) -> str:
|
||||
"""Extract the unit symbol from a unit value string."""
|
||||
# Assuming the unit value is in the format "value unit"
|
||||
return unit_val.strip().split(" ")[-1]
|
||||
|
||||
|
||||
class SIUnit:
|
||||
"""SI Units with automatic unit conversion."""
|
||||
|
||||
def __init__(self, name: str, quantity: str, symbol: str, factor: float):
|
||||
self.name = name
|
||||
self.quantity = quantity
|
||||
self.symbol = symbol
|
||||
self.factor = factor
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.symbol})"
|
||||
|
||||
def __repr__(self):
|
||||
return f"SIUnit(name={self.name}, symbol={self.symbol}, factor={self.factor})"
|
||||
|
||||
@classmethod
|
||||
def parse(cls, unit_str: str) -> Self:
|
||||
"""
|
||||
Return an SIUnit by parsing the given unit string, supporting SI prefixes.
|
||||
"""
|
||||
# If the unit is registered directly, return it.
|
||||
if unit_str in BASE_UNITS:
|
||||
return BASE_UNITS[unit_str]
|
||||
# Otherwise, check for a valid prefix.
|
||||
for prefix in sorted(SI_PREFIXES, key=len, reverse=True):
|
||||
if unit_str.startswith(prefix):
|
||||
base_symbol = unit_str[len(prefix) :]
|
||||
if base_symbol in BASE_UNITS:
|
||||
base_unit = BASE_UNITS[base_symbol]
|
||||
multiplier = SI_PREFIXES[prefix]
|
||||
return SIUnit(
|
||||
f"{prefix}{base_unit.name}",
|
||||
base_unit.quantity,
|
||||
f"{prefix}{base_unit.symbol}",
|
||||
base_unit.factor * multiplier,
|
||||
)
|
||||
raise ValueError(f"Unknown unit: {unit_str}")
|
||||
|
||||
|
||||
class Dimension:
|
||||
"""Class to represent a dimension with a unit."""
|
||||
|
||||
def __init__(self, value: float, unit: SIUnit):
|
||||
self.value = value
|
||||
self.unit = unit
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.value} {self.unit.symbol}"
|
||||
|
||||
def to_base_unit(self) -> float:
|
||||
"""Convert the dimension value to its base unit."""
|
||||
return float(self.value) * self.unit.factor
|
||||
|
||||
def __repr__(self):
|
||||
return f"Dimension(value={self.value}, unit={self.unit})"
|
||||
|
||||
@classmethod
|
||||
def parse(cls, unit_val: str) -> Self:
|
||||
"""
|
||||
Parse a unit value string into a Dimension object, supporting SI unit prefixes.
|
||||
Expects the format "value unit", e.g. "3.5 kW" or "10 Wh".
|
||||
"""
|
||||
parts = unit_val.strip().split()
|
||||
if len(parts) != 2:
|
||||
raise ValueError(f"Invalid unit value format: {unit_val}")
|
||||
value, unit_str = parts
|
||||
unit = SIUnit.parse(unit_str)
|
||||
return cls(float(value), unit)
|
||||
|
||||
|
||||
# Define SI units
|
||||
WATT = SIUnit("Watt", "Power", "W", 1)
|
||||
WATT_HOUR = SIUnit("Watt-hour", "Energy", "Wh", 1)
|
||||
|
||||
|
||||
# Mapping of base unit symbols to registered SIUnit objects
|
||||
BASE_UNITS = {
|
||||
"W": WATT,
|
||||
"Wh": WATT_HOUR,
|
||||
}
|
||||
Reference in New Issue
Block a user