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. Einbindung von Geräten
  5. Qcells / Solax Pv Anlage live Datenabfrage via Curl

NEWS

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

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

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    2.2k

Qcells / Solax Pv Anlage live Datenabfrage via Curl

Geplant Angeheftet Gesperrt Verschoben Einbindung von Geräten
5 Beiträge 4 Kommentatoren 1.1k Aufrufe 2 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.
  • jamakr4J Offline
    jamakr4J Offline
    jamakr4
    schrieb am zuletzt editiert von
    #1

    Hallo,
    alle die eine Solax bzw Qcells Pv Anlage haben kennen bestimmt das Problem, dass die Daten welche man über die Cloud bekommt nur alle 5 Minuten aktualisiert werden. Das ist für meine Zwecke jedoch zu ungenau. Also kurz gesucht und siehe da es gibt eine Lösung welche wesentlich mehr Daten in einem wesentlich kürzeren Zeitintervall ausgibt:

    curl -d "optType=ReadRealTimeData&pwd=<XXX Passwort XXX>" http://<XXX IP Adresse XXX>

    Als Folge kommt dann dieses tolle Zahlen Chaos (wahrscheinlich in json) raus:

    {"sn":"XXXXXXXX","ver":"3.008.10","type":14,"Data":[2342,2297,2364,55,54,54,1269,1229,1268,3766,4949,3130,21,91,1067,2852,4996,5000,4998,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1341,0,0,0,0,42780,0,0,4262,0,0,1,49,2425,256,7685,6672,5893,100,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0,11156,0,385,4,0,0,2833,0,3235,0,31,100,12045,0,471,0,0,0,44032,0,16875,0,2755,0,220,0,0,0,0,0,0,0,0,0,1,99,1,32,122,256,4672,3200,0,300,242,218,34,33,24,2132,782,15934,15934,15934,15934,0,0,3358,3321,44242,9,20564,12339,18753,12599,18737,12356,14132,20564,12339,18754,12345,18742,12358,12599,20564,12339,18754,12345,18742,12870,14132,20564,12339,18754,12345,18742,12870,12338,20564,12339,18754,12345,18742,12358,13110,4097,4098,1281,259,0,42780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"Information":[XXXXXX,XXX,"XXXXXXXXXXX",8,1.30,0.00,1.28,1.09,0.00,1]}

    (XXX ersetzt hier nur Zahlen, welche ich nicht veröffentlichen möchte)

    Auf Github hat jemand die Zahlen dann mit diesem Skript auseinander gepuzzelt (welcher Wert bedeutet was)

    import voluptuous as vol
    import aiohttp
    from solax.inverter import InverterPost
    from solax.units import Total, Units
    from solax.utils import (
    div10,
    div100,
    twoway_div10,
    to_signed,
    pv_energy,
    twoway_div100,
    total_energy,
    discharge_energy,
    charge_energy,
    feedin_energy,
    consumption,
    )

    class QVOLTHYBG33P(InverterPost):
    """
    QCells
    Q.VOLT HYB-G3-3P
    """

    class Processors:
        """
        Postprocessors used only in the QVOLTHYBG33P inverter sensor_map.
        """
    
        @staticmethod
        def inverter_modes(value, *_args, **_kwargs):
            return {
                0: "Waiting",
                1: "Checking",
                2: "Normal",
                3: "Off",
                4: "Permanent Fault",
                5: "Updating",
                6: "EPS Check",
                7: "EPS Mode",
                8: "Self Test",
                9: "Idle",
                10: "Standby",
            }.get(value, f"unmapped value '{value}'")
    
        @staticmethod
        def battery_modes(value, *_args, **_kwargs):
            return {
                0: "Self Use Mode",
                1: "Force Time Use",
                2: "Back Up Mode",
                3: "Feed-in Priority",
            }.get(value, f"unmapped value '{value}'")
    
    def __init__(self, host, port, pwd=""):
        super().__init__(host, port, pwd)
        self.manufacturer = "Qcells"
    
    _schema = vol.Schema(
        {
            vol.Required("type"): vol.All(int, 14),
            vol.Required("sn"): str,
            vol.Required("ver"): str,
            vol.Required("Data"): vol.Schema(
                vol.All(
                    [vol.Coerce(float)],
                    vol.Length(min=200, max=200),
                )
            ),
            vol.Required("Information"): vol.Schema(
                vol.All(vol.Length(min=10, max=10))
            ),
        },
        extra=vol.REMOVE_EXTRA,
    )
    
    @classmethod
    def response_decoder(cls):
        return {
            "Network Voltage Phase 1": (0, Units.V, div10),
            "Network Voltage Phase 2": (1, Units.V, div10),
            "Network Voltage Phase 3": (2, Units.V, div10),
            "Output Current Phase 1": (3, Units.A, twoway_div10),
            "Output Current Phase 2": (4, Units.A, twoway_div10),
            "Output Current Phase 3": (5, Units.A, twoway_div10),
            "Power Now Phase 1": (6, Units.W, to_signed),
            "Power Now Phase 2": (7, Units.W, to_signed),
            "Power Now Phase 3": (8, Units.W, to_signed),
            "AC Power": (9, Units.W, to_signed),
            "PV1 Voltage": (10, Units.V, div10),
            "PV2 Voltage": (11, Units.V, div10),
            "PV1 Current": (12, Units.A, div10),
            "PV2 Current": (13, Units.A, div10),
            "PV1 Power": (14, Units.W),
            "PV2 Power": (15, Units.W),
            "Grid Frequency Phase 1": (16, Units.HZ, div100),
            "Grid Frequency Phase 2": (17, Units.HZ, div100),
            "Grid Frequency Phase 3": (18, Units.HZ, div100),
            "Inverter Operation mode": (19, Units.NONE, cls.Processors.inverter_modes),
            # 20 - 32: always 0
            # 33: always 1
            # instead of to_signed this is actually 34 - 35,
            # because 35 =  if 34>32767: 0 else: 65535
            "Exported Power": (34, Units.W, to_signed),
            # 35: if 34>32767: 0 else: 65535
            # 36 - 38    : always  0
            "Battery Voltage": (39, Units.V, div100),
            "Battery Current": (40, Units.A, twoway_div100),
            "Battery Power": (41, Units.W, to_signed),
            # 42: div10, almost identical to [39]
            # 43: twoway_div10,  almost the same as "40" (battery current)
            # 44: twoway_div100, almost the same as "41" (battery power),
            # 45: always 1
            # 46: follows PV Output, idles around 44, peaks at 52,
            "Power Now": (47, Units.W, to_signed),
            # 48: always 256
            # 49,50: [49] + [50] * 15160 some increasing counter
            # 51: always 5634
            # 52: always 100
            # 53: always 0
            # 54: follows PV Output, idles around 35, peaks at 54,
            # 55-67: always 0
            "Total Energy": (68, Total(Units.KWH), total_energy),
            "Total Energy Resets": (69),
            # 70: div10, today's energy including battery usage
            # 71-73: 0
            "Total Battery Discharge Energy": (74, Total(Units.KWH), discharge_energy),
            "Total Battery Discharge Energy Resets": (75),
            "Total Battery Charge Energy": (76, Total(Units.KWH), charge_energy),
            "Total Battery Charge Energy Resets": (77),
            "Today's Battery Discharge Energy": (78, Units.KWH, div10),
            "Today's Battery Charge Energy": (79, Units.KWH, div10),
            "Total PV Energy": (80, Total(Units.KWH), pv_energy),
            "Total PV Energy Resets": (81),
            "Today's Energy": (82, Units.KWH, div10),
            # 83-85: always 0
            "Total Feed-in Energy": (86, Total(Units.KWH), feedin_energy),
            "Total Feed-in Energy Resets": (87),
            "Total Consumption": (88, Total(Units.KWH), consumption),
            "Total Consumption Resets": (89),
            "Today's Feed-in Energy": (90, Units.KWH, div100),
            # 91: always 0
            "Today's Consumption": (92, Units.KWH, div100),
            # 93-101: always 0
            # 102: always 1
            "Battery Remaining Capacity": (103, Units.PERCENT),
            # 104: always 1
            "Battery Temperature": (105, Units.C),
            "Battery Remaining Energy": (106, Units.KWH, div10),
            # 107: always 256 or 0
            # 108: always 3504
            # 109: always 2400
            # 110: around rise to 300 if battery not full, 0 if battery is full
            # 112, 113: range [250,350]; looks like 113 + offset = 112,
            #   peaks if battery is full
            # 114, 115: something around 33; Some temperature?!
            # 116: increases slowly [2,5]
            # 117-121: 1620	773	12850	12850	12850
            # 122-124: always 0
            # 125,126: some curve, look very similar to "42"(Battery Power),
            # with offset around 15
            # 127,128 resetting counter /1000, around battery charge + discharge
            # 164,165,166 some curves
            "Battery Operation mode": (168, Units.NONE, cls.Processors.battery_modes),
            # 169: div100 same as [39]
            # 170-199: always 0
        }
    
    @classmethod
    async def make_request(cls, host, port=80, pwd="", headers=None):
    
        url = f"http://{host}:{port}/"
        data = f"optType=ReadRealTimeData&pwd={pwd}"
    
        async with aiohttp.ClientSession() as session:
            async with session.post(url, headers=headers, data=data) as req:
                resp = await req.read()
    
        return cls.handle_response(resp)
    

    Nun ist meine Idee die Werte aus der Curl Abfrage einfach in ioBroker Datenpunkte einzutragen, leider kenne ich mich mit der Materie noch zu wenig aus und wollte daher mal fragen ob eventuell hier jemand eine Idee hat.

    Viele Grüße
    Jan

    arteckA 1 Antwort Letzte Antwort
    0
    • jamakr4J jamakr4

      Hallo,
      alle die eine Solax bzw Qcells Pv Anlage haben kennen bestimmt das Problem, dass die Daten welche man über die Cloud bekommt nur alle 5 Minuten aktualisiert werden. Das ist für meine Zwecke jedoch zu ungenau. Also kurz gesucht und siehe da es gibt eine Lösung welche wesentlich mehr Daten in einem wesentlich kürzeren Zeitintervall ausgibt:

      curl -d "optType=ReadRealTimeData&pwd=<XXX Passwort XXX>" http://<XXX IP Adresse XXX>

      Als Folge kommt dann dieses tolle Zahlen Chaos (wahrscheinlich in json) raus:

      {"sn":"XXXXXXXX","ver":"3.008.10","type":14,"Data":[2342,2297,2364,55,54,54,1269,1229,1268,3766,4949,3130,21,91,1067,2852,4996,5000,4998,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1341,0,0,0,0,42780,0,0,4262,0,0,1,49,2425,256,7685,6672,5893,100,0,42,0,0,0,0,0,0,0,0,0,0,0,0,0,11156,0,385,4,0,0,2833,0,3235,0,31,100,12045,0,471,0,0,0,44032,0,16875,0,2755,0,220,0,0,0,0,0,0,0,0,0,1,99,1,32,122,256,4672,3200,0,300,242,218,34,33,24,2132,782,15934,15934,15934,15934,0,0,3358,3321,44242,9,20564,12339,18753,12599,18737,12356,14132,20564,12339,18754,12345,18742,12358,12599,20564,12339,18754,12345,18742,12870,14132,20564,12339,18754,12345,18742,12870,12338,20564,12339,18754,12345,18742,12358,13110,4097,4098,1281,259,0,42780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"Information":[XXXXXX,XXX,"XXXXXXXXXXX",8,1.30,0.00,1.28,1.09,0.00,1]}

      (XXX ersetzt hier nur Zahlen, welche ich nicht veröffentlichen möchte)

      Auf Github hat jemand die Zahlen dann mit diesem Skript auseinander gepuzzelt (welcher Wert bedeutet was)

      import voluptuous as vol
      import aiohttp
      from solax.inverter import InverterPost
      from solax.units import Total, Units
      from solax.utils import (
      div10,
      div100,
      twoway_div10,
      to_signed,
      pv_energy,
      twoway_div100,
      total_energy,
      discharge_energy,
      charge_energy,
      feedin_energy,
      consumption,
      )

      class QVOLTHYBG33P(InverterPost):
      """
      QCells
      Q.VOLT HYB-G3-3P
      """

      class Processors:
          """
          Postprocessors used only in the QVOLTHYBG33P inverter sensor_map.
          """
      
          @staticmethod
          def inverter_modes(value, *_args, **_kwargs):
              return {
                  0: "Waiting",
                  1: "Checking",
                  2: "Normal",
                  3: "Off",
                  4: "Permanent Fault",
                  5: "Updating",
                  6: "EPS Check",
                  7: "EPS Mode",
                  8: "Self Test",
                  9: "Idle",
                  10: "Standby",
              }.get(value, f"unmapped value '{value}'")
      
          @staticmethod
          def battery_modes(value, *_args, **_kwargs):
              return {
                  0: "Self Use Mode",
                  1: "Force Time Use",
                  2: "Back Up Mode",
                  3: "Feed-in Priority",
              }.get(value, f"unmapped value '{value}'")
      
      def __init__(self, host, port, pwd=""):
          super().__init__(host, port, pwd)
          self.manufacturer = "Qcells"
      
      _schema = vol.Schema(
          {
              vol.Required("type"): vol.All(int, 14),
              vol.Required("sn"): str,
              vol.Required("ver"): str,
              vol.Required("Data"): vol.Schema(
                  vol.All(
                      [vol.Coerce(float)],
                      vol.Length(min=200, max=200),
                  )
              ),
              vol.Required("Information"): vol.Schema(
                  vol.All(vol.Length(min=10, max=10))
              ),
          },
          extra=vol.REMOVE_EXTRA,
      )
      
      @classmethod
      def response_decoder(cls):
          return {
              "Network Voltage Phase 1": (0, Units.V, div10),
              "Network Voltage Phase 2": (1, Units.V, div10),
              "Network Voltage Phase 3": (2, Units.V, div10),
              "Output Current Phase 1": (3, Units.A, twoway_div10),
              "Output Current Phase 2": (4, Units.A, twoway_div10),
              "Output Current Phase 3": (5, Units.A, twoway_div10),
              "Power Now Phase 1": (6, Units.W, to_signed),
              "Power Now Phase 2": (7, Units.W, to_signed),
              "Power Now Phase 3": (8, Units.W, to_signed),
              "AC Power": (9, Units.W, to_signed),
              "PV1 Voltage": (10, Units.V, div10),
              "PV2 Voltage": (11, Units.V, div10),
              "PV1 Current": (12, Units.A, div10),
              "PV2 Current": (13, Units.A, div10),
              "PV1 Power": (14, Units.W),
              "PV2 Power": (15, Units.W),
              "Grid Frequency Phase 1": (16, Units.HZ, div100),
              "Grid Frequency Phase 2": (17, Units.HZ, div100),
              "Grid Frequency Phase 3": (18, Units.HZ, div100),
              "Inverter Operation mode": (19, Units.NONE, cls.Processors.inverter_modes),
              # 20 - 32: always 0
              # 33: always 1
              # instead of to_signed this is actually 34 - 35,
              # because 35 =  if 34>32767: 0 else: 65535
              "Exported Power": (34, Units.W, to_signed),
              # 35: if 34>32767: 0 else: 65535
              # 36 - 38    : always  0
              "Battery Voltage": (39, Units.V, div100),
              "Battery Current": (40, Units.A, twoway_div100),
              "Battery Power": (41, Units.W, to_signed),
              # 42: div10, almost identical to [39]
              # 43: twoway_div10,  almost the same as "40" (battery current)
              # 44: twoway_div100, almost the same as "41" (battery power),
              # 45: always 1
              # 46: follows PV Output, idles around 44, peaks at 52,
              "Power Now": (47, Units.W, to_signed),
              # 48: always 256
              # 49,50: [49] + [50] * 15160 some increasing counter
              # 51: always 5634
              # 52: always 100
              # 53: always 0
              # 54: follows PV Output, idles around 35, peaks at 54,
              # 55-67: always 0
              "Total Energy": (68, Total(Units.KWH), total_energy),
              "Total Energy Resets": (69),
              # 70: div10, today's energy including battery usage
              # 71-73: 0
              "Total Battery Discharge Energy": (74, Total(Units.KWH), discharge_energy),
              "Total Battery Discharge Energy Resets": (75),
              "Total Battery Charge Energy": (76, Total(Units.KWH), charge_energy),
              "Total Battery Charge Energy Resets": (77),
              "Today's Battery Discharge Energy": (78, Units.KWH, div10),
              "Today's Battery Charge Energy": (79, Units.KWH, div10),
              "Total PV Energy": (80, Total(Units.KWH), pv_energy),
              "Total PV Energy Resets": (81),
              "Today's Energy": (82, Units.KWH, div10),
              # 83-85: always 0
              "Total Feed-in Energy": (86, Total(Units.KWH), feedin_energy),
              "Total Feed-in Energy Resets": (87),
              "Total Consumption": (88, Total(Units.KWH), consumption),
              "Total Consumption Resets": (89),
              "Today's Feed-in Energy": (90, Units.KWH, div100),
              # 91: always 0
              "Today's Consumption": (92, Units.KWH, div100),
              # 93-101: always 0
              # 102: always 1
              "Battery Remaining Capacity": (103, Units.PERCENT),
              # 104: always 1
              "Battery Temperature": (105, Units.C),
              "Battery Remaining Energy": (106, Units.KWH, div10),
              # 107: always 256 or 0
              # 108: always 3504
              # 109: always 2400
              # 110: around rise to 300 if battery not full, 0 if battery is full
              # 112, 113: range [250,350]; looks like 113 + offset = 112,
              #   peaks if battery is full
              # 114, 115: something around 33; Some temperature?!
              # 116: increases slowly [2,5]
              # 117-121: 1620	773	12850	12850	12850
              # 122-124: always 0
              # 125,126: some curve, look very similar to "42"(Battery Power),
              # with offset around 15
              # 127,128 resetting counter /1000, around battery charge + discharge
              # 164,165,166 some curves
              "Battery Operation mode": (168, Units.NONE, cls.Processors.battery_modes),
              # 169: div100 same as [39]
              # 170-199: always 0
          }
      
      @classmethod
      async def make_request(cls, host, port=80, pwd="", headers=None):
      
          url = f"http://{host}:{port}/"
          data = f"optType=ReadRealTimeData&pwd={pwd}"
      
          async with aiohttp.ClientSession() as session:
              async with session.post(url, headers=headers, data=data) as req:
                  resp = await req.read()
      
          return cls.handle_response(resp)
      

      Nun ist meine Idee die Werte aus der Curl Abfrage einfach in ioBroker Datenpunkte einzutragen, leider kenne ich mich mit der Materie noch zu wenig aus und wollte daher mal fragen ob eventuell hier jemand eine Idee hat.

      Viele Grüße
      Jan

      arteckA Offline
      arteckA Offline
      arteck
      Developer Most Active
      schrieb am zuletzt editiert von
      #2

      @jamakr4 schau dir axios mal an..damit kannst du den curl absetzen und die daten empfangen..
      dann musst du den json zerlegen..

      zigbee hab ich, zwave auch, nuc's genauso und HA auch

      1 Antwort Letzte Antwort
      0
      • Meister MopperM Online
        Meister MopperM Online
        Meister Mopper
        schrieb am zuletzt editiert von
        #3

        @jamakr4

        Ich arbeite mit dem Solax Adapter und kann damit die Daten lokal z. B. im 10-Sekundentakt abfragen. Die cloud benötige ich gar nicht.

        Proxmox und HA

        jamakr4J 1 Antwort Letzte Antwort
        0
        • Meister MopperM Meister Mopper

          @jamakr4

          Ich arbeite mit dem Solax Adapter und kann damit die Daten lokal z. B. im 10-Sekundentakt abfragen. Die cloud benötige ich gar nicht.

          jamakr4J Offline
          jamakr4J Offline
          jamakr4
          schrieb am zuletzt editiert von
          #4

          @meister-mopper Danke

          K 1 Antwort Letzte Antwort
          0
          • jamakr4J jamakr4

            @meister-mopper Danke

            K Offline
            K Offline
            kgw
            schrieb am zuletzt editiert von
            #5

            @jamakr4
            siehe hier:
            Solax Photovoltaik Portal in ioBroker

            https://forum.iobroker.net/topic/13152/solax-photovoltaik-portal-in-iobroker/10

            evtl. nützt es dir was.

            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

            589

            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