Seite 1 von 1

Heizstab ACThor mit Speicherstrom

Verfasst: Mi Sep 03, 2025 9:05 am
von AlexSBK
Hallo,
Ich möchte den ACThor in den Morgenstunden 4-9 Uhr mit Speicherstrom laufen lassen. Bis der Speicher z.B runter auf 20% ist.

Wie kann ich das umsetzen?

Re: Heizstab ACThor mit Speicherstrom

Verfasst: Mi Sep 03, 2025 9:29 am
von Heavendenied
Aktuell ist das so nach meinem Wissen nicht möglich.
Für die Zeitsteuerung gäbe es im Smarthome die Möglichkeit "immer an vor" und "immer an nach" zu nutzen. Aber da gibt es keine Speicherbeachtung dazu.
Umgekehrt gibt es bei der Speicherbeachtung keine Einstellung dies nur zu bestimmten Zeiten zu nutzen.
Also entweder als Feature Request (wobei fraglich ist wann der beabreitet würde, weil es wohl eine sehr exotische Anfordeurng ist) stellen oder selbst über ein Drittanbieter EMS wie HomeAssistant realisieren.

Ich persönlich würde das nie so machen, denn warum soll ich dem Speicher mehr Zyklen zumuten als unbedingt nötig? Ein paar Stunden später scheint dann die Sonne und man muss den Strom dann wieder in den Akku speichern statt ihn sofort mit dem Heizstab zu nutzen, also nochmal doppelte Verluste.

Re: Heizstab ACThor mit Speicherstrom

Verfasst: Mi Sep 03, 2025 10:38 am
von Gero
Das ist nur dann sinnvoll, wenn tagsüber so viel Überschuss kommt, dass zum einen der Speicher garantiert voll wird und der Pufferspeicher länger geheizt werden kann, als die Sonne scheint. Mehr heizen als heizen geht ja nicht. Und wenn morgens ab denn ersten Sonnenstrahlen bis abends zum letzten der Heizstab voll durchläuft und der Speicher voll wird, hätte man morgens mit den Speicherresten der Nacht noch ein bisschen den Heizstab laufen lassen können.

Ich würde sagen: Entweder ist der Heizstab zu klein oder der Warmwasserverbrauch zu hoch ;-)

Aber wenn das gemacht werden muss, geht das aktuell nur mit einer externen Steuerung. Ich würde da nodeRED nehmen, mit HA (oder ioBroker) hab' ich mich noch nicht beschäftigt. (steht aber irgendwann einmal an)

Re: Heizstab ACThor mit Speicherstrom

Verfasst: Do Sep 04, 2025 4:55 am
von AlexSBK
Hallo Zusammen,
Also gegeben ist.
18 Wohnungen mit Nahwärmenetz
4000 Liter heizwasserspeicher
168kwh Speicher
140kwp PV
45 kw ACThor

Der Speicher hat aktuell morgens zum Teil noch 50% SOC.
Wenn kein Auto geladen hat z.b.

Weil jetzt aber manchmal schon Heizung plus warmwasser abgefragt wird reichen die 4000 Liter nicht aus um die Nacht bis morgens 8-9uhr wo genug Sonne kommt zu überbrücken.

Ich müsste jetzt ca. 10-20kw vom Stromspeicher Speicher in den heizwasser Speicher übertragen….

Die Alternative Fernwärme kostet 16cent pro KW.

Re: Heizstab ACThor mit Speicherstrom

Verfasst: Do Sep 04, 2025 7:22 am
von Gero
Ah, eine große Anwendung. Da lohnt natürlich schon ein bissl Aufwand. Kauf Dir einen Raspi und installier' darauf nodeRED. Das passende Programm (in nodeRED-Speak "flow") kann ich beisteuern. Das ist natürlich nur eine Lösung, falls Du ein wenig IT-affin bist.

Ich hatte hier mal einen Post für Anfänger geschrieben, aber die Installationsroutine ist glaube ich mittlerweile ein bisschen anders.

viewtopic.php?t=4285

Re: Heizstab ACThor mit Speicherstrom

Verfasst: Do Sep 04, 2025 3:56 pm
von AlexSBK
Hi,
ja sicherlich ist die idee nicht schlecht.
Ich würde aber ungern jetzt extern die Smarthome Regelung übersteuern.

Am besten wäre es ja wenn smarthome in einem zeitfenster einfach 9kw auf dem Acthor freigibt.

Re: Heizstab ACThor mit Speicherstrom

Verfasst: Fr Sep 05, 2025 4:50 am
von Gero
Da wirst du wahrscheinlich noch ein bisschen warten müssen, denn die Prio liegt sicherlich in der nativen Implementiereng von smarthome in SW2.

Die zu bauende Logik ist aber recht simpel: ist der Speicher-SoC über x, schalte das smarthome-Gerät auf manuell und ein. Dann warte darauf, dass der Speicher-SoC auf x fällt und schalte dann das Gerät aus und auf Automatik.

Wenn ich mich recht entsinne, ist die Vorgabe der Leistung in manuellen Betrieb auch nur per MQTT möglich.

Re: Heizstab ACThor mit Speicherstrom

Verfasst: Fr Sep 05, 2025 6:52 pm
von AlexSBK
Hi,
hat sich erledigt:

Code: Alles auswählen

import requests
import paho.mqtt.client as mqtt
import logging
from datetime import datetime

# --- Logging ---
LOGFILE = "/var/log/openwb_heater.log"
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.FileHandler(LOGFILE),
        logging.StreamHandler()
    ]
)

# --- OpenEMS-Einstellungen ---
openems_url = "http://IP:8084/rest/channel/ctrlGridOptimizedCharge0/DelayChargeMaximumChargeLimit"
openems_username = "x"
openems_password = "user"
openems_base = "http://IP:8084"  # Basis-URL für REST-Channels

# --- Heizstab-/SOC-Parameter ---
SOC_THRESHOLD = 25          # Mindest-SOC für manuelles Einschalten
MIN_SOC_AUTO_MODE = 10      # Unterhalb dieses SOC -> sofort Automatik (auch vor AUTO_MODE_TIME)
MANUEB_POWER = 4000         # Leistung für den Heizstab im manuellen Modus

# --- Zeit-Parameter (einstellbar) ---
# Manuell-EIN nur im Fenster [HEATER_ON_START, HEATER_ON_END)  (Ende exklusiv)
HEATER_ON_START_HOUR = 5
HEATER_ON_START_MIN = 0
HEATER_ON_END_HOUR = 7
HEATER_ON_END_MIN = 0

# Ab dieser Uhrzeit wird zurück auf AUTOMATIK gestellt (>= AUTO_MODE_TIME)
AUTO_MODE_HOUR = 7
AUTO_MODE_MIN = 0

# --- Zeitfenster & Limits für adjust_value (parametrisierbar) ---
# Jedes Element: ((start_h, start_m), (end_h, end_m), cap_value)
CAP_RULES = [
    ((0, 0),   (10, 0),  1000),   # 00:00–09:59 -> max 1000
    ((10, 1),  (12, 0),  5000),   # 10:01–11:59 -> max 5000
    ((12, 1),  (18, 0),  30000),  # 12:01–17:59 -> max 30000
    ((18, 1),  (24, 0),  2000),   # 18:01–23:59 -> max 2000
]

# --- MQTT-Einstellungen ---
mqtt_broker_ip = "localhost"
mqtt_topic = "openWB/set/LegacySmartHome/config/get/maxBatteryPower"  # bestehender Publish

# --- Hilfsfunktionen ---
def get_openems_channel_value(channel: str):
    url = f"{openems_base}/rest/channel/{channel}"
    try:
        response = requests.get(url, auth=(openems_username, openems_password))
        response.raise_for_status()
        data = response.json()
        return data.get("value")
    except requests.exceptions.RequestException as e:
        logging.error(f"Fehler beim Abrufen des Channels {channel}: {e}")
        return None

def _minutes_since_midnight(dt: datetime) -> int:
    return dt.hour * 60 + dt.minute

def _in_window(now: datetime, start_h: int, start_m: int, end_h: int, end_m: int) -> bool:
    now_min = _minutes_since_midnight(now)
    start = start_h * 60 + start_m
    end = end_h * 60 + end_m
    if start <= end:
        return start <= now_min < end
    else:
        # Fenster über Mitternacht
        return now_min >= start or now_min < end

# --- paho-mqtt 1.x-kompatible Callbacks ---
def on_connect(client, userdata, flags, rc):
    logging.info(f"MQTT verbunden, rc={rc}")

def on_publish(client, userdata, mid):
    logging.info(f"MQTT Publish bestätigt, MID={mid}")

def get_openems_value():
    """Liest den Wert vom in openems_url konfigurierten Channel."""
    try:
        response = requests.get(openems_url, auth=(openems_username, openems_password))
        response.raise_for_status()
        data = response.json()
        return data["value"]
    except requests.exceptions.RequestException as e:
        logging.error(f"Fehler beim Abrufen des OpenEMS-Werts: {e}")
        return None

def send_mqtt_message(topic, value):
    """Einfacher One-shot Publish (connect → publish → disconnect)."""
    try:
        client = mqtt.Client()  # keine CallbackAPIVersion → kompatibel zu paho 1.x
        client.on_connect = on_connect
        client.on_publish = on_publish
        client.connect(mqtt_broker_ip, 1883, keepalive=30)
        client.loop_start()
        res = client.publish(topic, str(value))
        res.wait_for_publish()
        client.loop_stop()
        client.disconnect()
    except Exception as e:
        logging.error(f"Fehler beim Senden an {topic}: {e}")

def _cap_for_now(now: datetime):
    for (sh, sm), (eh, em), cap in CAP_RULES:
        if _in_window(now, sh, sm, eh, em):
            return cap
    return None

def adjust_value(value):
    now = datetime.now()
    cap = _cap_for_now(now)
    if cap is None:
        return value
    return min(value, cap)

# --- Hauptlogik ---

# 1) Wert abrufen und anpassen
value = get_openems_value()
if value is None:
    value = 0
    logging.warning("Kein Wert von OpenEMS erhalten. Standardwert 0 verwendet.")
else:
    logging.info(f"OpenEMS-Wert: {value}")

adjusted_value = adjust_value(value)
logging.info(f"Angepasster Wert: {adjusted_value}")

# 2) MaxBatteryPower senden
send_mqtt_message(mqtt_topic, adjusted_value)

# 3) Heizstab-Steuerung
soc = get_openems_channel_value("battery0/Soc")
if soc is None:
    logging.warning("SOC konnte nicht gelesen werden – Heizstab bleibt aus.")
else:
    logging.info(f"SOC: {soc}%")
    now = datetime.now()

    in_on_window = _in_window(
        now,
        HEATER_ON_START_HOUR, HEATER_ON_START_MIN,
        HEATER_ON_END_HOUR, HEATER_ON_END_MIN
    )

    # 3a) Manuell EIN nur im Zeitfenster und bei ausreichendem SOC
    if in_on_window and soc > SOC_THRESHOLD:
        logging.info("Bedingungen erfüllt (SOC>Schwelle & im Einschalt-Zeitfenster) → Heizstab MANUELL EIN")
        send_mqtt_message("openWB/set/LegacySmartHome/config/set/Devices/9/device_manual_control", 1)
        send_mqtt_message("openWB/set/LegacySmartHome/config/set/Devices/9/mode", 1)
        send_mqtt_message("openWB/set/LegacySmartHome/config/set/Devices/9/manueb", MANUEB_POWER)

    # 3b) Zurück in Automatik, wenn Zeit >= AUTO_MODE_TIME ODER SOC < MIN_SOC_AUTO_MODE
    elif (_minutes_since_midnight(now) >= (AUTO_MODE_HOUR * 60 + AUTO_MODE_MIN)) or (soc < MIN_SOC_AUTO_MODE):
        logging.info("Bedingungen erfüllt (Zeit >= Auto-Mode oder SOC < Min-SOC) → Heizstab AUTOMATIK")
        send_mqtt_message("openWB/set/LegacySmartHome/config/set/Devices/9/device_manual_control", 0)

    else:
        logging.info("Bedingungen nicht erfüllt (SOC/Zeitraum) – keine Aktion.")