Two small solar inverters on the balcony, and one question: how much of this do we actually use?
The inverters
Nothing special here. I bought two Hoymiles micro inverters (HM-300 and HM-400, 700 W together), simply because they were cheap. The interesting part is getting the numbers out of them. Locally, every few seconds, and without the manufacturer’s cloud.
For Hoymiles I use AhoyDTU, an open-source firmware for an ESP microcontroller with a cheap radio module that talks to the inverters directly. Power, voltage, current, temperature and the yield per inverter end up on MQTT. It also supports Home Assistant MQTT discovery, so most home automation systems pick up the values without typing a single topic. OpenDTU is an alternative that does the same job.
Different inverters? Then neither of them will help you, but there are other ways:
- Many inverters have a local interface, like Modbus TCP or a small HTTP API.
- A smart plug with power metering between inverter and socket works with every balcony inverter. You lose the details per panel, but you still get the power and the energy per day. And that is what counts.
The AhoyDTU settings
In the web UI of the DTU, under the MQTT settings, it only needs a few values:
- Broker: the IP of the home server (192.168.1.x), port 1883
- Topic:
inverter - Home Assistant discovery: on, with the default prefix
homeassistant - And a name per inverter. Mine are called
Balkon_SOandBalkon_SW.
After that the DTU publishes everything below inverter/, one subtopic per inverter and channel, plus inverter/total for both together.
The MQTT broker
The broker is a plain Mosquitto container on the home server:
services:
mosquitto:
image: eclipse-mosquitto:latest
restart: unless-stopped
volumes:
- /srv/mosquitto:/mosquitto
ports:
- 1883:1883
And /srv/mosquitto/config/mosquitto.conf is short:
persistence true persistence_location /mosquitto/data/ log_dest file /mosquitto/log/mosquitto.log listener 1883 allow_anonymous true
allow_anonymous is fine for me, because port 1883 is only reachable inside my LAN. If your broker can be reached from outside, set up a password file.
openHAB: broker and inverters
In openHAB the broker is a bridge. enableDiscovery is the important part, it lets openHAB pick up the Home Assistant discovery messages of the DTU:
Bridge mqtt:broker:OMV-Broker "MQTT Broker" [
host="mosquitto",
keepAlive=60,
enableDiscovery=true
]
host="mosquitto" works because openHAB and Mosquitto run in the same Docker network. The inverters then show up in the openHAB inbox by themselves. Add them, and you get one thing per inverter (plus one for the total) with all channels already defined. The items just link to those channels:
Number:Power HM400_ch0_P_AC "Inverter SW Power" (gPersistence) { channel="mqtt:homeassistant:OMV-Broker:112191617247:ch0_P_AC" }
Number:Energy HM400_ch0_YieldToday "Inverter SW Energy Today" { channel="mqtt:homeassistant:OMV-Broker:112191617247:ch0_YieldDay" }
Number:Power Inverter_total_P_AC "Inverter Total Power" (gPersistence) { channel="homeassistant:device:OMV-Broker:AHOY_2DDTU_5FTOTAL:total_P_AC" }
The long number in the thing UID comes from the discovery, so check yours in the inbox.
Is the DTU still alive?
A DTU that silently stops working means days without data, and I only notice when I look at the graphs. So I want a push notification instead.
The trick is a feature of MQTT itself, the last will. When the DTU connects to the broker, it publishes connected on the topic inverter/mqtt and leaves a second message with the broker: not connected, its last will. If the DTU disappears without saying goodbye (power gone, WiFi gone), the broker notices after a short timeout and publishes the last will in its name. Both messages are retained, so anyone who subscribes later still gets the current state.
In openHAB that topic is just a string channel:
Thing mqtt:topic:OMV-Broker:ahoy "Ahoy DTU" (mqtt:broker:OMV-Broker) {
Channels:
Type string : connection "MQTT Connection" [ stateTopic="inverter/mqtt" ]
}
String InverterAhoyConnection "Ahoy DTU MQTT [%s]" { channel="mqtt:topic:OMV-Broker:ahoy:connection" }
And a rule waits five minutes before it raises the alarm, so a short WiFi hiccup does not wake anybody. The push notification goes through the openHAB app. Simplified, it looks like this:
rule "Ahoy DTU offline alarm"
when
Item InverterAhoyConnection changed
then
if (InverterAhoyConnection.state.toString != "connected") {
ahoyOfflineTimer = createTimer(now.plusMinutes(5), [ |
if (InverterAhoyConnection.state.toString != "connected") {
sendBroadcastNotification("Ahoy DTU offline: no MQTT connection for 5 minutes", "error", "ahoy")
}
])
} else {
ahoyOfflineTimer?.cancel
// the real rule also sends "Ahoy DTU is back online" after an alarm
}
end
Of course I had to test it, so I unplugged the DTU:
23:06:30 InverterAhoyConnection connected -> not connected (last will)
23:11:30 InverterAhoyOffline OFF -> ON (alarm, push notification)
23:12:42 InverterAhoyConnection not connected -> connected (plugged in again)
23:12:42 InverterAhoyOffline ON -> OFF ("back online" notification)
Works. Why not simply raise an alarm when the inverters stop sending? Because they do that every evening. No sun, no inverter. The DTU stays connected all night, so it is the better signal.
The other side: the grid
The panels are only half of the story. To know how much of their energy the house uses, I need the grid side too. A Shelly 3EM in the distribution board measures the net power over all three phases. Positive means import, negative means export.
openHAB has a binding for Shellys. The thing needs the IP and, if the Shelly has a login, user and password:
Thing shelly:shellyem3:0ad35fbad3 "Shelly EM3" [
deviceIp="192.168.1.x",
userId="admin",
password="secret",
eventsCoIoT=true,
updateInterval=10
]
eventsCoIoT makes the Shelly push its values instead of waiting to be polled, so I get a new value about every 15 seconds. The item for the grid power:
Number:Power DeviceAccumulatedWatts "Grid power (net)" (gPersistence) { channel="shelly:shellyem3:0ad35fbad3:device#accumulatedPower" }
gPersistence is a group for all items that are stored at least once a minute, the grid power is one of them.
With these two values I get everything else:
- Export: what went back to the grid
- Self-used PV: production minus export (per hour, never below zero)
- Consumption: grid import plus self-used PV
The numbers
From 1 January to 7 October 2026:
| kWh | |
|---|---|
| PV production | 663 |
| used in the house | 459 |
| exported | 209 |
| house consumption | 2,885 |
| grid import | 2,426 |
So about two thirds (69%) of the solar energy is used in the house, and the 700 W cover 16% of our consumption. Not much, but not nothing either. The best day so far was 8 April 2026 with 4.1 kWh, and since September 2023 the two inverters have produced 1,631 kWh in total.
What bugs me are the 209 kWh of export. I get no feed-in compensation, so this energy is simply given away. That is 0.75 kWh per day on average, and a lot more on sunny summer days. Every kWh I use myself saves the full electricity price.
Here is 8 October in Grafana:

Total (D) is today, both inverters together. Total (Y) is not the year, it is everything since the start, the 1,631 kWh from above.















