Hallo ich habe einen Hoymileswechselrichter mit openDTU dessen Leistung ich mit einem Skript steuern will.
Sowohl die openDTU als auch der Wattwächter (so nennt er sich) sind mittels MQQT in FHM eingebunden.
Ich kann alle notwendigen Werte auslesen.
Wenn ich das errechnete Limit an die openDTU sende bekomme ich Fehler.
LIST von Wattwächter
Internals:
CID WWP_588C8153BF6C
DEF WWP_588C8153BF6C
FUUID 69fc6253-f33f-25d3-fd7c-2385a42651278639
IODev MQTT2_FHEM_Server
LASTInputDev MQTT2_FHEM_Server
MQTT2_FHEM_Server_CONN MQTT2_FHEM_Server_192.168.178.133_53797
MQTT2_FHEM_Server_MSGCNT 1299
MQTT2_FHEM_Server_TIME 2026-05-15 12:02:55
MSGCNT 1299
NAME WWP_588C8153BF6C
NR 4012
STATE ???
TYPE MQTT2_DEVICE
eventCount 1299
READINGS:
2026-05-15 12:02:55 0.2.0 02.10
2026-05-15 12:02:54 1.8.0 2413.7025
2026-05-15 12:02:55 14.7.0 50.0000
2026-05-15 12:02:54 16.7.0 -101.0000
2026-05-15 12:02:54 2.8.0 459.1679
2026-05-15 12:02:54 21.7.0 148.0000
2026-05-15 12:02:54 31.7.0 2.2700
2026-05-15 12:02:54 32.7.0 238.4000
2026-05-15 12:02:54 41.7.0 -87.0000
2026-05-15 12:02:54 51.7.0 0.8800
2026-05-15 12:02:54 52.7.0 237.9000
2026-05-15 12:02:54 61.7.0 -160.0000
2026-05-15 12:02:54 71.7.0 0.7700
2026-05-15 12:02:54 72.7.0 239.0000
2026-05-15 12:02:54 81.7.1 120.0000
2026-05-15 12:02:54 81.7.15 220.0000
2026-05-15 12:02:54 81.7.2 240.0000
2026-05-15 12:02:54 81.7.26 195.0000
2026-05-15 12:02:54 81.7.4 66.0000
2026-05-15 12:02:54 96.1.0 1EFR2575110078
2026-05-15 12:02:54 96.50.1 EFR
2026-05-15 12:02:55 96.90.2 4310
2026-05-15 11:05:29 IODev MQTT2_FHEM_Server
2026-05-15 12:02:54 Leistung_Haus -101.0000
2026-05-15 11:05:56 device_class frequency
2026-05-15 11:05:56 device_identifiers_1 WWP-588C8153BF6C
2026-05-15 11:05:56 device_manufacturer SmartCircuits GmbH
2026-05-15 11:05:56 device_model WattWächter Plus
2026-05-15 11:05:56 device_name Wattwächter
2026-05-15 11:05:56 name Unbekannt
2026-05-15 11:05:56 state_class measurement
2026-05-15 11:05:56 state_topic WattWaechter/WWP-588C8153BF6C/96.90.2
2026-05-15 11:05:54 status online
2026-05-15 11:05:56 unique_id WWP-588C8153BF6C_96_90_2
2026-05-15 11:05:56 unit_of_measurement Hz
Attributes:
readingList WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/status:.* status
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/96\x2e50\x2e1:.* 96.50.1
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/96\x2e1\x2e0:.* 96.1.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/1\x2e8\x2e0:.* 1.8.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/2\x2e8\x2e0:.* 2.8.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/16\x2e7\x2e0:.* 16.7.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/16\x2e7\x2e0:.* Leistung_Haus
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/21\x2e7\x2e0:.* 21.7.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/41\x2e7\x2e0:.* 41.7.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/61\x2e7\x2e0:.* 61.7.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/32\x2e7\x2e0:.* 32.7.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/52\x2e7\x2e0:.* 52.7.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/72\x2e7\x2e0:.* 72.7.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/31\x2e7\x2e0:.* 31.7.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/51\x2e7\x2e0:.* 51.7.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/71\x2e7\x2e0:.* 71.7.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/81\x2e7\x2e1:.* 81.7.1
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/81\x2e7\x2e2:.* 81.7.2
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/81\x2e7\x2e4:.* 81.7.4
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/81\x2e7\x2e15:.* 81.7.15
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/81\x2e7\x2e26:.* 81.7.26
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/14\x2e7\x2e0:.* 14.7.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/0\x2e2\x2e0:.* 0.2.0
WWP_588C8153BF6C:WattWaechter/WWP-588C8153BF6C/96\x2e90\x2e2:.* 96.90.2
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_96_50_1/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_96_1_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_1_8_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_2_8_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_16_7_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_21_7_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_41_7_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_61_7_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_32_7_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_52_7_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_72_7_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_31_7_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_51_7_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_71_7_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_81_7_1/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_81_7_2/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_81_7_4/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_81_7_15/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_81_7_26/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_14_7_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_0_2_0/config:.* { json2nameValue($EVENT) }
WWP_588C8153BF6C:homeassistant/sensor/WWP-588C8153BF6C_96_90_2/config:.* { json2nameValue($EVENT) }
room MQTT
Hier das cfg für die Berechnung. Das Senden an openDTU erfolgt in 99_myUtils.pm
Internals:
CFGFN ./FHEM/99_my_PV_Solar_01.cfg
DEF (PV_DTU:138291805508_0_power|WWP_588C8153BF6C:16.7.0):.* {
## Diese Daten müssen angepasst werden:
my $serial = "199980107908"; # Seriennummer des Hoymiles Wechselrichters
my $maximum_wr = 2250; # Maximale Ausgabe des Wechselrichters
my $minimum_wr = 100; # Minimale Ausgabe des Wechselrichters
my $dtu_ip = '192.168.178.244'; # IP Adresse von OpenDTU
my $dtu_nutzer = 'admin'; # OpenDTU Nutzername
my $dtu_passwort = 'Tastatur#'; # OpenDTU Passwort
my $port = ':1883'; # :80 :1883
##
my $setpoint = 111;
my $producing = ReadingsVal("PV_DTU","producing",9);
##{Log 3,"0===Solar_Nulleinspeisung producing:'$producing'"}
my $dat = sprintf("%02d-%02d-%04d %02d:%02d:%02d", $mday, $month, $year, $hour, $min, $sec);
my $reachable = ReadingsVal("PV_DTU","reachable",9.7);
my $watt_dtu = ReadingsVal("PV_DTU","138291805508_0_power",9.9);
$watt_dtu =~ s/\,/\./g;
##{Log 3,"2===Solar_Nulleinspeisung aktwatt_dtu:'$watt_dtu' "};
$watt_dtu = $watt_dtu * 1;
my $watt_dtu_dc = ReadingsVal("PV_DTU","138291805508_0_power_dc",9.9);
$watt_dtu_dc =~ s/\,/\./g;
##{Log 3,"31===Solar_Nulleinspeisung watt_dtu_dc:'$watt_dtu_dc' "};
$watt_dtu_dc = $watt_dtu_dc * 1;
my $heute_Wh = ReadingsVal("PV_DTU","138291805508_0_yieldday",9.9);
$heute_Wh =~ s/\,/\./g;
##{Log 3,"32===Solar_Nulleinspeisung aktheute_Wh:'$heute_Wh' "}
$heute_Wh = $heute_Wh * 1;
my $Solar_Total_kWh = ReadingsVal("PV_DTU","138291805508_0_yieldtotal",9.9);
$Solar_Total_kWh =~ s/\,/\./g;
my $altes_limit = ReadingsVal("PV_DTU","limit_absolute",1);
## aus Netz beziehen (+) oder Einspeisen (-)?
my $bezug_einspeisen =ReadingsVal("WWP_588C8153BF6C","16.7.0",0);
$bezug_einspeisen = $bezug_einspeisen *1; ##entspricht grid_sum
##{Log 3,"4===Solar_Nulleinspeisung bezug_einspeisen:'$bezug_einspeisen' altes_limit:'$altes_limit'"};
if ($producing == 0) { return;};
# Werte setzen
my $verbrauch = $bezug_einspeisen + $watt_dtu;
##{Log 3,"5===Solar_Nulleinspeisung Bezug/Einspeisung:'$bezug_einspeisen' Produktion:'$watt_dtu' W Verbrauch:'$verbrauch' W "};
if ($reachable == 1) {
$setpoint = $bezug_einspeisen + $altes_limit - 5; ## Neues Limit in Watt
##{Log 3,"51===Solar_Nulleinspeisung serial:'$serial' maximum_wr:'$maximum_wr' minimum_wr:'$minimum_wr'"};
##{Log 3,"52===Solar_Nulleinspeisung bezug_einspeisen:'$bezug_einspeisen' altes_limit_'$altes_limit' setpoint-5:'$setpoint'"};
if ($setpoint > $maximum_wr) {
## Fange oberes Limit ab
$setpoint = $maximum_wr;
##{Log 3,"61===Solar_Nulleinspeisung Setpoint auf Maximum gesetzt:'$setpoint' maximum_wr:'$maximum_wr' W"};
}
elsif ($setpoint <= $minimum_wr) {
## Fange unteres Limit ab $setpoint <= $minimum_wr
$setpoint = $minimum_wr;
##{Log 3,"62===Solar_Nulleinspeisung Setpoint auf Minimum gesetzt:'$setpoint' minimum_wr:'$minimum_wr' W"};
}
else {
##{Log 3,"7===Solar_Nulleinspeisung Setpoint berechnet:'$setpoint' W"};
}
if ($bezug_einspeisen < 0){ ## ja EINSPEISUNG
##{Log 3,"71===Solar_Nulleinspeisung Einspeisung:'$bezug_einspeisen' "};
}
else { ## BEZUG
##{Log 3,"72===Solar_Nulleinspeisung Bezug:'$bezug_einspeisen' "};
}
##{Log 3,"73===Solar_Nulleinspeisung erzeugt wird:'$watt_dtu' Zähler akt:'$bezug_einspeisen' W"};
##{Log 3,"74===Solar_Nulleinspeisung Max:'$maximum_wr' Min:'$minimum_wr' W"};
##{Log 3,"75===Solar_Nulleinspeisung altes_Limit:'$altes_limit' neues Limit:'$setpoint' W"};
}
##if ($setpoint != $altes_limit) {
##$setpoint = 2240; ########## nur Test ###########
{Log 3,"8===Solar_Nulleinspeisung UPDATE altes_Limit:'$altes_limit' neues Limit:'$setpoint' W"}
{openDTU_Limit($dtu_ip, $port, $dtu_nutzer, $dtu_passwort, $serial, $setpoint)};
##}
fhem("set Solar_Produktion_jn 1");
if ($Solar_Total_kWh == 0) {
{Log 3,"9===Solar_Nulleinspeisung Die Verbindung zu openDTU scheint weg zu sein !! Solar_Total_kWh:'$Solar_Total_kWh' "};
return;
}
$Solar_Total_kWh = $Solar_Total_kWh * 1;
if ($watt_dtu > 0) {
## hier normale Verarbeitung von openDTU-Werten watt_dtu gt null
fhem("set Solar_akt_vom $dat");
##fhem("set SolarStat_vom $dat");
fhem("set Solar_aktWatt $watt_dtu");
fhem("set Solar_Letzte_Watt $watt_dtu");
if ($bezug_einspeisen < 0){ ## ja EINSPEISUNG
fhem("set Einspeisung_akt $bezug_einspeisen");
fhem("set Bezug_akt 0");
}
else {
fhem("set Einspeisung_akt 0");
fhem("set Bezug_akt $bezug_einspeisen");
}
fhem("set Setze_DTU_Limit $setpoint");
fhem("set akt_DTU_Limit $altes_limit");
$heute_Wh = sprintf("%12.3f", $heute_Wh/1000);
fhem("set Solar_Today $heute_Wh");
fhem("set Solar_Total $Solar_Total_kWh");
}
}
FUUID 69fc8e42-f33f-25d3-54c8-8029499856e43877
NAME Solar_Nulleinspeisung
NOTIFYDEV WWP_588C8153BF6C,PV_DTU
NR 3495
NTFY_ORDER 50-Solar_Nulleinspeisung
REGEXP (PV_DTU:138291805508_0_power|WWP_588C8153BF6C:16.7.0):.*
STATE 2026-05-15 11:06:02
TRIGGERTIME 1778835962.62405
TYPE notify
READINGS:
2026-05-15 11:05:27 state active
2026-05-15 11:06:02 triggeredByDev PV_DTU
2026-05-15 11:06:02 triggeredByEvent 138291805508_0_power: 730.1
Attributes:
event-on-change-reading 138291805508_0_power
group Jobs,_Reste
oldreadings producing
room SolarAnlage
Hier in 99_myUtils setzen des Limits
sub openDTU_Limit (@){
my ($ip,$port,$user,$pass,$serial,$limit) = @_;
#my $ip = "192.168.178.xx"; # IP der OpenDTU
#my $user = "user";
#my $pass = "password";
#my $serial = "1141xxxxxxxx"; # Seriennummer des Wechselrichters
#my $limit = 50; # Wert (z.B. 50 Watt oder 50 Prozent)
Log(3,"== openDTU_Limit 1: :'$ip', '$port', '$user', '$pass', '$serial', '$limit'");
$ip = sprintf("%s%s", $ip,$port);
Log(3,"== openDTU_Limit:ip ist:'$ip'");
my $url = "http://$ip/api/limit/config";
my $at ="@";
$url = "http://".$user.":".$pass.$at.$ip."/api/limit/config";
##API UsageUse limit_type: 0 for Absolute Non-Persistent or limit_type: 256 for Absolute Persistent
##in your POST request to /api/limit/config# Beispiel: Relativ, nicht persistent (Prozent)
##my $payload = "data={'serial':'$serial','limit_type':1,'limit_value':$limit}";
#bsp#data={"serial":"11417xxxxxxx", "limit_type":0, "limit_value":100}
##Log(3,"== openDTU_Limit 2 url: :'$url'");
my $payload = "data={" . "\"serial\":"."\"$serial\", ";
##Log(3,"== openDTU_Limit 31 payload: :'$payload'");
$payload = $payload . "\"limit_type\":0, ";
##Log(3,"== openDTU_Limit 32 payload: :'$payload'");
$payload = $payload . "\"limit_value\":" . $limit . "}";
Log(3,"== openDTU_Limit 33 payload: :'$payload'");
my $erg_url = $url . "/" . $payload;
Log(3,"== openDTU_Limit 4 erg_url: :'$erg_url'");
Log(3,"== openDTU_Limit 5 Variante wget");
system("wget '$erg_url'");
##return;
Log(3,"== openDTU_Limit 6 Variante POST");
my $ua = LWP::UserAgent->new;
##$ua->credentials("$ip", "OpenDTU", $user => $pass);
##$ua->agent("$ip", "OpenDTU", $user => '$pass');
$ua->credentials("$ip", "PV_DTU", $user => '$pass');
Log(3,"== openDTU_Limit 61 Variante POST ua:'$ua'");
my $req = POST $url, [ "data" => $payload ];
my $res = $ua->request($req);
if ($res->is_success) {
print "Limit erfolgreich gesetzt!\n";
Log(3,"== openDTU_Limit:Limit erfolgreich gesetzt!");
} else {
print "Fehler: " . $res->status_line . "\n";
Log(3,"== openDTU_Limit:Fehler:$res->status_line .");
}
}
Fehler im LOG:
für die Variante wget:
2026.05.15 11:19:54 3: == openDTU_Limit 4 erg_url: :'http://admin:Tastatur#@192.168.178.244:1883/api/limit/config/data={"serial":"199980107908", "limit_type":0, "limit_value":1106}'
2026.05.15 11:19:54 3: == openDTU_Limit 5 Variante wget
http://admin:Tastatur#@192.168.178.244:1883/api/limit/config/data={"serial":"199980107908", "limit_type":0, "limit_value":1106}: Bad port number.
für die Variante POST
2026.05.15 11:19:54 3: == openDTU_Limit 6 Variante POST
2026.05.15 11:19:54 3: == openDTU_Limit 61 Variante POST ua:'LWP::UserAgent=HASH(0x626d5c774c48)'
Fehler: 500 Can't connect to [admin:Tastatur]:80 (Servname not supported for ai_socktype)
2026.05.15 11:19:54 3: == openDTU_Limit:Fehler:HTTP::Response=HASH(0x626d5c8ee8f0)->status_line .
In der POST Variante wird das Sonderzeichen im PW und auch die Portnummer ignoriert.
Bin ratlos.
VG
Das ist etwas wirr. Solche Mengen Perl-Code in einem notify sind weder verstehbar, noch wartbar.
Erster Tipp: Alles in ordentliche Unterprogramme in 99_myUtils.pm auslagern.
Zweiter Tipp: Fehler in der Darstellung vermeiden - z.B. heißt es nicht MQQT, und in der DEF fehlen auch diverse Dinge.
Dann kann man vielleicht helfen.
LG
pah