Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 56 additions & 58 deletions packages/modules/common/simcount/_simcounter_store.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,20 @@
import logging
from abc import abstractmethod
from enum import Enum
from queue import Queue, Empty
from typing import Optional

from paho.mqtt.client import Client as MqttClient, MQTTMessage

from helpermodules import pub, compatibility
from modules.common.fault_state import FaultState
from modules.common.simcount._simcounter_state import SimCounterState
from modules.common.store import ramdisk_write, ramdisk_read_float
from modules.common.store.ramdisk.io import RamdiskReadError

log = logging.getLogger(__name__)


def get_topic(prefix: str) -> str:
""" ermittelt das zum Präfix gehörende Topic."""
if prefix == "bezug":
topic = "evu"
elif prefix == "pv" or prefix == "pv2":
topic = prefix
elif prefix == "speicher":
topic = "housebattery"
else:
raise FaultState.error("Fehler im Modul simcount: Unbekannter Präfix: " + prefix)
return topic

POSTFIX_EXPORT = "watt0neg"
POSTFIX_IMPORT = "watt0pos"

def get_existing_imports_exports(file: str) -> float:
try:
result = ramdisk_read_float(file)
log.info("Found counter reading <%g Wh> in file <%s>", result, file)
return result
except FileNotFoundError:
return 0
log = logging.getLogger(__name__)


def get_serial():
Expand Down Expand Up @@ -72,32 +54,54 @@ def on_connect(*_args):
client.disconnect()


def restore_value(name: str, prefix: str) -> float:
"""Returns value in Watt-seconds for historic reasons"""
topic = "openWB/" + get_topic(prefix) + ("/WHImported_temp" if name == "watt0pos" else "/WHExport_temp")
class SimCountPrefix(Enum):
PV = ("pv", None, "pvkwh")
PV2 = ("pv2", None, "pvkwh2")
BEZUG = ("evu", "bezugkwh", "einspeisungkwh")
SPEICHER = ("housebattery", "speicherikwh", "speicherekwh")

def __init__(self, topic: str, import_file: Optional[str], export_file: str):
self.topic = topic
self.import_file = import_file
self.export_file = export_file

def read_import(self) -> float:
return self.__read_file(self.import_file)

def read_export(self) -> float:
return self.__read_file(self.export_file)

@staticmethod
def __read_file(file: str) -> float:
if file is None:
return 0.0
try:
result = ramdisk_read_float(file)
log.info("Found counter reading <%g Wh> in file <%s>", result, file)
return result
except FileNotFoundError:
return 0.0


def restore_value(prefix_str: str, postfix: str) -> float:
prefix = SimCountPrefix[prefix_str.upper()]
topic = "openWB/" + prefix.topic + ("/WHImported_temp" if postfix == POSTFIX_IMPORT else "/WHExport_temp")
mqtt_value = read_mqtt_topic(topic)
log.info("read from broker: %s=%s", topic, mqtt_value)
if mqtt_value is None:
result = None
else:
try:
result = float(mqtt_value)
# MQTT-Value is in Watt-seconds for historic reasons -> / 3600
result = float(mqtt_value) / 3600
except ValueError:
log.warning("Value <%s> from topic <%s> is not a valid number", mqtt_value, topic)
result = None

if result is None:
if prefix == "bezug":
file = "bezugkwh" if name == "watt0pos" else "einspeisungkwh"
elif prefix == "pv2":
file = "pv2kwh"
elif prefix == "pv":
file = "pvkwh"
else:
file = "speicherikwh" if name == "watt0pos" else "speicherekwh"
result = get_existing_imports_exports(file) * 3600

ramdisk_write(prefix + name, result)
result = (prefix.read_import if postfix == POSTFIX_IMPORT else prefix.read_export)()

ramdisk_write(prefix_str + postfix, result)
return result


Expand All @@ -117,16 +121,9 @@ def initialize(self, prefix: str, topic: str, power: float, timestamp: float) ->

class SimCounterStoreRamdisk(SimCounterStore):
def initialize(self, prefix: str, topic: str, power: float, timestamp: float) -> SimCounterState:
if prefix == "bezug":
imported = get_existing_imports_exports("bezugkwh")
exported = get_existing_imports_exports("einspeisungkwh")
elif prefix == "pv" or prefix == "pv2":
imported = 0
exported = get_existing_imports_exports(prefix + "kwh")
else:
imported = get_existing_imports_exports("speicherikwh")
exported = get_existing_imports_exports("speicherekwh")
result = SimCounterState(timestamp, power, imported, exported)
result = SimCounterState(
timestamp, power, restore_value(prefix, POSTFIX_IMPORT), restore_value(prefix, POSTFIX_EXPORT)
)
self.save(prefix, topic, result)
return result

Expand All @@ -136,29 +133,30 @@ def load(self, prefix: str, topic: str) -> Optional[SimCounterState]:
except FileNotFoundError:
return None

def read_or_restore(name: str) -> float:
# For historic reasons, the SimCount stored state uses Watt-seconds instead of Watt-hours -> / 3600:
def read_or_restore(postfix: str) -> float:
try:
return ramdisk_read_float(prefix + name) / 3600
except Exception:
return restore_value(name, prefix) / 3600
# ramdisk value is in watt-seconds for historic reasons -> / 3600
return ramdisk_read_float(prefix + postfix) / 3600
except (FileNotFoundError, RamdiskReadError) as e:
log.warning("Read from ramdisk failed: %s. Attempting restore from broker", e)
return restore_value(prefix, postfix)

return SimCounterState(
timestamp=timestamp,
power=ramdisk_read_float(prefix + "wh0"),
imported=read_or_restore("watt0pos"),
imported=read_or_restore(POSTFIX_IMPORT),
# abs() weil runs/simcount.py speichert das Zwischenergebnis des Exports negativ ab:
exported=abs(read_or_restore("watt0neg")),
exported=abs(read_or_restore(POSTFIX_EXPORT)),
)

def save(self, prefix: str, topic: str, state: SimCounterState):
topic = get_topic(prefix)
topic = SimCountPrefix[prefix.upper()].topic
ramdisk_write(prefix + "sec0", state.timestamp)
ramdisk_write(prefix + "wh0", state.power)

# For historic reasons, the SimCount stored state uses Watt-seconds instead of Watt-hours -> * 3600:
ramdisk_write(prefix + "watt0pos", state.imported * 3600)
ramdisk_write(prefix + "watt0neg", state.exported * 3600)
ramdisk_write(prefix + POSTFIX_IMPORT, state.imported * 3600)
ramdisk_write(prefix + POSTFIX_EXPORT, state.exported * 3600)
pub.pub_single("openWB/" + topic + "/WHImported_temp", state.imported * 3600, no_json=True)
pub.pub_single("openWB/" + topic + "/WHExport_temp", state.exported * 3600, no_json=True)

Expand Down