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.

@benagricola
Copy link
Author

Work ongoing.
If anyone reads this and has access to the relevant inverter and wifi module, try using socat to send magic strings to your inverter and see what you get back:

$ socat -t 3 - UDP-DATAGRAM:10.10.100.254:48899,bind=:6666
WIFIKIT-214028-READ
AT+VER
AT+SYSTIME
AT+Z # It looks like sending AT+Z at regular intervals is necessary to keep the device in AT mode

@t0nyb
Copy link

t0nyb commented Sep 26, 2022

Hello

I have a 3.6k Solis hybrid inverter and an S3 wifi stick ( regrettably )

I have tried the above commands from a linux box but get no response. But I'm not a linux guru and have never heard of socat before, so other more competent people might have different results.

Hope this helps

Tony

EDIT - I am happy to be spoon fed instructions.

@benagricola
Copy link
Author

@t0nyb first off would be to confirm if the inverter is actually on the address that the socat command assumes. Does pinging 10.10.100.254 work? If you're connected to your home wifi network then the inverter is probably on a DHCP assigned IP so you'll need to work out what that is first.

@t0nyb
Copy link

t0nyb commented Sep 28, 2022

IMG_0046

@hn
Copy link

hn commented Feb 26, 2024

This page has more info on the Solis S3 WiFi stick and the EMW3080-E SoC.

@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