Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Einsteigerfragen
  4. Sofar Solar HYD10 KTL Wechselrichter an modbus Adapter

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    17
    1
    2.4k

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    963

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    2.2k

Sofar Solar HYD10 KTL Wechselrichter an modbus Adapter

Geplant Angeheftet Gesperrt Verschoben Einsteigerfragen
183 Beiträge 20 Kommentatoren 25.1k Aufrufe 16 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • spicerS Online
    spicerS Online
    spicer
    schrieb zuletzt editiert von spicer
    #181

    Jetzt hat es um 2026-02-06 16:04:24.546 angefangen. Nach nur ein paar Minuten!

    Mir gefällt das "Socket closed with error" jedesmal nicht.
    Das könnte doch irgend etwas füllen bis zum Crash.
    Sauber ist das auf jeden Fall nicht.

    Wenn es mehrere Möglichkeiten gibt, eine Aufgabe zu erledigen, und eine davon in einer Katastrophe endet oder sonstwie unerwünschte Konsequenzen nach sich zieht, dann wird es jemand genau so machen. Alles, was schiefgehen kann, wird auch schiefgehen.
    (Murphys Gesetz)

    1 Antwort Letzte Antwort
    0
    • R Offline
      R Offline
      RISSN
      schrieb zuletzt editiert von
      #182

      https://www.solarvie.at/en-eu/products/sofarsolar-ethernet-dongle-lse-3

      kaufe dir einfach dieses Teil und du hast Ruhe, 55 Euro kostet weniger als die Nerven die du lassen musst. Vor allem hast du es gleich auch noch in der App

      1 Antwort Letzte Antwort
      0
      • spicerS Online
        spicerS Online
        spicer
        schrieb zuletzt editiert von spicer
        #183

        Habe mir eine eigene Lösung geschrieben, welche ich euch nicht vorenthalten möchte.
        Habe in einem LXC, welcher für diverse Skripte zuständig ist, folgendes Python Script drauf gemacht plus eine config.yaml .
        Dies sendet die Sofar-Daten per MQTT an den ioBroker.

        /opt/modbus-mqtt/modbus_tcp_rtu.py

        #!/usr/bin/env python3
        
        import socket
        import struct
        import time
        import yaml
        import logging
        import paho.mqtt.client as mqtt
        import os
        
        CONFIG_FILE = "/opt/modbus-mqtt/config.yaml"
        LOG_FILE = "/var/log/modbus-mqtt.log"
        
        logging.basicConfig(
            filename=LOG_FILE,
            level=logging.INFO,
            format="%(asctime)s [%(levelname)s] %(message)s"
        )
        
        logging.info("Starting modbus-mqtt with config from disk")
        
        try:
            with open(CONFIG_FILE, "r") as f:
                cfg = yaml.safe_load(f)
        except Exception as e:
            logging.error(f"Failed to load config: {e}")
            exit(1)
        
        last_mtime = os.path.getmtime(CONFIG_FILE)
        
        MODBUS_HOST = cfg["modbus"]["host"]
        MODBUS_PORT = cfg["modbus"]["port"]
        UNIT_ID = cfg["modbus"]["unit_id"]
        
        MQTT_HOST = cfg["mqtt"]["host"]
        MQTT_PORT = cfg["mqtt"]["port"]
        BASE_TOPIC = cfg["mqtt"]["base_topic"]
        
        POLL_INTERVAL = cfg["poll_interval"]
        REGISTERS = cfg["registers"]
        
        mqttc = mqtt.Client()
        mqttc.username_pw_set(cfg["mqtt"]["username"], cfg["mqtt"]["password"])
        mqttc.connect(MQTT_HOST, MQTT_PORT)
        mqttc.loop_start()
        
        # ---------------------------------------------------------
        # CRC16 Modbus
        # ---------------------------------------------------------
        
        def crc16(data):
            crc = 0xFFFF
            for pos in data:
                crc ^= pos
                for _ in range(8):
                    if crc & 1:
                        crc = (crc >> 1) ^ 0xA001
                    else:
                        crc >>= 1
            return crc.to_bytes(2, byteorder="little")
        
        # ---------------------------------------------------------
        # RTU‑Frame senden über TCP
        # ---------------------------------------------------------
        
        def read_holding_registers_rtu_tcp(unit, address, count):
            # Build RTU frame: [unit][function][addr_hi][addr_lo][count_hi][count_lo][crc_lo][crc_hi]
            frame = bytearray()
            frame.append(unit)
            frame.append(0x03)  # Function code: Read Holding Registers
            frame += struct.pack(">HH", address, count)
            frame += crc16(frame)
        
            # TCP socket
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(2)
            s.connect((MODBUS_HOST, MODBUS_PORT))
            s.send(frame)
        
            # Response
            response = s.recv(256)
            s.close()
        
            # Validate minimum length
            if len(response) < 5:
                raise Exception("Invalid response length")
        
            # Validate CRC
            data = response[:-2]
            crc_received = response[-2:]
            crc_calc = crc16(data)
            if crc_received != crc_calc:
                raise Exception("CRC mismatch")
        
            # Byte count
            byte_count = response[2]
            if byte_count != count * 2:
                raise Exception("Unexpected byte count")
        
            # Extract registers
            registers = []
            for i in range(count):
                hi = response[3 + i*2]
                lo = response[4 + i*2]
                registers.append((hi << 8) | lo)
        
            return registers
        
        # ---------------------------------------------------------
        # Poll‑Loop
        # ---------------------------------------------------------
        
        while True:
            # Auto‑Reload wenn config.yaml geändert wurde
            current_mtime = os.path.getmtime(CONFIG_FILE)
            if current_mtime != last_mtime:
                logging.info("Config changed, restarting...")
                mqttc.loop_stop()
                exit(0)
        
            for reg in REGISTERS:
                addr = reg["addr"]
                reg_type = reg["type"]
                factor = reg["factor"]
                length = 2 if reg_type == "uint32" else 1
        
                try:
                    regs = read_holding_registers_rtu_tcp(UNIT_ID, addr, length)
        
                    if reg_type == "int16":
                        value = struct.unpack(">h", struct.pack(">H", regs[0]))[0]
                    elif reg_type == "uint16":
                        value = regs[0]
                    elif reg_type == "uint32":
                        value = (regs[0] << 16) | regs[1]
                    else:
                        continue
        
                    value *= factor
        
                    topic = f"{BASE_TOPIC}/register/{addr}"
                    mqttc.publish(topic, value)
                    #logging.info(f"Published {topic} = {value}")
        
                except Exception as e:
                    logging.error(f"Error reading register {addr}: {e}")
        
                time.sleep(0.2)
        
            time.sleep(POLL_INTERVAL)
        
        

        /opt/modbus-mqtt/config.yaml

        modbus:
          host: "192.168.88.101"
          port: 8899
          unit_id: 1
        
        mqtt:
          host: "192.168.1.251"
          port: 1883
          base_topic: "modbus/inverter"
          username: "mqtt_user"
          password: "mqtt_passwort"
        
        poll_interval: 20
        
        registers:
          - addr: 1199
            name: "ActivePower_Load_Sys"
            type: "uint16"
            factor: 0.01
        
          - addr: 1160
            name: "ActivePower_PCC_Total"
            type: "int16"
            factor: 0.01
        
          - addr: 1476
            name: "Power_PV_Total"
            type: "uint16"
            factor: 0.01
        
          - addr: 1542
            name: "Power_Bat1"
            type: "int16"
            factor: 0.01
        
          - addr: 1544
            name: "SOC_Bat1"
            type: "uint16"
            factor: 1
        
          - addr: 1668
            name: "PV_Generation_Today"
            type: "uint32"
            factor: 0.01
        
        

        Beim Waveshare musste ich auf "Transparent" (anstelle von "modbus TCP <=> modbus RTU") stellen.
        In der config seht ihr auch, dass LXCs und der Waveshare nicht im gleichen Netzwerk sind. WAN von 192.168.88.0 (MikroTik Router) hängt am Netz 192.168.1.0 (Fritzbox). Da hab ich eine Route definiert, damit man vom einen ins andere Netz zugreifen kann.
        Die IPs, Ports, Usernames und Passwörter müsst ihr natürlich auf eure Gegebenheiten anpassen.

        In der /etc/systemd/system/modbus-mqtt.service

        [Unit]
        Description=Modbus RTU over TCP to MQTT Gateway
        After=network-online.target
        Wants=network-online.target
        
        [Service]
        Type=simple
        User=root
        WorkingDirectory=/opt/modbus-mqtt
        ExecStart=/usr/bin/env python3 /opt/modbus-mqtt/modbus_tcp_rtu.py
        Restart=always
        RestartSec=5
        Environment=PYTHONUNBUFFERED=1
        
        [Install]
        WantedBy=multi-user.target
        

        Wenn alles fertig ist, eingeben:

        sudo systemctl daemon-reload
        sudo systemctl enable modbus-mqtt.service
        sudo systemctl start modbus-mqtt.service
        

        Die Daten werden nun per MQTT an den ioBroker gesendet.
        Der Datenpunkt sieht dann etwa so aus:

        mqtt.0.modbus.inverter.register.{Registeradresse}

        c231d92c-1d69-4e52-a206-48dfd9e63cf5-grafik.png

        Wenn es mehrere Möglichkeiten gibt, eine Aufgabe zu erledigen, und eine davon in einer Katastrophe endet oder sonstwie unerwünschte Konsequenzen nach sich zieht, dann wird es jemand genau so machen. Alles, was schiefgehen kann, wird auch schiefgehen.
        (Murphys Gesetz)

        1 Antwort Letzte Antwort
        0
        Antworten
        • In einem neuen Thema antworten
        Anmelden zum Antworten
        • Älteste zuerst
        • Neuste zuerst
        • Meiste Stimmen


        Support us

        ioBroker
        Community Adapters
        Donate

        335

        Online

        32.6k

        Benutzer

        82.2k

        Themen

        1.3m

        Beiträge
        Community
        Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
        ioBroker Community 2014-2025
        logo
        • Anmelden

        • Du hast noch kein Konto? Registrieren

        • Anmelden oder registrieren, um zu suchen
        • Erster Beitrag
          Letzter Beitrag
        0
        • Home
        • Aktuell
        • Tags
        • Ungelesen 0
        • Kategorien
        • Unreplied
        • Beliebt
        • GitHub
        • Docu
        • Hilfe