Hoymiles DTU microinverters (PV)

Hi

Typical solar plants have big/noisy inverter with an API. In my situation I choose micro-inverters technology… without API.
BUT… if there is a needs - there must be a solution :slight_smile:

In typical instalation there is an DTU unit, which monitor each inverter (and panel) and send’s data to vendor portal (for service). https://www.hoymiles.com/keqiao/products/DTU-MI
Access to this device is simple - just by browser…

Each data which are displayed on browser goes from small CSV file (named by vendor - hometable.xml).

The problem is that url is not typical HTTP/1.1 but old HTTP/0.9 which is not readable by hassio. Solution is to use curl and stream JSON data to Hassio.

Both scripts:
Python to get data from Hoymiles
and JSON template to define sensors are published on my Git

This is basic version - if you have some ideas - or someone would make a module out of it - that would be great :slight_smile:

2 Likes

any chance for tutorial? :wink:

1 Like

Hi… What do you expect???

As I said - details about panels usage are in file http://DTU_IP/hometable.xml
Rest is solution to get those data for example each 5 minutes and share with hassio

I created a python script which solve it. everything on my GitHub…

Not much online about how to interface with these devices. I’m hoping someone will have tried this with the DTU-Pro model. So far, I haven’t found anything for my particular device. Even a cloud-based solution would be acceptable, but retrieving the data locally would be the icing on the cake.

1 Like

Hi Steve

DTU didn’t have any API (official). But. Their simple web interface has some engine which can be helpfull
Data on GUI are combined with template and raw data from environment. Those data are automatically downloaded live from DTU using CSV.
Name of this CSV file is /hometable.xml … don’t worry it is not XML just CSV

There is one notice - this file is available thru old HTTP/0.9 protocol. to download it using curl you must use additional flag --http0.9

Please check this documentation: Ubuntu Manpage: curl - transfer a URL

The only port open on my device is “12345”, which I’ve tried adjusting the curl command to hit, but it does nothing.

Did we really need the DTU-Pro or the USB-DTU.

I own just a single trina-solar panel with 330W peak and buying a dtu would cost me more than the half of my whole mini-solar system.
Did they use Zigbee or did they use another prop. wireless protocol? Is it hackable?

By the way, here is a github project:

Found in:

Will this work on HA OS installation? When I try to execute the .py commands I get an error saying “command not found”.
It would be helpful if You could provide a simple installation guide (where to put the files, which params to set, etc.)
It would be absolutely fantastic if You can tell us how to integrate this with the new HA Energy Dashobard!

1 Like

Hi,
I have approached this using nodered and curl command. The solution is much simpler and is stays local (meaning - no need to any passwords, accounts, etc - getting data directly from DTU unit)

Seems like a perfect solution.
Which DTU do you have? For what I’w seen only the Pro one have a integrated web server.
Do you have an installator account, or just a user one?
It looks like we might share the same installation type: three wires, 9kw solar panels, and a huge need to monitor everything.
I’m stuck with a closed-cloud service for the moment (Comwatt, French Cie, crappy spirit…) for the solar monitoring, but would be really happy to change. Your solution seems like a perfect fit.

Hi,

I have DTU-100 (not Pro). I don’t have an installer account BUT - You don’t need any account here as You’re only accessing the web interface of the DTU (on local network).

So, I can simply type in the local url like http://192.168.12.210 and the home page of the DTU is displayed (where all data is displayed). From then on - all I needed to do is get the page contents via http request and parse the results. Most of that is done by nodered. The biggest “trick” in my case was that they use some weird HTPP/0.9 protocol which means that standard GET commands in http requests don’t work…

Anyway - for me, I only need some basic parameters like Total Energy, Total Power, etc. (which are provided in first columns) - but if You play with it You can get data for each panel or whatever You see on the screen (and e.g. create automation for when something is wrong with it).

The IMPORTANT part for mee is that NO INTERNET connection is needed!

I’ve included the code for the NodeRed flow also:

[
    {
        "id": "b52d74e9be54c49b",
        "type": "tab",
        "label": "PV",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "e1ca176c6ebb0e6f",
        "type": "exec",
        "z": "b52d74e9be54c49b",
        "command": "curl 192.168.12.210/hometable.xml --http0.9",
        "addpay": "",
        "append": "",
        "useSpawn": "false",
        "timer": "1",
        "winHide": false,
        "oldrc": false,
        "name": "",
        "x": 370,
        "y": 160,
        "wires": [
            [
                "487410fb842d2664"
            ],
            [
                "4848185b98be45aa"
            ],
            [
                "b31bdde29ea31f7e"
            ]
        ]
    },
    {
        "id": "95773632b7258564",
        "type": "inject",
        "z": "b52d74e9be54c49b",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "60",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "ping",
        "payloadType": "str",
        "x": 110,
        "y": 160,
        "wires": [
            [
                "e1ca176c6ebb0e6f"
            ]
        ]
    },
    {
        "id": "bdb103f2ea61cc72",
        "type": "debug",
        "z": "b52d74e9be54c49b",
        "name": "Debug",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1250,
        "y": 140,
        "wires": []
    },
    {
        "id": "b31bdde29ea31f7e",
        "type": "debug",
        "z": "b52d74e9be54c49b",
        "name": "Return code",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 690,
        "y": 280,
        "wires": []
    },
    {
        "id": "4848185b98be45aa",
        "type": "debug",
        "z": "b52d74e9be54c49b",
        "name": "Errors",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 670,
        "y": 200,
        "wires": []
    },
    {
        "id": "487410fb842d2664",
        "type": "function",
        "z": "b52d74e9be54c49b",
        "name": "Convert to String",
        "func": "msg.payload = msg.payload.toString();\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 670,
        "y": 140,
        "wires": [
            [
                "5b528da2128633eb"
            ]
        ]
    },
    {
        "id": "5b528da2128633eb",
        "type": "csv",
        "z": "b52d74e9be54c49b",
        "name": "Select data",
        "sep": ";",
        "hdrin": false,
        "hdrout": "all",
        "multi": "one",
        "ret": "\\n",
        "temp": "power_total,energy_total,energy_today",
        "skip": "0",
        "strings": true,
        "include_empty_strings": false,
        "include_null_values": false,
        "x": 850,
        "y": 140,
        "wires": [
            [
                "da66d7eb327f9284",
                "0ffdb0c2167f20ce",
                "7749b410bd7be18b"
            ]
        ]
    },
    {
        "id": "da66d7eb327f9284",
        "type": "ha-entity",
        "z": "b52d74e9be54c49b",
        "name": "DTU Energy Today",
        "server": "9847e1812fb1326f",
        "version": 2,
        "debugenabled": false,
        "outputs": 1,
        "entityType": "sensor",
        "config": [
            {
                "property": "name",
                "value": "dtu_energy_today"
            },
            {
                "property": "device_class",
                "value": "energy"
            },
            {
                "property": "icon",
                "value": ""
            },
            {
                "property": "unit_of_measurement",
                "value": "kWh"
            },
            {
                "property": "state_class",
                "value": "total_increasing"
            },
            {
                "property": "last_reset",
                "value": ""
            }
        ],
        "state": "payload.energy_today",
        "stateType": "msg",
        "attributes": [],
        "resend": true,
        "outputLocation": "payload",
        "outputLocationType": "msg",
        "inputOverride": "allow",
        "outputOnStateChange": false,
        "outputPayload": "$entity().state ? \"on\": \"off\"",
        "outputPayloadType": "jsonata",
        "x": 1050,
        "y": 200,
        "wires": [
            [
                "bdb103f2ea61cc72"
            ]
        ]
    },
    {
        "id": "0ffdb0c2167f20ce",
        "type": "ha-entity",
        "z": "b52d74e9be54c49b",
        "name": "DTU Power Total",
        "server": "9847e1812fb1326f",
        "version": 2,
        "debugenabled": false,
        "outputs": 1,
        "entityType": "sensor",
        "config": [
            {
                "property": "name",
                "value": "dtu_power_total"
            },
            {
                "property": "device_class",
                "value": "power"
            },
            {
                "property": "icon",
                "value": ""
            },
            {
                "property": "unit_of_measurement",
                "value": "kW"
            },
            {
                "property": "state_class",
                "value": "measurement"
            },
            {
                "property": "last_reset",
                "value": ""
            }
        ],
        "state": "payload.power_total",
        "stateType": "msg",
        "attributes": [],
        "resend": true,
        "outputLocation": "payload",
        "outputLocationType": "msg",
        "inputOverride": "allow",
        "outputOnStateChange": false,
        "outputPayload": "$entity().state ? \"on\": \"off\"",
        "outputPayloadType": "jsonata",
        "x": 1050,
        "y": 80,
        "wires": [
            [
                "bdb103f2ea61cc72"
            ]
        ]
    },
    {
        "id": "7749b410bd7be18b",
        "type": "ha-entity",
        "z": "b52d74e9be54c49b",
        "name": "DTU Energy Total",
        "server": "9847e1812fb1326f",
        "version": 2,
        "debugenabled": false,
        "outputs": 1,
        "entityType": "sensor",
        "config": [
            {
                "property": "name",
                "value": "dtu_energy_total"
            },
            {
                "property": "device_class",
                "value": "energy"
            },
            {
                "property": "icon",
                "value": "mdi:infinity"
            },
            {
                "property": "unit_of_measurement",
                "value": "kWh"
            },
            {
                "property": "state_class",
                "value": "total_increasing"
            },
            {
                "property": "last_reset",
                "value": ""
            }
        ],
        "state": "payload.energy_total",
        "stateType": "msg",
        "attributes": [],
        "resend": true,
        "outputLocation": "payload",
        "outputLocationType": "msg",
        "inputOverride": "allow",
        "outputOnStateChange": false,
        "outputPayload": "$entity().state ? \"on\": \"off\"",
        "outputPayloadType": "jsonata",
        "x": 1050,
        "y": 140,
        "wires": [
            [
                "bdb103f2ea61cc72"
            ]
        ]
    },
    {
        "id": "9847e1812fb1326f",
        "type": "server",
        "name": "Home Assistant",
        "version": 2,
        "addon": false,
        "rejectUnauthorizedCerts": false,
        "ha_boolean": "y|yes|true|on|home|open",
        "connectionDelay": true,
        "cacheJson": true,
        "heartbeat": false,
        "heartbeatInterval": "30"
    }
]

Good luck!

Exactly what I need. So you managed to add all the inverters without any account? The gateway I found is the W100, with a USB stick form factor, is that the one?
And do you know then what is the purpose of the pro account?

Anyway, thank you very much for your answers, at least I know that I’ll be able to gather data on my little solar farm.

Hello Papi77
Just received my DTU, but the pro version, just because it was faster. (I’m way too geek to wait!) The W100 (USB stick form factor) should arrive in about 10 days.
Did a company installed your DTU in first place? Or you bought the DTU, and did your own install? Because I have no way to setup my solar installation, or to scan for panels. I can login in the DTU, I have access to the main page of the DTU, but nothing related to the solar installation.
Any clever tip from your side?
Cheers

Well, for those waiting for more informations, I received 2 DTU: the W100 and the Pro. I’m unable to find the DTU-100 Papy77 is using. And so far no luck. I’ve found an installer account to set everything up, but:
The W100 (the usb stick for factor) do not have a local webserver, it only pushes data to the hoymiles website.
The Pro has a local webserver, but only to setup the wifi and a few other settings, but nothing regarding the inverters data.
So pissed that nowadays you have to rely on a cloud solution to access local data.

edit:

Well I’m continuing my monologue in case someone has an idea.
I’m sending back the Pro version, keeping the W100 to feed the cloud (yurk)
I might have found the DTU-100 to follow the Papy77 guidelines, but still waiting for an answer from Netherland. Only shop I found selling it on the web.

I tried to Wireshark the local connection when I access the DTU directly, but absolutely nothing appears, appart DHCP messages. If someone feel like telling me why, or pointing me somewhere…

See you for the next episode

1 Like

If you have DTU-Pro you may give a chance for one of those:

Both of them are using direct ModbusTCP communication to DTU, so the cloud is not needed!

Here also one DTU W100 user trying to get it to communicata to something else than only Hoymiles cloud. The cloud does not have any API, or I cannot find any information of it atleast.

The W100 user interface (web page) looks totally different and it does not tell any data for the user. Only settings can be adjusted. So is there anyone who has found a way to read the data from the W100 module?
The user interface has transfer tab, which defines server settings. I am not good enought with these to say could this be utilized. The SocketA could be something to use?
It looks like this:

I do have a HM-600 - and I am using an ESP32 with an nrf24 module for less than 10€. Flashed them with https://github.com/tbnobody/OpenDTU and imported the data by mqtt into HA.

3 Likes

Hello, about six months ago I made an integration with DTU Pro based on the api of the mobile application.
Using reverse engineering, I developed the communication of the mobile application with DTU and used it to eavesdrop native DTU communication with Hoymiles servers.

At the moment I can confirm 100% stability of operation with data update every minute.
Available here: GitHub - banny310/hoymiles-dtu-homeassistant-addon: Home Assistant Add-on: Hoymiles DTU Solar
Feedback welcome :slight_smile:

3 Likes

Could you explain how you integrated the OpenDTU data?

mqtt:
  sensor:

      - name: "Balkonkraftwerk Leistung AC"
        state_topic: "solar/[serial]/0/power"
        device_class: power
        unit_of_measurement: W
        state_class: measurement
        unique_id: "BalkonkraftwerkLeistungAC"
      - name: "Balkonkraftwerk Module 1-3 Leistung"
        state_topic: "solar/[serial]/1/power"
        device_class: power
        unit_of_measurement: W
        state_class: measurement
        unique_id: "BalkonkraftwerkModule13Leistung"
      - name: "Balkonkraftwerk Module 2-4 Leistung"
        state_topic: "solar/[serial]/2/power"
        device_class: power
        unit_of_measurement: W
        state_class: measurement
        unique_id: "BalkonkraftwerkModule24Leistung"   
      - name: "Balkonkraftwerk Temperatur"
        state_topic: "solar/[serial]/0/temperature"
        device_class: power
        unit_of_measurement: °C
        state_class: measurement
        unique_id: "BalkonkraftwerkTemperatur"
      - name: "Balkonkraftwerk Arbeit Tag"
        state_topic: "solar/[serial]/0/yieldday"
        device_class: energy
        unit_of_measurement: Wh
        state_class: total_increasing
        unique_id: "BalkonkraftwerkArbeitTag"
      - name: "Balkonkraftwerk Arbeit Gesamt"
        state_topic: "solar/[serial]/0/yieldtotal"
        device_class: energy
        unit_of_measurement: kWh
        state_class: total_increasing
        unique_id: "BalkonkraftwerkArbeitGesamt"
1 Like