Für eine dynamische Nulleinspeisung am Growatt SPH3600 brauche ich einen virtuellen SDM630 Leistungsmesser, dem ich selbst die Leistung mitgeben kann (3Phasen Netz mt 1 Phasen Inverter). Modbus Master zum Auslesen des Eastron SDM630 gibts einige, aber keinen für die Simulation eines solchen. Da alle Daten in FHEM vorhanden sind (SML Orbis Strommesser, Leistungsmesser Solar, etc.) habe ich dieses genial einfache Modul von ChrisD ausgesucht. Der Growatt ist RTU Master und sucht den Energymeter auf Adresse #2. Er liest die ersten 18 Input Register. Ein einfacher Amazon USB-RS485 Stecker dient als Anschluß.
Leider hat der hier im Thread angebotene und auch der im Github vorhandene 36_ModbusSlave.pm einen Fehler, der den Betrieb mit dem Growatt unmöglich macht. Statt des Datensatzes der angekommen ist, wird nur das letzte Byte der Checksumme der Parse Routine übergeben, und die sendet dann ein 5 Byte Reply.
Fehlerhafter Code
sub ModbusSlave_Read($) {############################################################
# called from the global loop, when the select for hash->{FD} reports data
[color=red]Log 0[/color],"Read";
my ($hash) = @_;
my $buf = DevIo_SimpleRead($hash);
return "" if(!defined($buf));
my $name = $hash->{NAME};
my $pdata = $hash->{helper}{PARTIAL};
$pdata .= $buf;
ModbusSlave_LogFrame($hash,"ModbusSlave_Read($name)",$pdata,4);
if(( bytes::length($pdata) >= 4 ) && ( ModbusSlave_crc_is_ok($pdata)))
{
Log3 $hash,4,"ModbusSlave_Read($name) : crc ok, parsing request";
RemoveInternalTimer( "RTimeout:".$name);
$hash->{helper}{PARTIAL} = undef;
ModbusSlave_UpdateStatistics($hash,1,0,bytes::length($buf),0); #$buf ist letzter Block
ModbusSlave_Parse($hash, $buf); #$buf ist letzter Block, nicht ganzer Satz
Bei 9600baud und schnellem Rechner kommt der Datensatz nicht in einem Stück, sondern Zeichen- für Zeichen. Wahrscheinlich fällt der Fehler bei einem langsamen System mit hoher Baudrate gar nicht auf.
$buf = letzter Block von empfangenen Zeichen (hier: 2. Byte der Checksumme)
$pdata = Modbus Datenblock , der verarbeitet werden soll
Richtig muss es also heissen:
ModbusSlave_UpdateStatistics($hash,1,0,bytes::length($pdata),0);
ModbusSlave_Parse($hash, $pdata);
Ausserdem "müllt" der Log über das Read bei Dauerabfragen das Logfile zu. Daher habe ich es auf verbose Level 2 gesetzt:
# called from the global loop, when the select for hash->{FD} reports data
my ($hash) = @_;
Log3 $hash,2,"Read RTU"
Danach läuft es jetzt einfach super, über MQTT2 hole ich die benötigten Werte für Spannung (wird nicht gebraucht) und natürlich die Leistung mit Vorzeichen. Die einfache Definition hier noch der Vollständigkeit:
root@mobilheim-esx:/opt/fhem# cat fhem.cfg
attr global userattr cmdIcon devStateIcon:textField-long devStateStyle icon sortby webCmd webCmdLabel:textField-long widgetOverride
attr global autoload_undefined_devices 1
attr global autosave 0
attr global logfile ./log/fhem-%Y-%m.log
attr global modpath .
attr global motd none
attr global statefile ./log/fhem.save
attr global verbose 3
define WEB FHEMWEB 8083 global
setuuid WEB 6327fbb8-f33f-9008-edc0-7d16279fe4a5412f
# Fake FileLog entry, to access the fhem log from FHEMWEB
define Logfile FileLog ./log/fhem-%Y-%m.log Logfile
setuuid Logfile 6327fbb8-f33f-9008-3f21-7401c05374272240
define autocreate autocreate
setuuid autocreate 63294800-f33f-9008-952b-d5effcc5fb36ae0b
attr autocreate filelog ./log/%NAME-%Y.log
define eventTypes eventTypes ./log/eventTypes.txt
setuuid eventTypes 6327fbb8-f33f-9008-164d-9139fc43c197395e
# Disable this to avoid looking for new USB devices on startup
#define initialUsbCheck notify global:INITIALIZED usb create
define MQTT2_Garage MQTT2_CLIENT 192.168.188.240:1883
setuuid MQTT2_Garage 6327fbb8-f33f-9008-1fbf-fad8914b9bc67ccc
attr MQTT2_Garage room Garage
define MQTT2_ewe MQTT2_DEVICE ewe
setuuid MQTT2_ewe 63294800-f33f-9008-39d9-e9b242ee7ccfda5a
attr MQTT2_ewe IODev MQTT2_Garage
attr MQTT2_ewe readingList garage/Strom/Strom/power:.* ewe_power\
garage/Strom/Strom/power_L1:.* ewe_power_L1\
garage/Strom/Strom/power_L2:.* ewe_power_L2\
garage/Strom/Strom/power_L3:.* ewe_power_L3\
garage/Growatt/Growatt/voltage:.* ewe_voltage
attr MQTT2_ewe room Garage
define SDM630 ModbusSlave /dev/ttyUSB1@9600,8,N,1
setuuid SDM630 63294800-f33f-9008-b320-ceb744d0d0fa80f9
attr SDM630 verbose 1
define SDM630_30001 dummy
setuuid SDM630_30001 63294800-f33f-9008-cd70-66f90b0318cc4025
attr SDM630_30001 comment MBR:2,0,I,,F
attr SDM630_30001 group SDM630
attr SDM630_30001 room SDM630
define SDM630_30003 dummy
setuuid SDM630_30003 63294800-f33f-9008-5876-b9d359d188945905
attr SDM630_30003 comment MBR:2,2,I,,F
attr SDM630_30003 group SDM630
attr SDM630_30003 room SDM630
define SDM630_30005 dummy
setuuid SDM630_30005 63294800-f33f-9008-d17b-b66dc1c0651e6d07
attr SDM630_30005 comment MBR:2,4,I,,F
attr SDM630_30005 group SDM630
attr SDM630_30005 room SDM630
define SDM630_30007 dummy
setuuid SDM630_30007 63294800-f33f-9008-5bda-716d0bc978966cd8
attr SDM630_30007 comment MBR:2,6,I,,F
attr SDM630_30007 group SDM630
attr SDM630_30007 room SDM630
define SDM630_30009 dummy
setuuid SDM630_30009 63294800-f33f-9008-8b30-de23e95b435476b6
attr SDM630_30009 comment MBR:2,8,I,,F
attr SDM630_30009 group SDM630
attr SDM630_30009 room SDM630
define SDM630_30011 dummy
setuuid SDM630_30011 63294800-f33f-9008-2043-c80a26a8d1ff9246
attr SDM630_30011 comment MBR:2,10,I,,F
attr SDM630_30011 group SDM630
attr SDM630_30011 room SDM630
define SDM630_30013 dummy
setuuid SDM630_30013 63294800-f33f-9008-6f26-2784b56ef96ab936
attr SDM630_30013 comment MBR:2,12,I,,F
attr SDM630_30013 group SDM630
attr SDM630_30013 room SDM630
define SDM630_30015 dummy
setuuid SDM630_30015 63294800-f33f-9008-2e00-979ffccc4ccc5d2b
attr SDM630_30015 comment MBR:2,14,I,,F
attr SDM630_30015 group SDM630
attr SDM630_30015 room SDM630
define SDM630_30017 dummy
setuuid SDM630_30017 63294800-f33f-9008-2d2d-8818d8fd079470c0
attr SDM630_30017 comment MBR:2,16,I,,F
attr SDM630_30017 group SDM630
attr SDM630_30017 room SDM630
#define sendtogrowatt at +00:00:10 { fhem "set SDM630_30013 " . ReadingsVal('MQTT2_ewe','ewe_power',0) }
define n_ewe_power notify MQTT2_ewe:ewe_power:.* { fhem "set SDM630_30013 " . ReadingsVal('MQTT2_ewe','ewe_power',0);;fhem "set SDM630_30001 " . ReadingsNum('MQTT2_ewe','ewe_voltage',0) }
setuuid n_ewe_power 63294800-f33f-9008-bda9-d0e2698a87eabef9
attr n_ewe_power room SDM630
30001 = Spannung an der 1. Leitung
30007 = Strom an der 1. Leitung
30013 = Leistung saldiert an der 1. Leistung +/-
Selbst setze ich FHEM schon lange Zeit auf Raspi ein, fremdle jedoch mit der PERL Sprache und vor allem der Syntax. Super mächtig aber manchmal für den non-Profi extrem nervig. Daher bisher wenig selbst gemacht. Ich bitte um Entschuldigung, wenn das Beispiel nicht für jeden optimal ist.
Eine "Unschönheit" des ModbusSlave Moduls: Da nicht global eine Adresse dem Slave zugeordnet wird, sondern nur in den Registern, antwortet der Slave manchmal (während der Testphase) auch auf Aufrufe mit anderen Adressen (#1, #3, etc.) . Das "verwirrte" manche Master, die einfach nach Teilnehmern auf dem Bus suchen (wie mein Growatt). Ein optionaler Parameter für die Slave Adresse wäre eine tolle Erweiterung, sodass das Modul bei allen anderen Adressen "den Mund hält". Ich sehe aber auch das Potential in der Lösung mit übergreifenden Registern. Danke für die Bereitstellung des Moduls.