Modbus TCP proxy for a Huawei SUN200 inverter with Nginx

Background: Monitor all the things!

End of last year, I had solar panels and a hybrid inverter installed, in the perspective of adding a domestic battery in the future.

Due to overall supply chain issues in the world and the popularity of solar panels in Belgium, the only brand of invertir that could be supplied to me in a reasonable time was Huawei.

Although I’m wary of this brand, I decided to go for it.  I have a very segmented network and I can also fully isolate it should I have any suspicions.

I also have a Home Assistant instance running in the house and, of course, wanted to get information out of the inverter and into HA to be able to know how well my panels were performing and be able to act upon availability of extra production.

Problem: WiFi all the things?

Natively, the SUN2000 inverter exposed a Modbus inverter that can be contacted through three ways:

  • An embedded an Wireless Access Point that has a very limited range.
  • The RS485 port, that can also be used to fit an additional WiFi/Ethernet (with much better range, the Smart Dongle A05) or LTE module to provide improved connectivity.

I did not order the latter dongle when ordering the rest of the hardware, and its availability is anyway very limited.

The unofficial Home Assistant integration for the SUN2000 details how to wire a Modbus TCP to Ethernet adapter working, but that was not an option for me – I’ll need that port when adding the domestic battery (probably next year).

I was thus left with the built-in WiFi.  And when I say the range is poor, I really mean it.  My initial attempt was to add a Wireless dongle on my HA server, which is located about 10 meters away from the inverter, and connect to the inverter WiFi.

I did get that to work, but with very poor signal, resulting in frequent disconnects that could only be solved with manual reconnects. 

Moreover, the inverter also had a second WiFi circuit acting as a wireless station to get online connectivity, which really did not really work properly either with my WiFi AP located close to the HA node.  That small WiFi antenna is really just for looks…

Attempt 1: Get a SDongle-A05

After a bit of digging around, I got my hands on an SDongle-A05 through eBay.

My hopes for a simple solution were quickly destroyed.  Yes, the dongle was immediately recognized and, finally, my inverter got reliable network connectivity through Ethernet.

However, I was never able to make the Modbus TCP connection work through that network interface, so my core problem was not solved.  After an infuriating Sunday of digging around and trying tons of things, I decided enough was enough and another solution was needed.

Attempt 2: Nginx TCP Proxy

Disregarding the range problem, connecting via the built-in AP of the inverter had proven to be reliably working for several months.  I thus decided to handle this issue another way : if I can’t get to connect to my network, I’ll proxy the connection via a more reliable hardware network-wise.

I had some Raspberry Pi 3B+’s lying around, so I decided I had the perfect candidate for a proof-of-concept.

What I needed was a transparent TCP proxy that would simply pass packets from one side to another without any other form of transformation.  I quickly found out Nginx is the perfect candidate.

I whipped up Raspberry Pi OS on an SD card, configured WPA supplicant to connect to the inverter built-in WiFi and got exactly where I wanted to be network-wise:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:27:eb:a1:c1:19 brd ff:ff:ff:ff:ff:ff
    inet 172.16.38.244/24 brd 172.16.38.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::59e5:8639:bd95:e042/64 scope link
       valid_lft forever preferred_lft forever
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:27:eb:f4:94:4c brd ff:ff:ff:ff:ff:ff
    inet 192.168.200.2/24 brd 192.168.200.255 scope global noprefixroute wlan0
       valid_lft forever preferred_lft forever
    inet6 fe80::2925:5d44:2f59:867f/64 scope link
       valid_lft forever preferred_lft forever

Important note: I had Ethernet connectivity available in the room where the inverter sits.  If that’s not your case, you’ll need a USB WiFi adapter for the RPI.

Next, we need to configure Nginx.  The TCP Proxy sits at the same level as the http environment, meaning you’ll need to place your directives either in nginx.conf itself or a file it refers.

I took the second approach.  My /etc/nginx/nginx.conf file contains the following:

...

http {
....
}

include /etc/nginx/proxy.conf;

And the /etc/nginx/proxy.conf consists of a simple stream proxy directive:

stream {
    server {
        listen     172.16.38.244:6607;
        proxy_pass 192.168.200.1:6607;
        proxy_bind 192.168.200.2:6607;
    }
}

And voilà !  Restart Nginx and you’re done.  You can now point Home Assistant to the IP address of the RPI for the SUN2000 integration, and you’ll see packets flowing back and forth the inverter.

This has been running without hiccups for a few months.  I’ll replace the RPI for a Rock Pi S that pulls even less power, but the principle will remain the same.

Add a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.