Die Leistun eines Hoymiles Wechselrichters mit openDTU per Skript begrenzen

Begonnen von boeho, 15 Mai 2026, 12:10:45

Vorheriges Thema - Nächstes Thema

boeho

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

Prof. Dr. Peter Henning

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

Wzut

Zitat von: boeho am 15 Mai 2026, 12:10:45Bad port number.

da würde ich ansetzen und in deinem Aufruf die 1883 gegen 80 ersetzen (ist z.Z. auskommentiert).
Das ist der Port auf dem deine openDTU den api Call annehmen soll. Mit MQTT hat das nichts zu tun.
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher