Neueste Beiträge

#21
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von Bitschubser - 25 Juli 2026, 18:38:14
Mit set SolarForecast reset aiData searchValue=con>9000 bekomme ich die Werte angezeigt.
2026.07.25 17:44:34 1: SolarForecast - AI Raw data found - idx: 2026072416 -> key=con, val=10582
Wenn ich das korrekt deute, sagt diese Zeile aus, dass am 24.06.2026 zwischen 15:00 Uhr und 16:00 Uhr 10582 Watt verbraucht wurden.
Das ist auch korrekt so, da wurde das Auto geladen.
Ich hätte aber gerne eine Prognose aus Werten ohne den Verbrauch der Wallbox / Consumer01 mit einzubeziehen, da das Auto nicht immer - und schon gar nicht immer zur selben Zeit - da ist, um geladen zu werden.
Daher habe ich den Parameter exconfc=1 in der Konfiguration des Consumer01 gesetzt. Das scheint aber nicht so zu funktionieren, wie ich dachte, denn sonst hätte ich keine prognostizierten Verbräuche in der Höhe

Die KI-Prognose hatte ich vor einiger zeit aktiviert, dabei aber keine weiteren Parameter angegeben.
Habe jetzt aiConActivate=1 als Parameter angegeben

Nach Aktivierung ctrlDebug=consumption_long sehe ich im Log:
2026.07.25 18:26:45 1: SolarForecast DEBUG> ################### START Consumption forecast ###################
2026.07.25 18:26:45 1: SolarForecast DEBUG> Basics - installed locale: C.UTF-8, used scheme: EN
2026.07.25 18:26:45 1: SolarForecast DEBUG> Need number of stored days: 60, Number of days in History: 31 => can calculate excludes/includes: no
2026.07.25 18:26:45 1: SolarForecast DEBUG> process Today dayname: Sat, Tomorrow dayname: Sun
2026.07.25 18:26:45 1: SolarForecast DEBUG> ################### Consumption forecast for the next 24 Hours ###################
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=00, isToday=1, hod=19, SUMMARY -> estimated CON: 1406 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=01, isToday=1, hod=20, SUMMARY -> estimated CON: 1311 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=02, isToday=1, hod=21, SUMMARY -> estimated CON: 1000 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=03, isToday=1, hod=22, SUMMARY -> estimated CON: 1060 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=04, isToday=1, hod=23, SUMMARY -> estimated CON: 1060 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=05, isToday=1, hod=24, SUMMARY -> estimated CON: 962 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=06, isToday=0, hod=01, SUMMARY -> estimated CON: 842 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=07, isToday=0, hod=02, SUMMARY -> estimated CON: 762 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=08, isToday=0, hod=03, SUMMARY -> estimated CON: 743 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=09, isToday=0, hod=04, SUMMARY -> estimated CON: 741 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=10, isToday=0, hod=05, SUMMARY -> estimated CON: 736 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=11, isToday=0, hod=06, SUMMARY -> estimated CON: 760 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=12, isToday=0, hod=07, SUMMARY -> estimated CON: 636 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=13, isToday=0, hod=08, SUMMARY -> estimated CON: 958 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=14, isToday=0, hod=09, SUMMARY -> estimated CON: 1476 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=15, isToday=0, hod=10, SUMMARY -> estimated CON: 1464 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=16, isToday=0, hod=11, SUMMARY -> estimated CON: 1512 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=17, isToday=0, hod=12, SUMMARY -> estimated CON: 2326 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=18, isToday=0, hod=13, SUMMARY -> estimated CON: 1646 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=19, isToday=0, hod=14, SUMMARY -> estimated CON: 2150 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=20, isToday=0, hod=15, SUMMARY -> estimated CON: 2630 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=21, isToday=0, hod=16, SUMMARY -> estimated CON: 1622 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=22, isToday=0, hod=17, SUMMARY -> estimated CON: 1767 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=23, isToday=0, hod=18, SUMMARY -> estimated CON: 2056 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=24, isToday=0, hod=19, SUMMARY -> estimated CON: 1406 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=25, isToday=0, hod=20, SUMMARY -> estimated CON: 1311 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=26, isToday=0, hod=21, SUMMARY -> estimated CON: 1000 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=27, isToday=0, hod=22, SUMMARY -> estimated CON: 1060 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=28, isToday=0, hod=23, SUMMARY -> estimated CON: 1060 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=29, isToday=0, hod=24, SUMMARY -> estimated CON: 962 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=30, isToday=0, hod=01, SUMMARY -> estimated CON: 842 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=31, isToday=0, hod=02, SUMMARY -> estimated CON: 762 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=32, isToday=0, hod=03, SUMMARY -> estimated CON: 743 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=33, isToday=0, hod=04, SUMMARY -> estimated CON: 741 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=34, isToday=0, hod=05, SUMMARY -> estimated CON: 736 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=35, isToday=0, hod=06, SUMMARY -> estimated CON: 760 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=36, isToday=0, hod=07, SUMMARY -> estimated CON: 636 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=37, isToday=0, hod=08, SUMMARY -> estimated CON: 958 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=38, isToday=0, hod=09, SUMMARY -> estimated CON: 1476 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=39, isToday=0, hod=10, SUMMARY -> estimated CON: 1464 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=40, isToday=0, hod=11, SUMMARY -> estimated CON: 1512 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=41, isToday=0, hod=12, SUMMARY -> estimated CON: 2326 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=42, isToday=0, hod=13, SUMMARY -> estimated CON: 1646 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=43, isToday=0, hod=14, SUMMARY -> estimated CON: 2150 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=44, isToday=0, hod=15, SUMMARY -> estimated CON: 2630 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=45, isToday=0, hod=16, SUMMARY -> estimated CON: 1622 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=46, isToday=0, hod=17, SUMMARY -> estimated CON: 1767 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=47, isToday=0, hod=18, SUMMARY -> estimated CON: 2056 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=48, isToday=0, hod=19, SUMMARY -> estimated CON: 1406 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=49, isToday=0, hod=20, SUMMARY -> estimated CON: 1311 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=50, isToday=0, hod=21, SUMMARY -> estimated CON: 1000 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=51, isToday=0, hod=22, SUMMARY -> estimated CON: 1060 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=52, isToday=0, hod=23, SUMMARY -> estimated CON: 1060 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> NH=53, isToday=0, hod=24, SUMMARY -> estimated CON: 962 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> ################### ENDE Consumption forecast ###################
2026.07.25 18:26:45 1: SolarForecast DEBUG> store AI legacy alpha value to circular/history -> hod=19 confc=1848 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> store AI legacy alpha value to circular/history -> hod=20 confc=895 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> store AI legacy alpha value to circular/history -> hod=21 confc=692 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> store AI legacy alpha value to circular/history -> hod=22 confc=1122 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> store AI legacy alpha value to circular/history -> hod=23 confc=629 Wh
2026.07.25 18:26:45 1: SolarForecast DEBUG> store AI legacy alpha value to circular/history -> hod=24 confc=963 Wh
Diese Prognosen könnten so passen.
#22
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von Prof. Dr. Peter Henning - 25 Juli 2026, 17:50:01
Zitat von: DS_Starter am 25 Juli 2026, 17:24:52Ach ... ist einfach zu warm  ;)

LG,
Heiko

Ich habe den Post aus meinem Whirlpool heraus gemacht.

LG

pah
#23
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von DS_Starter - 25 Juli 2026, 17:49:18
@Bitschubser,

was liefert dein Log mit ctrlDebug=consumption_long?

Verwendest du KI (Fann)? oder die Standard Legacy-Prognose?
#24
Codeschnipsel / Aw: Blitze per MQTT
Letzter Beitrag von OliS. - 25 Juli 2026, 17:31:25
Und hier noch eine Version, die die nächstgrößere Ortschaft anhand der Koordinaten mit ausgibt.

#!/usr/bin/env python3

import asyncio
import json
import logging
import math
import time
from datetime import datetime, timezone
from urllib import parse, request

import websockets
import paho.mqtt.client as mqtt

# ---------------------------------------------------------------------------
# Konfiguration - hier anpassen
# ---------------------------------------------------------------------------

HOME_LAT = 50.815      # eigene Breite
HOME_LON = 10.225      # eigene Laenge
RADIUS_KM = 20         # Umkreis, der als "hier" gilt

MQTT_HOST = "127.0.0.1"
MQTT_PORT = 1883
MQTT_USER = None       # z.B. "fhem" oder None wenn kein Login noetig
MQTT_PASS = None
MQTT_TOPIC = "blitz/strike"
MQTT_CLIENT_ID = "blitzortung_bridge"

# Mehrere Blitzortung-Relays, falls eines nicht erreichbar ist wird
# automatisch das naechste probiert
WS_SERVERS = [
    "wss://ws1.blitzortung.org/",
    "wss://ws2.blitzortung.org/",
    "wss://ws3.blitzortung.org/",
    "wss://ws4.blitzortung.org/",
    "wss://ws5.blitzortung.org/",
    "wss://ws6.blitzortung.org/",
    "wss://ws7.blitzortung.org/",
    "wss://ws8.blitzortung.org/",
]

# Handshake-Nachricht, die der Server erwartet bevor er Daten schickt
HANDSHAKE_MSG = '{"a": 111}'

# User-Agent für Nominatim (bitte aussagekräftig, z.B. mit Projektname + Kontakt)
NOMINATIM_USER_AGENT = "blitzortung_bridge (dein Kontakt oder Projekt-URL)"

# ---------------------------------------------------------------------------
# Reverse Geocoding (Nominatim)
# ---------------------------------------------------------------------------

def get_nearest_town(lat: float, lon: float, language: str = "de") -> str | None:
    """
    Ermittelt per Nominatim die nächstgrößere Ortschaft für gegebene Koordinaten.
    Gibt Stadt/Town/Village zurück oder None, falls nichts gefunden.
    """
    base_url = "https://nominatim.openstreetmap.org/reverse"
    params = {
        "lat": lat,
        "lon": lon,
        "format": "json",
        "accept-language": language,
        "zoom": 10,          # Bevorzugt größere Ortschaften
    }

    url = base_url + "?" + parse.urlencode(params)
    headers = {
        "User-Agent": NOMINATIM_USER_AGENT,
    }

    req = request.Request(url, headers=headers)

    try:
        with request.urlopen(req, timeout=5) as resp:
            data = json.loads(resp.read().decode("utf-8"))
    except Exception:
        logging.debug("Nominatim-Anfrage fehlgeschlagen für %s,%s", lat, lon)
        return None

    address = data.get("address", {})

    # Priorität: city > town > village > municipality > county
    for key in ("city", "town", "village", "municipality", "county"):
        value = address.get(key)
        if value:
            return value

    # Fallback: 'name' oder 'place' aus dem Top-Level
    return data.get("name") or data.get("place")


# ---------------------------------------------------------------------------
# Blitzortung Dekompression & Geodäsie
# ---------------------------------------------------------------------------

def unpack_blitzortung(raw: str) -> str:
    """Entpackt die LZW-aehnliche Kompression, die Blitzortung fuer
    die WebSocket-Rohdaten verwendet. Portiert aus einer verifizierten
    Referenzimplementierung (gkbrk.com/blitzortung)."""
    d = list(raw)
    if not d:
        return ""
    dictionary = {}
    c = d[0]
    f = c
    out = [c]
    next_code = 256
    for i in range(1, len(d)):
        code = ord(d[i])
        if code < 256:
            a = d[i]
        else:
            a = dictionary.get(code) or (f + c)
        out.append(a)
        c = a[0]
        dictionary[next_code] = f + c
        next_code += 1
        f = a
    return "".join(out)


def haversine_km(lat1, lon1, lat2, lon2) -> float:
    r = 6371.0
    dlat = math.radians(lat2 - lat1)
    dlon = math.radians(lon2 - lon1)
    a = (
        math.sin(dlat / 2) ** 2
        + math.cos(math.radians(lat1))
        * math.cos(math.radians(lat2))
        * math.sin(dlon / 2) ** 2
    )
    return r * 2 * math.asin(math.sqrt(a))


def calculate_bearing(lat1, lon1, lat2, lon2) -> float:
    """Berechnet den mathematischen Grosskreiswinkel (Azimut) von Punkt 1 zu Punkt 2.
    Ergebnis: 0° = Norden, 90° = Osten, 180° = Sueden, 270° = Westen"""
    lat1_rad = math.radians(lat1)
    lat2_rad = math.radians(lat2)
    diff_lon_rad = math.radians(lon2 - lon1)

    x = math.sin(diff_lon_rad) * math.cos(lat2_rad)
    y = math.cos(lat1_rad) * math.sin(lat2_rad) - (
        math.sin(lat1_rad) * math.cos(lat2_rad) * math.cos(diff_lon_rad)
    )

    initial_bearing = math.atan2(x, y)
    initial_bearing = math.degrees(initial_bearing)
    return (initial_bearing + 360) % 360


def bearing_to_text(bearing: float) -> str:
    """Konvertiert Gradzahlen (0-360) in Himmelsrichtungs-Kuerzel (8er-Teilung)."""
    directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]
    index = int((bearing + 22.5) / 45) % 8
    return directions[index]


logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(message)s",
)
log = logging.getLogger("blitz-bridge")


class MqttPublisher:
    def __init__(self):
        self.client = mqtt.Client(client_id=MQTT_CLIENT_ID)
        if MQTT_USER:
            self.client.username_pw_set(MQTT_USER, MQTT_PASS)
        self.client.connect(MQTT_HOST, MQTT_PORT, keepalive=60)
        self.client.loop_start()

    def publish(self, payload: dict):
        self.client.publish(MQTT_TOPIC, json.dumps(payload, ensure_ascii=False), qos=0, retain=False)


async def listen_once(publisher: MqttPublisher, start_index: int = 0):
    """Ein Verbindungsversuch. Wirft eine Exception bei Verbindungsabbruch."""
    servers = WS_SERVERS[start_index:] + WS_SERVERS[:start_index]
    for server in servers:
        try:
            log.debug("Verbinde mit %s ...", server)
            async with websockets.connect(server, ping_interval=20, ping_timeout=20) as ws:
                await ws.send(HANDSHAKE_MSG)
                log.debug("Verbunden, warte auf Blitzdaten ...")
                async for raw_msg in ws:
                    handle_message(raw_msg, publisher)
                return  # Verbindung sauber beendet -> aeussere Schleife reconnected
        except Exception as exc:
            log.debug("Verbindung zu %s fehlgeschlagen: %s", server, exc)
            continue
    # Wenn alle Server fehlgeschlagen sind, kurz warten bevor Retry
    await asyncio.sleep(5)


def handle_message(raw_msg: str, publisher: MqttPublisher):
    try:
        text = unpack_blitzortung(raw_msg)
        data = json.loads(text)
    except Exception as exc:
        log.debug("Konnte Nachricht nicht verarbeiten (%s): %.100s", exc, raw_msg)
        return  # ungueltige/nicht relevante Nachricht ignorieren

    lat = data.get("lat")
    lon = data.get("lon")
    if lat is None or lon is None:
        return

    dist = haversine_km(HOME_LAT, HOME_LON, lat, lon)
    if dist <= RADIUS_KM:
        ts_ns = data.get("time")
        ts = (
            datetime.fromtimestamp(ts_ns / 1e9, tz=timezone.utc).isoformat()
            if ts_ns
            else datetime.now(tz=timezone.utc).isoformat()
        )
       
        # Berechnung der Richtung (Grad und Text)
        bearing = calculate_bearing(HOME_LAT, HOME_LON, lat, lon)
        bearing_txt = bearing_to_text(bearing)

        # Ortschaft via Nominatim (optional, nicht-blockierend genug für den Use-Case)
        location = get_nearest_town(lat, lon)

        payload = {
            "distance_km": round(dist, 1),
            "direction_deg": round(bearing, 1),
            "direction_text": bearing_txt,
            "lat": lat,
            "lon": lon,
            "time": ts,
        }

        if location:
            payload["location"] = location

        log.info(
            "Blitz im Radius: %.1f km entfernt in Richtung %s (%.1f°) bei %s",
            dist,
            bearing_txt,
            bearing,
            location or "unbekannter Ort",
        )
        publisher.publish(payload)


async def main():
    publisher = MqttPublisher()
    server_index = 0
    while True:
        try:
            await listen_once(publisher, start_index=server_index)
        except Exception as exc:
            log.error("Unerwarteter Fehler: %s", exc)
        server_index = (server_index + 1) % len(WS_SERVERS)
        log.debug("Verbindung verloren, versuche erneut in 5s ...")
        await asyncio.sleep(5)


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        log.info("Beendet durch Benutzer.")

LG
Oli
#25
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von Bitschubser - 25 Juli 2026, 17:27:19
Danke Peter für deinen Hinweis. Ich habe es selbstverständlich in meinem Post geändert.
Bringt mich aber nicht wirklich weiter.
#26
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von DS_Starter - 25 Juli 2026, 17:24:52

Ich möchte doch mal stark anregen, die Einheit kWh/Stunde durch kW zu ersetzen.

Wo hast du eine solche Stelle gefunden? Suche im Code bringt keinen Fund.


Ach ... ist einfach zu warm  ;)

LG,
Heiko
#27
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von Prof. Dr. Peter Henning - 25 Juli 2026, 17:05:06
Ich möchte doch mal stark anregen, die Einheit kWh/Stunde durch kW zu ersetzen. Und wenn nötig, als Mittelwert zu kennzeichnen.

LG

pah
#28
Sonstige Systeme / Aw: Withings Modul - 32_within...
Letzter Beitrag von erdnar - 25 Juli 2026, 16:58:02
Zitat von: RalfP am 23 Juli 2026, 10:36:18Hallo,

habe seit einigen Tagen diese Meldung im Log:
withings: getUserDetail json error Invalid Params: action is specified in URL and in GET/POST dataKennt jemand den Grund dafür?

Ist jetzt sicher nur bedingt hilfreich:
Ich habe heute das WithingsModul erstmalig (wegen neuer Waage) installiert.
Der Fehler taucht ab Installation im 15-Minutenrythmus auf.
Danke
ErdnaR
#29
Homematic / Aw: Problem mit dem HM-Sec-SD
Letzter Beitrag von Otto123 - 25 Juli 2026, 16:47:09
Zitat von: kurtklaiber am 25 Juli 2026, 15:46:04Das wäre allerdings zur Erprobung der notifys (usw) sehr hilfreich.
Du kannst den Event mit dem trigger Befehl simulieren, siehe auch help trigger
#30
Automatisierung / Aw: Neues Modul - 74_Unifi - F...
Letzter Beitrag von sxx128 - 25 Juli 2026, 16:40:35
Hallo zusammen,

ich habe seit dieser Woche einen Unifi Cloudgateway Ulra. Egal was ich mache ich bekomme den nicht in FHem integriert
ein:

define Unifi  Unifi IPAdresse  443 Benutzer Passwort  60 default

legt das Device an. Der Status ist aber immer "disconnected"

Auf dem Cloudgateway habe ich einen lokalen Benutzer mit entprechenden Rechten angelegt.

Egal was ich gelesen und probiert habe hilft nix. Am Ende des Tages würde ich gerne eine Anwesenheitserkennung realisieren. Ich hab von APIs gelesen, von einem alten Modul usw. usw. . kann mir jemand von euch bitte auf die Sprünge helfen. Das wäre super. Vielen Dank für eure Hilfe im Voraus und ein schönes Wochenende.

Ich habe jetzt mal den Patch und die 74_Unifi.pm

installiert. Es ergab sich keinerlei Änderung.

Grüße
Steven