pysolarmanv5

repository·main·Indexed 41 days ago

https://github.com/jmccrohan/pysolarmanv5

A Python library for interacting with Solarman (IGEN-Tech) v5 based solar inverter data loggers using a proprietary protocol over TCP port 8899. Version 3.0.6 provides both synchronous (PySolarmanV5) and asynchronous (PySolarmanV5Async) interfaces to encapsulate Modbus RTU frames. The package includes utilities such as solarman-scan for device discovery, a Solarman TCP/RTU proxy, and a frame decoder.

Tokens
9.2K
Snippets
45
Records
58
Agent score
51%

What's inside pysolarmanv5

  1. Overview of pysolarmanv5

    main

    pysolarmanv5 is a Python module designed to interact with Solarman (IGEN-Tech) v5 based solar inverter data loggers. It works by encapsulating Modbus RTU frames within the proprietary Solarman v5 protocol, which is typically sent to the data logger on TCP port 8899.

    The library provides both synchronous and asynchronous interfaces, following a pattern similar to the uModbus library.

  2. Understand the Solarman V5 Protocol

    main

    Solarman V5 is a proprietary, TCP-based protocol used by Solarman (IGEN-Tech) solar inverter data loggers to communicate locally and with the Solarman Cloud.

    Key technical details:

    • Transport: TCP-based.
    • Default Port: tcp/8899 (used by Hi-Flying HF-A11 SOCs).
    • Communication Model: By sending a correctly formed packet to the data logging stick on port 8899, you can send and receive Modbus RTU frames directly to/from the inverter without interfering with Solarman Cloud operations.
    • Endianness: All Solarman V5 fields are encoded Little Endian, except for the embedded Modbus RTU frame, which is Big Endian per the Modbus specification.
  3. Calculate Timestamps from Solarman V5 Response

    main

    When processing a response payload, you can derive meaningful timestamps using the following logic:

    1. Device Total Operation Time: Total Working Time - Power On Time (matches Solarman Cloud).
    2. Data Acquisition Timestamp: Total Working Time + Offset Time. Since pysolarmanv5 frames are real-time, this is equivalent to the current Unix timestamp.
    Device Total Operation Time = Total Working Time - Power On Time
    Data acquisition timestamp = Total Working Time + Offset Time
  4. Identify compatible Solarman v5 devices

    main
    To determine if your data logger is compatible, you can check the user-contributed list of supported devices. If your device is not listed, use the solarman_scan utility to scan your local network for compatible data logging sticks.
  5. Install pysolarmanv5

    main

    You can install the latest stable version of pysolarmanv5 from PyPI using pip. If you need the latest development version directly from the GitHub repository, you can install via git. Installing from git will also include the tools located in the /utils directory.

    # Install stable version from PyPI
    pip install pysolarmanv5
    
    # Install latest development version from git
    pip install git+https://github.com/jmccrohan/pysolarmanv5.git
  6. Use the solarman rtu proxy CLI

    main

    The solarman rtu proxy utility acts as a Modbus RTU over TCP proxy for Solarman loggers. It allows devices like Home Assistant to communicate with Solarman loggers via Modbus TCP by proxying the traffic to the logger's actual IP and serial number.

    CLI Arguments

    FlagLong NameDefaultDescription
    -b--bind0.0.0.0The IP address to listen on for incoming TCP connections.
    -p--port1502The TCP port to listen on.
    -l--loggerRequiredThe IP address of the Solarman logger.
    -s--serialRequiredThe serial number of the logger (integer).

    Home Assistant Integration Example

    You can use this proxy with Home Assistant's native Modbus integration using the following configuration:

    - name: "solarman-modbus-proxy"
      type: rtuovertcp
      host: 192.168.1.20
      port: 1502
      delay: 3
      retry_on_empty: true
      sensors:
        [...]
    python utils/solarman_rtu_proxy.py -l 192.168.1.10 -s 12345678
  7. Initialize PySolarmanV5 client

    main

    To interact with a Solarman V5 data logging stick, instantiate the PySolarmanV5 class. You must provide the IP address (or hostname) and the serial number of the data logging stick.

    Parameters:

    • address (str): IP address or hostname of the data logging stick.
    • serial (int): Serial number of the data logging stick (not the inverter).
    • port (int, optional): TCP port, defaults to 8899.
    • mb_slave_id (int, optional): Inverter Modbus slave ID, defaults to 1.
    • socket_timeout (int, optional): Socket timeout in seconds, defaults to 60.
    • v5_error_correction (bool, optional): Enable naive error correction for V5 frames, defaults to False.
    • logger (logging.Logger, optional): Custom Python logger.
    • socket (socket.socket, optional): A pre-existing TCP socket. If provided, address is unused.
    • auto_reconnect (bool, optional): If True, the client will attempt to keep the connection open. Not compatible with custom sockets.
    from pysolarmanv5 import PySolarmanV5
    
    # Basic initialization
    modbus = PySolarmanV5("192.168.1.10", 123456789)
  8. Use PySolarmanV5Async for asynchronous Solarman V5 communication

    main

    The PySolarmanV5Async class provides an asynchronous interface to interact with Solarman V5 data logging sticks via TCP. It manages a connection to the logger and allows you to send/receive Modbus RTU requests and responses asynchronously using asyncio.

    Initialization Parameters

    • address (str): IP address or hostname of the data logging stick.
    • serial (int): Serial number of the data logging stick (not the inverter).
    • port (int, optional): TCP port to connect to (defaults to 8899).
    • mb_slave_id (int, optional): Inverter Modbus slave ID (defaults to 1).
    • auto_reconnect (bool, optional): If True, the client will attempt to reconnect automatically on error.
    import asyncio
    from pysolarmanv5 import PySolarmanV5Async
    
    async def main():
        # Initialize the client
        modbus = PySolarmanV5Async("192.168.1.10", 123456789)
        
        # Connect to the data logging stick
        await modbus.connect()
        
        # Read 6 input registers starting at address 33022
        registers = await modbus.read_input_registers(register_addr=33022, quantity=6)
        print(registers)
        
        # Disconnect
        await modbus.disconnect()
    
    asyncio.run(main())
  9. Use the solarman-tcp-proxy utility

    main

    The solarman-tcp-proxy is a CLI utility that acts as a Modbus TCP to Solarman proxy. It allows devices like Home Assistant to communicate with Solarman loggers using standard Modbus TCP, even if the logger requires RTU-style communication.

    It listens on a specified TCP port, intercepts Modbus TCP frames, converts them into RTU frames (including CRC calculation), sends them to the Solarman logger via PySolarmanV5Async, and then converts the logger's RTU response back into a Modbus TCP frame for the client.

    python utils/solarman_tcp_proxy.py --logger 192.168.1.20 --serial 12345678
  10. Perform a register scan

    main

    If you are unsure of the register map for a specific device, you can use a register scan to identify available data points. This process iterates through registers to discover what information the device provides.

    # Based on ../examples/register_scan.py
    from pysolarmanv5 import SolarmanV5
    
    # Initialize client
    client = SolarmanV5('192.168.1.100', port=8899)
    
    # Execute scan
    # (Implementation details depend on the specific scan logic provided in the example)
    
    client.close()
  11. Use an asynchronous client

    main

    For high-performance applications or when managing multiple devices simultaneously, use the asynchronous client. This allows for non-blocking I/O operations using asyncio.

    # Based on ../examples/async_client_example.py
    import asyncio
    from pysolarmanv5 import AsyncSolarmanV5
    
    async def main():
        # Initialize the async client
        client = AsyncSolarmanV5('192.168.1.100', port=8899)
        
        # Perform async operations
        # await client.some_method()
        
        await client.close()
    
    if __name__ == '__main__':
        asyncio.run(main())