Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Q.Volt HYB-G3-1P #94

Open
TheRealZago opened this issue Nov 1, 2022 · 1 comment
Open

Add support for Q.Volt HYB-G3-1P #94

TheRealZago opened this issue Nov 1, 2022 · 1 comment

Comments

@TheRealZago
Copy link

Hi all,
After working a bit with this inverter for a quick standalone real time data monitor, I feel confident in sharing with you the schema I managed to interpret.

The API can be accessed either when connected directly to the PocketWiFi dongle, or when all connected to a network.
The API endpoint is the same as the 3-phase bigger brother (Q.Volt HYB-G3-3P), so a POST request with body optType=ReadRealTimeData&pwd={pwd} to the dongle's IP address, querying port 80 for HTTP. Too bad they don't share a single array position...

Here's the sample JSON output

{
    "sn": "[WiFi dongle SN]",
    "ver": "3.001.03",
    "type": 15,
    "Data": [
        2372,
        14,
        312,
        4995,
        2355,
        2363,
        7,
        6,
        181,
        164,
        2,
        19104,
        0,
        63,
        31660,
        0,
        0,
        27,
        96,
        3212,
        0,
        4313,
        0,
        88,
        100,
        0,
        29,
        3678,
        0,
        0,
        0,
        0,
        0,
        0,
        52344,
        1,
        1255,
        0,
        312,
        35,
        256,
        3504,
        2400,
        74,
        300,
        208,
        196,
        33,
        33,
        84,
        1,
        1,
        0,
        0,
        20874,
        0,
        65223,
        65535,
        65387,
        65535,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        2460,
        0,
        62722,
        65535,
        3600,
        0,
        61936,
        65535,
        120,
        0,
        40,
        0,
        0,
        0,
        0,
        95,
        14,
        45,
        0,
        0,
        350,
        0,
        230,
        0,
        0,
        0,
        10,
        0,
        0,
        9782,
        271,
        5643,
        1620,
        778,
        14135,
        14135,
        14135,
        0,
        0,
        0,
        1,
        3195,
        0,
        0,
        3334,
        3319,
        62928,
        20,
        20564,
        12339,
        18497,
        12866,
        18736,
        12356,
        13105,
        20564,
        12339,
        18498,
        12355,
        18740,
        12356,
        13873,
        20564,
        12339,
        18498,
        12866,
        18740,
        12356,
        12849,
        20564,
        12339,
        18754,
        12849,
        18742,
        13124,
        12338,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        1,
        2050,
        4097,
        258,
        1,
        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": [
        6,
        15,
        "[inverter SN]",
        8,
        1.29,
        0,
        1.27,
        1.03,
        0,
        1
    ]
}

So far, I've been able to identify the following fields

{
    "Network Voltage": (0, Units.V, div10),
    "Inverter output current": (1, Units.A, twoway_div10),
    "Inverter output power": (2, Units.W, to_signed),
    "Grid Frequency": (3, Units.HZ, div100),
    "PV1 Voltage": (4, Units.V, div10),
    "PV2 Voltage": (5, Units.V, div10),
    "PV1 Current": (6, Units.A, div10),
    "PV2 Current": (7, Units.A, div10),
    "PV1 Power": (8, Units.W),
    "PV2 Power": (9, Units.W),
    "Inverter Operation mode": (10, Units.NONE, cls.Processors.inverter_modes),
    "Total inverter yield": (pack_u16(11, 12), Total(Units.KWH), div10),
    "Today's inverter output yield": (13, Units.KWH, div10),
    "Battery Voltage": (14, Units.V, div100),
    "Battery Current": (15, Units.A, twoway_div100),
    "Battery Power": (16, Units.W, to_signed),
    "Battery Temperature": (17, Units.C),
    "Battery Remaining Capacity": (18, Units.PERCENT),
    # 19: seemingly monotonic, slowly growing
    # 20: always 0
    # 21: always 4313
    # 22: always 0
    "Battery Remaining Energy": (23, Units.KWH, div10),
    # 24: always 100
    # 25: always 0
    # 26-27: jumping around
    # 28-31: always 0
    # 32-33: realtime feed-in/grid power?
    "Total output to grid": (pack_u16(34, 35), Total(Units.KWH), div100),
    "Total input from grid": (pack_u16(36, 37), Total(Units.KWH), div100),
    "Current power usage": (38, Units.W, to_signed),
    # 39-115: mix of steady values, 0s, FFFFs and changing mysteries
    "Total battery energy throughput": (pack_u16(116, 117), Total(Units.WH)),
    # 118-124: BMS serial number, ASCII, little-endian, 2 chars per register
    # 125-131: Battery 1 serial number, ASCII, little-endian, 2 chars per register
    # 132-138: Battery 2 serial number, ASCII, little-endian, 2 chars per register
    # 139-145: Battery 3 serial number, ASCII, little-endian, 2 chars per register
    # 146-152: Battery 4 serial number, ASCII, little-endian, 2 chars per register
    # 153-156: ???
    "Battery Operation mode": (157, Units.NONE, cls.Processors.battery_modes),
    # 158 - 199: always 0
}

This is an afternoon's worth of data collection and interpretation. I've also managed to pick the worst day by having very little solar production, so I'll keep it running for a couple more days.
I'll open a pull request as soon as I'm done with these last sanity checks.

@TheRealZago
Copy link
Author

Alright, I've figured out a few more numbers. Pull request incoming.

One more question. I'm seeing a weird behavior with the discovery logic, specifically it's getting stuck for 5 minutes on the X3 data query, before aiohttp decides it's had enough and raises a asyncio.exceptions.TimeoutError.
Wouldn't it be advisable to set the API response timeout to something more realistic (idk, 30 seconds)? Is there any known condition where a response would take more than that to be processed?
From what I can tell, there's no explicit timeout set for the HTTP request itself, so I think it's rolling with the default OS' socket timeout.

I can circumvent the lockup by moving the HYB-G3-1P before the X3, but I have no idea how other inverters could behave.

Here's the full traceback:

zago@MintBox:~/repo/solax$ python3 test.py
Trying as <class 'solax.inverters.x_hybrid.XHybrid'>
Trying as <class 'solax.inverters.x3.X3'>
Traceback (most recent call last):
  File "test.py", line 10, in <module>
    data = loop.run_until_complete(work())
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "test.py", line 5, in work
    r = await solax.real_time_api('172.16.1.215', 80, "solarone")
  File "/home/zago/repo/solax/solax/__init__.py", line 36, in real_time_api
    i = await discover(ip_address, port, pwd)
  File "/home/zago/repo/solax/solax/discovery.py", line 42, in discover
    await i.get_data()
  File "/home/zago/repo/solax/solax/inverter.py", line 51, in get_data
    data = await self.make_request(self.host, self.port, self.pwd)
  File "/home/zago/repo/solax/solax/inverter.py", line 151, in make_request
    async with session.post(url, headers=headers) as req:
  File "/home/zago/.local/lib/python3.8/site-packages/aiohttp/client.py", line 1141, in __aenter__
    self._resp = await self._coro
  File "/home/zago/.local/lib/python3.8/site-packages/aiohttp/client.py", line 560, in _request
    await resp.start(conn)
  File "/home/zago/.local/lib/python3.8/site-packages/aiohttp/client_reqrep.py", line 914, in start
    self._continue = None
  File "/home/zago/.local/lib/python3.8/site-packages/aiohttp/helpers.py", line 720, in __exit__
    raise asyncio.TimeoutError from None
asyncio.exceptions.TimeoutError

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant