Skip to content

Instantly share code, notes, and snippets.

@benagricola
Last active March 18, 2024 13:47
Show Gist options
  • Save benagricola/0684dccd9b7f235451f73575d64c82e6 to your computer and use it in GitHub Desktop.
Save benagricola/0684dccd9b7f235451f73575d64c82e6 to your computer and use it in GitHub Desktop.
Working out how to enable Modbus over TCP on Solis RHI-3.6K-48ES-5G inverter with datalogger S3-WIFI-ST - without having either.

Intro

Data from this issue indicates that the wifi dongle uses a MXCHIP EMW3080-E SOC.

Searches for that model number found a bunch of useful issues, including the MX Guide which contains a list of AT commands that might be supported by the module.

Further digging indicated that Solis has an App that they use to configure the logger, called Solis Cloud

Steps

  • Decompile the APK using jadx-gui. Look for any hints of bluetooth or wifi connectivity configuration and AT commands

com.ginlongcloud.activity.YJPWYZDeployActivity:

// These are not original names due to decompilation.
public String dongleIP = "10.10.100.254";
public String configPort = "48899";
public String magicString = "WIFIKIT-214028-READ";
public String okRes = "+ok";
public String verRes = "AT+VER\r\n";
public String ssidCmd = "AT+WSSSID=ck01\r\n";
public String sKeyCmd = "AT+WSKEY=WPA2PSK,AES,18881888\r\n";
public String wifiModeStationCmd = "AT+WMODE=STA\r\n";
public String zCmd = "AT+Z\r\n";
public String softApNet = "10.10.100.";

This file looks promising.

  • Work out how AT commands are sent to the chip to start configuration

com.ginlongcloud.activity.YJPWYZDeployActivity:

public final void DoSend(String str) {
    // sendInfo is not important - looks like it might be used for logging
    String str2 = "sendInfo: " + str;
    new TrySend(str).start();
}

<unknown>.<unknown>.<unknown>.SocketHandlerThread:

public void ReceivePacket() {
    DatagramPacket datagramPacket = new DatagramPacket(new byte[63], 63);
    while (true) {
        DatagramSocket datagramSocket = this.socket;
        if (datagramSocket == null) {
            return;
        }
        try {
            datagramSocket.receive(datagramPacket);
            String str = new String(datagramPacket.getData(), datagramPacket.getOffset(), datagramPacket.getLength());
            this.recvd = str;
            if (!CommandValidator.validate(str)) {
                C12627c.m1167c().m1160j(new WIFIEvent(this.recvd)); // Send as WIFI EVENT
            }
            this.handler.sendEmptyMessage(0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public void sendPacket(InetAddress inetAddress, int i, String str) {
    try {
        this.socket.send(new DatagramPacket(str.getBytes(), str.length(), inetAddress, i));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override // java.lang.Thread, java.lang.Runnable
public void run() {
    ReceivePacket();
    super.run();
}

Easy. Plaintext sent over UDP. Unsurprisingly to <dongleIP>:<configPort> or 10.10.100.254:48899.

  • Find out if there's any preconfiguration done before sending AT commands

com.ginlongcloud.activity.YJPWYZDeployActivity:

public void InitView() {
    super.InitView();
    ...
    SocketHandlerThread socket = new SocketHandlerThread(this.View);
    this.socket = socket;
    socket.start();
    GetCurrentWifiNetworkDetails();
    ScanWifiNetworks();
    this.command = 1;
    DoSend("WIFIKIT-214028-READ");
}

That WIFIKIT-214028-READ string looks interesting. It looks like it's sent to the wifi dongle on configPort, and is labelled as command 1.

It also looks like it's sent after the wifi network is reconfigured. So maybe it's a trigger string that needs to be sent before AT commands can be used.

There's also reference to a HF-A11ASSISTHREAD string which upon searching the internet, finds a ton of info including this which goes very in depth on how the discovery / AT protocol system works.

@mooky31
Copy link

mooky31 commented Mar 18, 2024

Hello,
I have a Solis HI-6K-48ES-5G-DC and a S3-WIFI-ST.
I would be very interested in making them work with solarman.
So if I can help you in any way, just ask me.

@mooky31
Copy link

mooky31 commented Mar 18, 2024

I tried to pass the socat commands, port 48899 seems to be closed :

mooky@nas:~$ socat -t 3 - UDP-DATAGRAM:192.168.20.106:48899,bind=:6666
WIFIKIT-214028-READ

mooky@nas:~$ sudo tcpdump -nei p10p1 host 192.168.20.106
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on p10p1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
14:40:18.240793 a8:a1:59:ab:c2:1a > d0:ba:e4:8d:3b:96, ethertype IPv4 (0x0800), length 62: 192.168.20.200.6666 > 192.168.20.106.48899: UDP, length 20
14:40:18.242994 d0:ba:e4:8d:3b:96 > a8:a1:59:ab:c2:1a, ethertype IPv4 (0x0800), length 70: 192.168.20.106 > 192.168.20.200: ICMP 192.168.20.106 udp port 48899 unreachable, length 36

HTTP port is opened, I can login using admin/pass of my wifi SSID.
Very few information/configuration available on the web interface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment