Skip to content

hn/ginlong-solis

Repository files navigation

Ginlong Solis solar inverters

Preamble

Ginlong Solis is one of the world's recognised manufacturers of string solar inverters. Almost all of their products have an Modbus RS-485 interface for reading live status and statistics.

Quick start, you'll find here:

The ESPHome solution also has some advanced features such as limiting the inverter output power, synchronising the inverter time via NTP and more.

If in doubt, I recommend choosing the Solis S3 stick with the alternative firmware. You can currently buy the Solis S3 stick for about 20 € and get a rugged, waterproof case, external antenna, etc. For this price you can not buy and assemble the individual parts.

Please do me a favor: 👍 If you use any information or code you find here, please link back to this page. ⭐ Also, please consider to star this project. I really like to keep track of who is using this to do creative things, especially if you are from other parts of the world. 😃 You are welcome to open an issue to report on your personal success project and share it with others.

Solis ESPHome sample screen

ESP8266 Solis interface

Hardware

You need a proprietary Exceedconn EC04681-2014-BF connector (available on Ebay) and an RS485-to-serial adapter (a cheap one without DE/RE pins is sufficient, e.g. the HW-0519, XY-K485 or XY-017). Wire all components to e.g. a Wemos D1 mini (also available as 'pro' variant with an SMA connector and external antenna for better reception) as follows:

Solis ESP8266 wiring

A bit strange, you have to connect the RX pin of the HW-0519 adapter to the RX pin of the ESP (and the TX pin to the TX pin), so no RX-TX-crossover like normal.

Software (ESPHome)

Especially recommended if you use Home Assistant, solis-esphome-esp8266.yaml is an ready-to-use configuration file for ESPHome, using an ESP8266. With the ESPHome dashboard you can easily set up your system with just a few clicks via a user-friendly web interface.

Software (Arduino)

With solis2influx.ino one can read out all inverter data (status and statistics) via Modbus and push it to InfluxDB. It uses WiFiManager to setup WiFi, so you have to connect to the SOLIS2INFLUX access point with your mobile phone first.

The reading of the data starts immediately after configuring WiFi. The data is not sent to the InfluxDB server until the inverter's serial number has been read, which may take a moment (the serial number is added as a mandatory tag to distinguish multiple inverters):

DC voltage 1 = 243.70V
DC current 1 = 0.90A
Inverter temperature = 22.50°C
Grid frequency = 49.98Hz
Writing to influxDB: solis,serialnumber=1801020221230123 DC\ voltage\ 1=243.70,DC\ current\ 2=0.90,Inverter\ temperature=22.5,Grid\ frequency=49.98
Energy last month = 234kWh
Energy today = 1.23kWh
Energy last day = 3.45kWh
Writing to influxDB: solis,serialnumber=1801020221230123 Energy\ last\ month=234i,Energy\ today=1.23,Energy\ last\ day=3.45

Solis S3 WiFi Data Logging Stick (3rd gen)

The WiFi stick is Solis' current solution for connecting the inverter to their 'SolisCloud' platform (which is operated by Alibaba China). You can recognise the 3rd gen stick by the three LEDs on the front and the reset button on the back.

Software

The firmware of the stick offers support for connecting the stick to the home WiFi and displays basic inverter statistics. The firmware (at least the current version 1012F) is a kind of beta and incomplete, as it lacks important functions that are available in the previous generation WiFi sticks. In particular, support for setting a second remote logging server (called "Server B") is missing.

The web interface is protected by HTTP simple auth with fixed username admin and password 123456789. After connecting the stick to your home WiFi the web password changes without notice to your WiFi password. So you need to login to the web admin interface with admin and your WiFi password. This somewhat wierd behaviour again shows the immature state of the firmware.

Since the current firmware does not support setting up your own remote logging server, there is solis2influx.pl to read basic statistics from the web interface (/inverter.cgi) and publish this information in an influx db.

The stick firmware is based on Alibaba's AliOS-Things 3.0.0 embedded operating system (not sure if some parts of MXCHIPS's MiCO OS were been mixed in). It uses hardcoded DNS servers (public1.alidns.com and public2.alidns.com) and frequently pushes data to *.iot-as-mqtt.*.aliyuncs.com (this server is chosen depending on your geolocation).

Hardware

The stick hardware is based on MXCHIP's EMW3080-E MCU (ARM Cortex-M4F, 2.4G Hz IEEE 802.11 b/g/n WiFi, Suffix -E denotes IPEX antenna, MX1290 processor). Datasheet: V2.2.

✋ Contrary to all available datasheets, the EMW3080-E (at least the one in my Solis S3 stick) does not have 2MB flash installed, but an 8MB flash module.

The EMW3080 is some kind of relabeled (call it the same family) RTL8710BN MCU (Ameba-Z series). One can find more info about the EMW3080 at A_D Electronics and a discussion at esp8266.ru.

The stick is connected to the inverter via a type of proprietary Exceedconn EC04681-2014-BF connector (circular pin arrangement: 1=VCC=5V, 2=GND, 3=RS485+, 4=RS485-) . The external antenna is connected via a standard SMA connector. You can open the case by pressing the notches towards the centre of the stick.

Solis WiFi Stick PCB Front Solis WiFi Stick PCB Back

There is a serial interface (LogCLI) on the PCB connected to UART2_Log_TX and UART2_Log_RX of the MCU (115200 8N1, 3.3 Volt).

Update: Since end of 2022 there is a new PCB version which contains a hardware watchdog. You can recognize these new boards by the silkscreen '22.34' (which probably corresponds to the year and week of manufacture) .

Analysis via the serial port

You get a first impression when you examine the UART2_Log output:

ROM:[V0.1]
FLASHRATE:4
BOOT TYPE:0 XTAL:40000000
IMG1 DATA[1128:10002000]
IMG1 ENTRY[800053d:100021ef]
IMG1 ENTER
CHIPID[000000ff]
read_mode idx:2, flash_speed idx:2
calibration_result:[1:19:13][3:15]
calibration_result:[2:21:11][1:15]
calibration_result:[3:1:1][1:1]
calibration_ok:[2:21:11]
FLASH CALIB[NEW OK]
OTA2 ADDR[8100000]
OTAx SELE[ffffffff]
OTA1 USE
IMG2 DATA[0x800f1c0:36:0x10005000]
IMG2 SIGN[RTKWin(10005008)]
IMG2 ENTRY[0x10005000:0x800b105]
BOOT_FLASH_RDP RDP enable
RDP bin decryption Failed!
checksum_ipsec = 0x46956286, checksum_rdp_flash = 0x80d838a
2ndboot image start

Press key 'w' to 2ndboot cli menu in 100ms.
122: ota crc cal:0x7a1a param:0xffff
17: ota upg_flag:0xffffcount:0 crc;0xffff
30: No OTA upgrade.

See the full (anonymized) bootlog for more details.

When holding the 'w' key during boot an extremely limited 2ndboot CLI starts:

2ndboot image start 

Press key 'w' to 2ndboot cli menu in 100ms.
2ndboot ver: 2ndboot-1.0.0-20210917.200018
Please input 1-2 to select functions
[1] Uart Ymodem Upgrade 
[2] System Reboot 
[h] Help Info
2ndboot# h 
2ndboot ver: 2ndboot-1.0.0-20210917.200018
Please input 1-2 to select functions
2ndboot# 

When pulling TX pin 21 (PA_30) low during boot, the device waits for a xmodem transfer (UART boot mode):

ROM:[V0.1]
FLASHRATE:4
UARTIMG_Download 2
Open xModem Transfer on Log UART...

When the device is in this mode, one can download the firmware using RTLtool (depends on Python2) (Update: ltchiptool is now a better option):

$ python2 ./rtltool.py -p /dev/ttyUSB0 gf
Connecting...
Flash Status value: 0x40
$ python2 ./rtltool.py -p /dev/ttyUSB0 rf 0x8000000 0x800000 dump-0x8000000-0x800000.bin
Connecting...
Read Flash data from 0x08000000 to 0x08800000 in file: dump-0x8000000-0x800000.bin ...
Done!

Analysis of the memory content (firmware 1012F)

The dump contains all kinds of interesting stuff (AOS-R-3.0.0 and sdk-c-3.0.1 clearly link to AliOS-Things 3.0.0). With the help of Realtek AmebaZ Memory Layout, Introduction to Ameba-Z SDK and mk3080/flash_partitions.c one can reconstruct the flash partition table found at address 0x800e320:

DESCRIPTION     START_ADDR    LENGTH
Bootloader      0x0           0x8000        // = AliOS-Things/platform/mcu/rtl8710bn/bin/boot_all.bin
Recovery        0xb000        0x6000        // 2ndboot
Application     0x19000       0x127000
OTA Storage     0x150000      0x127000
Parameter1      0x2a0000      0x2000
Parameter2      0x2a2000      0x2000        // WiFi credentials @ 0x2a3000
Parameter3      0x2a4000      0x2000        // AliOS PK+PS+DN+DS
Parameter4      0x2a6000      0x2000
Parameter5      0x2a8000      0x10000
Parameter55     0x2b8000      0x1000
Parameter33     0x7fe000      0x1000        // Backup of Parameter3 ?
Offline         0x300000      0x4fe000      // 0x1000 zeros + some noise

Playing with the Alibaba IOT Platform

Partition 'Parameter3' contains the 'Product Key' (PK) and 'Device Secret' (DS) needed to connect to the Alibaba IOT Platform. The serial number of the stick is used as 'Device Name' (DN). With the Link SDK for Python you can easily impersonate as the inverter and send MQTT data to the SolisCloud.

Analysis of the main application (firmware 1012F)

The main application starts at 0x19000 with a TEXT segment for flash in place execution (XIP). It is followed by a DATA segment for RAM execution. I will refer to this part as 'APP1'.

The complete APP1 in OTA package format (including checksums) starts at 0x19000 with length 797628 and MD5 checksum 0a88cb5556ab28ffba63a8d56e131d56. With decode-alios-ota-firmware.pl one can view all details and validate the checksums:

$ ./decode-alios-ota-firmware.pl solis-s3-app-1012F_ota.bin
# Segment .text
  0x00000000:  Signature        = 0x3831393538373131 (OK)
  0x00000008:  Code length      = 790112
  0x0000000c:  Address          = 0x00000000 (FLASH XIP)
  0x00000010:  Reserved         = 0xffffffffffffffffffffffffffffffff
  0x00000020:  Code             = (byte code)

# Segment .data
  0x000c0e80:  Signature        = 0x3831393538373131 (OK)
  0x000c0e88:  Code length      = 7420
  0x000c0e8c:  Address          = 0x10005000 (RAM)
  0x000c0e90:  Reserved         = 0xffffffffffffffffffffffffffffffff
  0x000c0ea0:  Code             = (byte code)

# Segments checksum
  0x000c2b9c:  Checksum         = 0x25249404 (OK)

# OTA trailer
  0x000c2ba0:  Magic            = 0xefefefef (OK)
  0x000c2ba4:  Size             = 797600 (OK)
  0x000c2ba8:  MD5 checksum     = 0x85a615f88804cfb7784ffab81c27795b (OK)
  0x000c2bb8:  Reserved         = 0xffffffff

# End of data
  0x000c2bbc:  Filesize         = 0xc2bbc = 797628 (OK)

Somewhat unexpectedly, the APP1 part is followed by a second app ('APP2') starting with TEXT at 0xdbbbc (length 222276) and DATA at 0x112020 (length 3656). This APP2 is binary identical to AliOS ate.bin. It is currently not clear whether it is being used at all, there is a suspicion that it is an ATE firmware for Automatic test equipment or to set eFuses/RDP.

Tampering with the main application (firmware 1012F)

With knowledge of the source code it is easy to locate the corresponding byte code in the dump. For example, the Mbed TLS wrapper code

if (ca_crt != NULL) {
   mbedtls_ssl_conf_authmode(&(pTlsData->conf), MBEDTLS_SSL_VERIFY_REQUIRED);

corresponds to the binary

0803fb86 ba f1 00 0f     cmp.w      r10,#0x0
0803fb8a 2f d0           beq        LAB_0803fbec
0803fb8c 02 21           movs       r1,#0x2		// 0x2 = MBEDTLS_SSL_VERIFY_REQUIRED
0803fb8e 2e e0           b          LAB_0803fbee

So, if you change value 02 21 to 00 21 (0x0 = MBEDTLS_SSL_VERIFY_NONE) at offset 0x3fb8c, the destination SSL certificate will not be checked anymore and you can man-in-the-middle or redirect the SSL traffic (MQTT, HTTP, ... to Alibaba cloud).

When writing to the flash with RTLtool (wf cmd), make sure to always write full 4096 bytes aligned data blocks (flash SECTOR_SIZE 0x1000).

⚠️ Warning: Obviously writing to the flash memory is dangerous and may permanently damage your device.

Replacing the main application

Thanks to the fine folks at LibreTiny, arduino-compatible cores for RTL8710B chips are available. And even better, LibreTiny is now part of ESPHome. With solis-esphome-emw3080.yaml you can read out all relevant status and statistics data from your Solis inverter and push it to Home Assistant.

Install the ESPHome firmware for the S3 stick as follows:

  1. Install the ESPHome dashboard for Home Assistant (at least version 2023.9.0).
  2. If you not already have one, add a secrets.yaml to the ESPHome addon, containing at least wifi_ssid, wifi_password, wifi_ap_ssid, wifi_ap_password, api_encryption_key and ota_password.
  3. Add solis-esphome-emw3080.yaml to the ESPHome addon.
  4. Depending on your inverter type, copy one of solis-modbus-inv.yaml or solis-modbus-esinv.yaml as well.
  5. Within solis-esphome-emw3080.yaml edit inverter type (include statement within packages section).
  6. Click the three-dots button, then "Install" and "Manual Download".
  7. Wait for the compilation process to finish and download the "UF2 package".
  8. Set the MCU to UART boot mode (pull TX pin low during boot -- you do not need to solder, just inserting some jumper wires is sufficient). Make sure your serial adapter uses 3.3V voltage, read the notes below carefully about possible challenges with these adapters.
  9. Backup the stock firmware with ltchiptool (also available as a Win GUI version):
    $ ltchiptool -V
    ltchiptool v4.10.1 # use at least this version
    $ ltchiptool flash read -d /dev/ttyUSB0 RTL8710B solis-s3-firmware-1012f.bin
    I: Connecting to 'Realtek AmebaZ' on /dev/ttyUSB0 @ 1500000
    I: Reading Flash (8 MiB)
    $ ls -l solis-s3-firmware-1012f.bin
    8388608 # file size should be exactly this, otherwise something has gone wrong
    
  10. Flashing the ESPHome image (replacing stock AliOS 2ndboot and main app altogether) is as simple as
    $ ltchiptool flash write -d /dev/ttyUSB0 solis-emw3080.uf2
    

After flashing, you can reconnect the S3 WiFi stick to the inverter and the status data will magically appear in Home Assistant. For subsequent updates you can simply OTA-upload the firmware via the ESPHome addon.

⚠️ Warning: Obviously writing to the flash memory is dangerous and may permanently damage your device. Be careful and keep children away.

⚠️ It is recommended to use a good FTDI FT232RL USB serial adapter for dumping and flashing. Other adapters may have problems with the required high transfer rate. In some cases, the serial adapter or USB port does not supply enough power to flash the stick, then try a different adapter or USB port.

💡 This integration uses a patched version of the ArduinoCore-API. This workaround is necessary until libretiny-eu/libretiny#154 is fixed.

💡 Matching the EMW3080 datasheet, one should actually use the generic-rtl8710bn-2mb-788k board profile for LibreTiny. But since the Solis WiFi stick has a special 8MB version of the MCU with an OTA address of 0x100000, the not exactly matching profile generic-rtl8710bx-4mb-980k is used here, manually setting the MCU type and frequency in the PlatformIO options to the correct value.

Solis Modbus Register Map and RS-485 documentation

Solis products feature (at least) two different Modbus register maps, the ESINV (energy storage inverter) map mostly uses registers in the 3xxxx (ten-thousands) range and the INV (inverter) map uses the 3xxx (thousands) range. It is probably a good practice (not thoroughly tested) to query register 35000 ("inverter type definition") and act according to the first two decimal places of the read value (the documentation says: "high 8 bit means protocol version, low 8 bit means inverter model", but I think this is only correct if you interpret it as some kind of 'decimal bits'):

For the INV 3xxx Register Map, you'll need to subtract offset 1 from addresses before transmitting on the bus (see explanation in section 5.3 of the document).

Dr. Brian Coghlan initially translated the ESINV-Modbus inverter communication protocol from chinese to english in 2018, but it now seems to me to have been superseded by the official versions from Solis linked above.

Misc

Credits