[ModBusAttr] Werte schreiben als Text ?

Begonnen von cotecmania, 24 März 2020, 10:26:29

Vorheriges Thema - Nächstes Thema

cotecmania

Hallo,

Ich betreibe meinen Solarladeregler LS2024B seit Jahren und er läuft zuverlässig, Werte werden gelesen.
Ich schaffe es aber nicht, die RealTimeClock (RTC) auf dem Gerät zu setzen.
Der Wert z.B. RTC2 ist so definiert und wird korrekt gelesen :


obj-h36884-expr   sprintf("%02d %02d", ($val & 0xff), ($val >> 8) )
obj-h36884-format   %s
obj-h36884-polldelay   x12
obj-h36884-reading   RTC2
obj-h36884-set 1


RTC2 wird z.B. so richtig als reading angezeigt : 16 22

Wenn ich den Wert nun setzen will bekomme ich Fehlermeldungen.
set LS2024B RTC2 17 25  -> Set Value 17 25 is not numeric and textArg not specified
set LS2024B RTC2 1         -> Error code 04 / slave device failure

Das steht in der Doku zum Gerät :
D2 Real time clock 9014
03(read)10(write) D7-0 Hour, D15-8 Day

Das im Log, wenn ich es mit dem Wert 1 teste :
2020.03.24 10:23:20 5: LS2024B: UpdateSetList: setList=interval reread:noArg reconnect:noArg stop:noArg start:noArg close:noArg saveAsModule scanModbusId scanStop:noArg scanModbusObjects Batterie_Typ:User,AGM,Gel,Saeure RTC2 Last_Modus:manuell,nachts,nachts+timer,timer
2020.03.24 10:23:20 5: LS2024B: UpdateSetList: getList=
2020.03.24 10:23:27 5: LS2024B: set called with RTC2 (h36884) setVal = 1
2020.03.24 10:23:27 5: LS2024B: GetSetChecks with force
2020.03.24 10:23:27 5: LS2024B: GetSetChecks returns success
2020.03.24 10:23:27 5: LS2024B: set packed hex 31 with n to hex 0001
2020.03.24 10:23:27 4: LS2024B: DoRequest called from Set created request: id 1, fCode 16, type h, adr 36884, len 1, value 0001 for device LS2024B reading RTC2 (set RTC2), read buffer empty
2020.03.24 10:23:42 5: LS2024B: attr change set updateGetSetList to 1


Wie kann ich den Wert korrekt setzen ?

PS: Einfache Integerwerte wie 0/1 für einen anderen Wert funktionieren

Gruss
Joe
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

StefanStrobel

Hallo Joe,

mit dem Attribut obj-h36884-expr definierst Du wie man von dem 16-Bit Wert im Holding-Register 36884 zu einem Text kommt.
Wenn Du nun einen eingegebenen Text im richtigen Format in das Register schreiben möchtest, dann musst Du den umgekehrten Weg auch definieren.
In der Doku findest Du dazu:

obj-[cdih][1-9][0-9]*-setexpr
    defines a perl expression that converts the user specified value in a set to a raw value that can be sent to the device. This is typically the inversion of -expr above.

Zudem musst Du dem Modul noch beibringen, dass es nach dem Set-Befehl einen String (zwei Zahlen mit Space dazwischen) akzeptieren soll. Die Lösung dafür steht aber schon in der Fehlermeldung drin: textArg.

obj-h36884-textArg 1

Dann kann die setExpr den String zerlegen und daraus eine passende 16-Bit-Zahl machen.

Dann musst Du ggf. noch dafür sorgen, dass mit function code 16 (Hex 10 in Deiner Doku) geschrieben wird und nicht mit 6.

dev-([cdih]-)*write
specifies the function code to use for writing this type of object. The default is 6 for holding registers and 5 for coils. Discrete inputs and input registers can not be written by definition.


Ich hoffe das hilft Dir weiter.

Gruss
   Stefan

cotecmania

Hallo Stefan,

Danke für die Ausführungen. Das mit der Textformatierung habe ich verstanden, allerdings finde ich in der Commandref keine Beschreibung zu "textArg"

Um den Problemen mit dem Stringhandling erstmal aus dem Wege zu gehen, wollte ich einfach mal einen Integer-Wert schreiben z.B. 1 was ja auch nicht funktioniert.
Fehler : Error code 04 / slave device failure
Siehe auch noch mal meinen LOG-Auszug von oben

dev-h-write passt schon mit 16. In der Doku war das wohl ein Hex-Wert 0x10

Diesen Wert hier kann ich problemlos schreiben mit 0 oder 1:

obj-h36970-reading Last_EinAus
obj-h36970-set 1


Warum RTC2 nicht ?

Gruss
Joe
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

cotecmania

Hallo nochmals,

Das Problem war, dass die RealTimeClock nur auf einmal beschrieben werden darf, d.h. alle 3 Register müssen mit einem Write beschrieben werden.

Die 3 Bytes auf einmal zu lesen und zu formatieren habe ich geschafft, aber wie sieht das "setexpr" aus, um die Uhrzeit setzen zu können ?

Also die "inversion" zu folgendem ?
obj-h36883-expr sprintf("%02d.%02d.20%02d %02d:%02d:%02d",(($val[1]>>8), $val[2] & 0xff), ($val[2] >> 8), ($val[1] & 0xff) , ($val[0] >> 8),($val[0] & 0xff) )
ergibt
25.03.2020 11:12:08


Gruss und Danke
Joe
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

StefanStrobel

Bitte poste doch erst mal Deine Konfiguration (unpack, len etc.), da das ja zusammen passen muss.

Ich könnte mir vorstellen, dass es am einfachsten ist, in den Expressions von / zu Hex-Strings zu arbeiten und den unpack- / pack-code als H* zu setzen.
Vermutlich ist das aber Geschmackssache ;-)

Gruss
   Stefan

cotecmania


   obj-h36883-expr sprintf("%02d.%02d.20%02d %02d:%02d:%02d",(($val[1]>>8), $val[2] & 0xff), ($val[2] >> 8), ($val[1] & 0xff) , ($val[0] >> 8),($val[0] & 0xff) )
   obj-h36883-len 3
   obj-h36883-reading RTC
   obj-h36883-set 1
   obj-h36883-textArg 1
   obj-h36883-unpack s>s>s>
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

StefanStrobel

Die Herausforderung ist jetzt dass s>s>s> zwar praktisch für das Lesen ist, aber beim Schreiben so nicht funktioniert, da Du beim Set eben nur einen Wert übergeben kannst bzw. die Expression auch nur einen Wert zurückgibt.
Wenn Du aber als unpack-Code so etwas wie "HHHHHHHHHHHH" verwendest, dann bekommst Du in der Expr beim Lesen einen Hex-String, den Du auch gut byteweise auseinandernehmen kannst und beim Schreiben kann Deine setExpr ebenfalls einen Hex-String zusammenbauen.

Gruss
   Stefan

cotecmania

Hallo Stefan,

"HHHHHHHHHHHH" funktioniert nicht.
Ich habe leider nix mit perl am Hut aber nach etwas googeln  fand ich raus, dass unpack mit "H*" folgendes Ergebnis liefert : 042c19151403
Das sind die 6 Bytes, die die Zeitinformation beinhaltet.
Diese Bytefolge kann ich auch direkt wieder mit neuen Werten auf den Laderegler schreiben.
So weit so gut.
Nur will ich das Ganze ja menschlich lesbar :

Das ist somit meine expr:
sprintf("%02d.%02d.20%02d %02d:%02d:%02d", hex(substr($val,4,2)), hex(substr($val,10,2)), hex(substr($val,8,2)), hex(substr($val,6,2)), hex(substr($val,0,2)), hex(substr($val,2,2)))
und erzeugt, wie gewünscht so etwas : 25.03.2020 22:59:55

Morgen muss ich schauen, wie ich das wieder in eine Bytefolge (mit setexpr) bringe und dann muesste das Schreiben ja funktionieren.
Ob es der effektivste Weg ist, bezweifle ich ...

Gruss
Joe
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

laserrichi

Hi Jo,
bist du da schon weitergekommen ? wie sieht jetzt dein reading aus ?
Ich habe gerade gesehen das mein Laderegler ja die gleichen register hat und ich auch bisher gescheitert bin die Zeit zu setzen.
RaspberryPi 4 Bullseye,Homematic,Z-Wave,Rademacher Duofern,Signalduino,Fritz7590,ESPEasy,Tasmota,Robonect,Kameras,1-Wire,Modbus,Solar,Maranz,VU+,ulanzi tc001 mit awtrix light

springber

Hallo,

ich habe auch meinen Solarladeregler LS2024B mit ModbusAttr eingebunden. Ich habe keine Möglichkeit gefunden über setexpr das Datum vom Format "TT.MM.YYYY HH:MM:SS" in HEX umzuwandeln. Beim Versuch eine perlfunktion (99_myUtils.pm) einzugeben gab es immer Fehlermeldungen und das hat nicht funktioniert. Die Perfunktion funktioniert und der daraus berechnete HHHHHHHHHHHH Wert kann auch in set <DEVICE> RTC HHHHHHHHHHHH eingegeben werden und die Uhr im LS2024B wird gesetzt. Aber ich kann nicht das Datum in Klartext "TT.MM.YYYY HH:MM:SS" eingeben.

Ich habe mir damit beholfen ein at Device anzulegen in dem eine Perl Funktion steht. In der Perl Funktion wird die aktuelle Systemzeit vom fhem System ermittelt und in das Format HHHHHHHHHHHH umgewandelt. Der HHHHHHHHHHHH Wert wird dann als fhem set <DEVICE> RTC HHHHHHHHHHHH ausgeführt. Ergebnis - die Uhr am Solarladeregler stimmt mit der fehm Systemzeit überein.

Die raw DEF von dem at device ist:

defmod EPSOLAR_1_set_date_time at *01:01:01 {\
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);;\
  #$sec = 00;;\
  #$min = 00;;\
  #$hour = 10;;\
  #$mday = 02;;\
  #$mon = 03;;\
  #$year=21;;\
  $year = $year-2000+1900;;\
  #print "Aktuelles Datum ist : $mday.$mon.$year $hour:$min:$sec\n\r\n\r";;\
  my $setvalue = sprintf("%02X", $min).sprintf("%02X", $sec);;\
  my $dezvalue = hex($setvalue);;\
  #print "Min\tSec\t$min\t$sec\t$setvalue\t$dezvalue\n\r";;\
  my $alles = $setvalue;;\
  $setvalue = sprintf("%02X", $mday).sprintf("%02X", $hour);;\
  $dezvalue = hex($setvalue);;\
  #print "Day\tHour\t$mday\t$hour\t$setvalue\t$dezvalue\n\r";;\
  $alles = $alles.$setvalue;;\
  $setvalue = sprintf("%02X", $year).sprintf("%02X", $mon);;\
  $dezvalue = hex($setvalue);;\
  #print "Year\tMonth\t$year\t$mon\t$setvalue\t$dezvalue\n\r";;  \
  $alles = $alles.$setvalue;;\
  #print "Alles in HEX:\t$alles\n\r";;\
  Log 1, "set EPSOLAR_1 RTC $mday.$mon.$year $hour:$min:$sec in HEX: $alles";;\
  fhem("set EPSOLAR_1 RTC $alles");;\
}


Die Definition RTC im Device für den Solarladeregler LS2024B ist:

attr EPSOLAR_1 obj-h36883-expr sprintf("%02d.%02d.20%02d %02d:%02d:%02d", hex(substr($val,4,2)), hex(substr($val,10,2)), hex(substr($val,8,2)), hex(substr($val,6,2)), hex(substr($val,0,2)), hex(substr($val,2,2)))
attr EPSOLAR_1 obj-h36883-len 3
attr EPSOLAR_1 obj-h36883-poll 1
attr EPSOLAR_1 obj-h36883-polldelay X1
attr EPSOLAR_1 obj-h36883-reading RTC
attr EPSOLAR_1 obj-h36883-set 1
attr EPSOLAR_1 obj-h36883-setexpr $val
attr EPSOLAR_1 obj-h36883-showGet 1
attr EPSOLAR_1 obj-h36883-textArg 1
attr EPSOLAR_1 obj-h36883-unpack H*

laserrichi

ui es bewegt sich etwas :-)

habe das mal probiert aber bekomme fehler: Global symbol "$setvalue" requires explicit package name

wobei ich das jetzt noch kein setexpr mal eingebaut hatte, ich hab bei mir ja das modul gebastelt für meinen Solarlader.

Kann man das nicht in das eigene Modul dann evtl. einbauen ?

RaspberryPi 4 Bullseye,Homematic,Z-Wave,Rademacher Duofern,Signalduino,Fritz7590,ESPEasy,Tasmota,Robonect,Kameras,1-Wire,Modbus,Solar,Maranz,VU+,ulanzi tc001 mit awtrix light

springber

Und es geht doch   :) :)

wenn man bei setexpr einen einzeiler macht ist der zwar ziemlich lang aber es geht. Also habe ich das geändert und kann Datum und Zeit vom Solarlader über set ändern. Das Eingabeformat für das set ist wie das reading TT.MM.YYYY hh.mm.ss also z.B. 02.02.2021 12:04:36. Zu beachten ist, die Zahlen müssen immer 2 (oder 4) Stellig sein - also 3.2.21 12:4:56 geht nicht - aber 03.02.2021 12:04:56 schon.  :)

Das at Device musste ich natürlich auch wieder anpassen, so dass der set DEVICE RTC Befehl wieder mit TT.MM.YYYY hh.mm.ss ausgeführt wird.

attr EPSOLAR_1 obj-h36883-expr sprintf("%02d.%02d.20%02d %02d:%02d:%02d", hex(substr($val,4,2)), hex(substr($val,10,2)), hex(substr($val,8,2)), hex(substr($val,6,2)), hex(substr($val,0,2)), hex(substr($val,2,2)))
attr EPSOLAR_1 obj-h36883-len 3
attr EPSOLAR_1 obj-h36883-poll 1
attr EPSOLAR_1 obj-h36883-polldelay X1
attr EPSOLAR_1 obj-h36883-reading RTC
attr EPSOLAR_1 obj-h36883-set 1
attr EPSOLAR_1 obj-h36883-setexpr sprintf("%02X", substr($val,14,2)).sprintf("%02X", substr($val,17,2)).sprintf("%02X", substr($val,0,2)).sprintf("%02X", substr($val,11,2)).sprintf("%02X", substr($val,8,2)).sprintf("%02X", substr($val,3,2))
attr EPSOLAR_1 obj-h36883-showGet 1
attr EPSOLAR_1 obj-h36883-textArg 1
attr EPSOLAR_1 obj-h36883-unpack H*


Das at Device um die aktuelle Systemzeit an den Solarlader zu schicken:

defmod EPSOLAR_1_set_date_time at *01:01:01 {\
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);;\
  #$sec = 00;;\
  #$min = 00;;\
  #$hour = 10;;\
  #$mday = 02;;\
  #$mon = 03;;\
  #$year=21;;\
  $year = $year+1900;;\
  #print "Aktuelles Datum ist : $mday.$mon.$year $hour:$min:$sec\n\r\n\r";;\
  my $alles = sprintf("%02d", $mday)."\.".sprintf("%02d", $mon)."\.".sprintf("%04d", $year)." ".sprintf("%02d", $hour).":".sprintf("%02d", $min).":".sprintf("%02d", $sec);;\
  Log 1, "set EPSOLAR_1 RTC $alles";;\
  fhem("set EPSOLAR_1 RTC $alles");;\
}

laserrichi

sehr cool ...  genau das ist DIE Lösung die ich lange gesucht hatte.
Ich habe es in mein Modul schon mal eingebaut und es funktioniert :-)
Werde dann noch ein paar andere Dinge weiter ausbauen und mein Modul 98_ModbusEPEVER.pm hier wieder aktualisieren.
RaspberryPi 4 Bullseye,Homematic,Z-Wave,Rademacher Duofern,Signalduino,Fritz7590,ESPEasy,Tasmota,Robonect,Kameras,1-Wire,Modbus,Solar,Maranz,VU+,ulanzi tc001 mit awtrix light

StefanStrobel

Hallo,

wie genau sah denn Euer Versuch aus, es ohne "at" und direkt mit einer setExpr zu machen und was genau war die Fehlermeldung?
Eigentlich sollte das auch funktionieren.

Gruss
   Stefan

springber

Hallo,

meine ersten versuche waren in der setexr etwas zu definieren ähnlich wie in einem userReading - also {perlcode}. Da ist es so, dass der letzte Wert dann im Reading steht. In dem {Perlcode} kann ich dann auch ins Log schreiben, andere Werte setzen, eine Message zu schicken etc.

Das hat bei setexpr nicht funktioniert. Auch die Eingabe im Attribut so weit zu vereinfachen, indem ich nur eine Funktion und $val schreibe (Funktion($val)) und diese Funktion in99_myUtils.pm definieren hat nicht funktioniert (die Funktion hat mit return $neuerWert geendet) . Wenn ich in der Funktion Übergabewerte definiert habe (sub Funktion ($) {my ($Wert) = @_;) habe ich immer die Fehlermedlung im Log bekommen falsche Anzahl an Übergabeparameter. Ich habe verschiedenes probiert- ohne Erfolg.

Erst das Ganze als onliner direkt in setexpr hat dann geklappt.

(ich gebe zu, ich bin kein Freund von onlinern, Performance ist nicht mein Ziel ich habe es lieber runtergebrochen in kleine Schritte....)

StefanStrobel

Hallo springber,

ich habe das versucht in einem Test nachzustellen, bei mir klappt es aber:


sub setExprSub {
    my $val = shift;
    return $val * 3;
}

attr Master obj-h258-setexpr setExprSub ($val)


wie genau sieht Deine Funktion und Dein Attribut denn im Fehlerfall aus?

Gruss
   Stefan

springber

Hallo StefanStrobel,

jetzt ist es mir klar, ich habe bei der Übergabe von $val einen Fehler gemacht und habe nicht

"my $val = shift;"

benutzt.

Ich versuche es noch mal bei Gelegenheit aber wieso es nicht ging ist mir ziemlich klar ...

Danke!

Viele Grüße

springber

springber

Hallo,

ich kann vielleicht noch etwas für ein Modul 98_ModbusEPEVER.pm beitragen. Ich habe die Status Meldung von Battery C1, Cargin Equipment C2 und Dischargin Equipment C7 aufgedröselt und die Bits in den Fehlertext umgesetzt. Die jeweiligen Funktionen habe ich in 99_myUtils erstellt. Je ein Notify bei Änderung vom Wert (C1 -> obj-i12800-reading,C2->obj-i12801-reading oder C7->obj-i12802-reading) ruft die Funktion auf und in der Funktion wird ein userReading mit dem Zusammengesetzten Fehlertext geschrieben. (ach ja - ich schreibe gerne ausführlichen Code Schritt für Schritt - das geht sicher auch anders...).

Ist vielleicht ein bisschen langer Post aber vielleicht hilft es ja jemandem :)

Viele Grüße springber

Das sieht dann so aus:
Discharging_equipment_Textstatus -> 1, Running, Normal, , , , , , , , , , , output power 00 light load, 00 normal
   
Discharging_equipment_status -> 1

Die Funktion für Battery Status:
attr EPSOLAR_1 obj-i12800-poll 1
attr EPSOLAR_1 obj-i12800-reading Battery_Status
attr EPSOLAR_1 obj-i12800-showGet 1




#### EPSOLAR Charge Fehlercode in Klartext ausgeben
# Eingabe ist der Fehlercode aus dem Reading obj-i12800-reading (siehe oben)
sub
Battery_Fehlercode(){
#my $Zahl = 0b1111111111111111;
my$Zahl = ReadingsVal("EPSOLAR_1","Battery_Status",0);
my $D0_3 = $Zahl & 0x0f;
my $D4_7 = $Zahl >> 4;
$D4_7 = $D4_7 & 0x0f;
my $D8 = $Zahl >> 8;
$D8 = $D8 & 0x01;
my $D9 = $Zahl >> 9;
$D9 = $D9 & 0x01;
my $D15 = $Zahl >> 15;
$D15 = $D15 & 0x01;
# if ($D0 == 1) {$D0t = "Running"};

my $D0_3T = "ERROR";
my $D4_7T = "ERROR";
my $D8T = "ERROR";
my $D9T = "ERROR";
my $D15T = "ERROR";

$D0_3T = "00 Normal" if ($D0_3 == 0);
$D0_3T = "01 Overvolt" if ($D0_3 == 1);
$D0_3T = "02 Under Volt" if ($D0_3 == 2);
$D0_3T = "03 Low Volt Disconnect" if ($D0_3 == 3);
$D0_3T = "04 Fault" if ($D0_3 == 4);
$D4_7T = "Temperature 00 Normal" if ($D4_7 == 0);
$D4_7T = "Temperature 01 Over Temp.(Higher than the warningsettings)" if ($D4_7 == 1);
$D4_7T = "Temperature 02 Low Temp.(Lower than the warning settings)" if ($D4_7 == 2);
$D8T = "" if ($D8 == 0);
$D8T = "1 Battery inner resistance abnormal" if ($D8 == 1);
$D9T = "" if ($D9 == 0);
$D9T = "1 The load is Over current" if ($D9 == 1);
$D15T = "" if ($D15 == 0);
$D15T = "Wrong identification for rated voltage" if ($D15 == 1);

#print($D0_3T.";".$D4_7T.";".$D8T.";".$D9T.";".$D15T."\n");

my $Battery_Textstatus = ($Zahl.", ".$D0_3T.", ".$D4_7T.", ".$D8T.", ".$D9T.", ".$D15T); 
#log 1, "EPSOLAR_1 Charging_equipment_Textstatus $Discharge_Fehlercode \n";
fhem("setreading EPSOLAR_1 Battery_Textstatus $Battery_Textstatus");
return $Battery_Textstatus;
}


Für Charging Equipment (C2):
(Achtung siehe auch Code unten - in der Dokumentation ist meiner Meinung ein Fehler für Bit D1 0 = Normal und 1 = Fault. Richtig muss es anders herum sein - zumindest aus meiner Erfahrung. Also Bit D1 1 = Normal und 0 = Fault.

attr EPSOLAR_1 obj-i12801-poll 1
attr EPSOLAR_1 obj-i12801-reading Charging_equipment_status
attr EPSOLAR_1 obj-i12801-showGet 1


#### EPSOLAR Charge Fehlercode in Klartext ausgeben
# Eingabe ist der Fehlercode von Reading obj-i12801-reading (siehe oben)
sub
Charge_Fehlercode(){
#my $Zahl = 0b1111111111111111;
my$Zahl = ReadingsVal("EPSOLAR_1","Charging_equipment_status",0);
my $D0 = $Zahl & 0x01;
my $D1 = $Zahl >> 1;
$D1 = $D1 & 0x01;
my $D2_3 = $Zahl >> 2;
$D2_3 = $D2_3 & 0x03;
my $D4 = $Zahl >> 4;
$D4 = $D4 & 0x01;
my $D5 = $Zahl >> 5;
$D5 = $D5 & 0x01;
my $D6 = $Zahl >> 6;
$D6 = $D6 & 0x01;
my $D7 = $Zahl >> 7;
$D7 = $D7 & 0x01;
my $D8 = $Zahl >> 8;
$D8 = $D8 & 0x01;
my $D9 = $Zahl >> 9;
$D9 = $D9 & 0x01;
my $D10 = $Zahl >> 10;
$D10 = $D10 & 0x01;
my $D11 = $Zahl >> 11;
$D11 = $D11 & 0x01;
my $D12 = $Zahl >> 12;
$D12 = $D12 & 0x01;
my $D13 = $Zahl >> 13;
$D13 = $D13 & 0x01;
my $D14_15 = $Zahl >> 14;
$D14_15 = $D14_15 & 0x03;
# if ($D0 == 1) {$D0t = "Running"};

my $D0T = "ERROR";
my $D1T = "ERROR";
my $D2_3T = "ERROR";
my $D4T = "ERROR";
my $D5T = "ERROR";
my $D6T = "ERROR";
my $D7T = "ERROR";
my $D8T = "ERROR";
my $D9T = "ERROR";
my $D10T = "ERROR";
my $D11T = "ERROR";
my $D12T = "ERROR";
my $D13T = "ERROR";
my $D14_15T = "ERROR";

$D0T = "Running" if ($D0 == 1);
$D0T = "Standby" if ($D0 == 0);
    # gegenüber der Dokumentation habe ich D1 0 und 1 getauscht, weil im Betrieb in der Regel Fehler angezeigt wurde aber alles normal war (kein weites Bit für die Art des Fehlers gesetzt. BSP 07.03.2021
$D1T = "Normal" if ($D1 == 1);
$D1T = "Fault" if ($D1 == 0);
$D2_3T = "Charging status. 00 No charging" if ($D2_3 == 0);
$D2_3T = "Charging status. 01 Float" if ($D2_3 == 1);
$D2_3T = "Charging status. 02Boost" if ($D2_3 == 2);
$D2_3T = "Charging status. 03 Equalization" if ($D2_3 == 3);
$D4T = "" if ($D4 == 0);
$D4T = "PV Input is short" if ($D4 == 1);
$D5T = "" if ($D5 == 0);
$D5T = "" if ($D5 == 1);
$D6T = "" if ($D6 == 0);
$D6T = "" if ($D6 == 1);
$D7T = "" if ($D7 == 0);
$D7T = "Load MOSFET is short" if ($D7 == 1);
$D8T = "" if ($D8 == 0);
$D8T = "The load is short" if ($D8 == 1);
$D9T = "" if ($D9 == 0);
$D9T = "The load is Over current" if ($D9 == 1);
$D10T = "" if ($D10 == 0);
$D10T = "Input is over current" if ($D10 == 1);
$D11T = "" if ($D11 == 0);
$D11T = "Anti-reverse MOSFET is short" if ($D11 == 1);
$D12T = "" if ($D12 == 0);
$D12T = "Charging or Anti-reverse MOSFET is short" if ($D12 == 1);
$D13T = "" if ($D13 == 0);
$D13T = "Charging MOSFET is short" if ($D13 == 1);
$D14_15T = "Input volt status. 00 normal" if ($D14_15 == 0);
$D14_15T = "Input volt status. 01 no power connected" if ($D14_15 == 1);
$D14_15T = "Input volt status. 02 Higher volt input" if ($D14_15 == 2);
$D14_15T = "Input volt status. 03 Input volt error" if ($D14_15 == 3);



#print($D0T.";".$D1T.";".$D2_3T.";".$D4T.";".$D5T.";".$D6T.";".$D7T.";".$D8T.";".$D9T.";".$D10T.";".$D11T.";".$D12T.";".$D13T.";".$D14_15T."\n");
my $Charge_Fehlercode = ($Zahl.", ".$D0T.", ".$D1T.", ".$D2_3T.", ".$D4T.", ".$D5T.", ".$D6T.", ".$D7T.", ".$D8T.", ".$D9T.", ".$D10T.", ".$D11T.", ".$D12T.", ".$D13T.", ".$D14_15T); 
#log 1, "EPSOLAR_1 Charging_equipment_Textstatus $Discharge_Fehlercode \n";
fhem("setreading EPSOLAR_1 Charging_equipment_Textstatus $Charge_Fehlercode");
return $Charge_Fehlercode;


}


Für Discharging Equipment (C7):
attr EPSOLAR_1 obj-i12802-poll 1
attr EPSOLAR_1 obj-i12802-reading Discharging_equipment_status
attr EPSOLAR_1 obj-i12802-showGet 1


#### EPSOLAR Discharge Fehlercode in Klartext ausgeben
# Eingabe ist der Fehlercode aus dem Reading obj-i12802-reading (siehe oben)
sub
Discharge_Fehlercode(){
# my $Zahl = 0b1010101010101010;
my$Zahl = ReadingsVal("EPSOLAR_1","Discharging_equipment_status",0);
my $D0 = $Zahl & 0x01;
my $D1 = $Zahl >> 1;
$D1 = $D1 & 0x01;
my $D2 = $Zahl >> 2;
$D2 = $D2 & 0x01;
my $D3 = $Zahl >> 3;
$D3 = $D3 & 0x01;
my $D4 = $Zahl >> 4;
$D4 = $D4 & 0x01;
my $D5 = $Zahl >> 5;
$D5 = $D5 & 0x01;
my $D6 = $Zahl >> 6;
$D6 = $D6 & 0x01;
my $D7 = $Zahl >> 7;
$D7 = $D7 & 0x01;
my $D8 = $Zahl >> 8;
$D8 = $D8 & 0x01;
my $D9 = $Zahl >> 9;
$D9 = $D9 & 0x01;
my $D10 = $Zahl >> 10;
$D10 = $D10 & 0x01;
my $D11 = $Zahl >> 11;
$D11 = $D11 & 0x01;
my $D12_13 = $Zahl >> 12;
$D12_13 = $D12_13 & 0x03;
my $D14_15 = $Zahl >> 14;
$D14_15 = $D14_15 & 0x03;

my $D0T = "ERROR";
my $D1T = "ERROR";
my $D2T = "ERROR";
my $D3T = "ERROR";
my $D4T = "ERROR";
my $D5T = "ERROR";
my $D6T = "ERROR";
my $D7T = "ERROR";
my $D8T = "ERROR";
my $D9T = "ERROR";
my $D10T = "ERROR";
my $D11T = "ERROR";
my $D12_13T = "ERROR";
my $D14_15T = "ERROR";

$D0T = "Running" if ($D0 == 1);
$D0T = "Standby" if ($D0 == 0);
$D1T = "Normal" if ($D1 == 0);
$D1T = "Fault" if ($D1 == 1);
$D2T = "" if ($D2 == 0);
$D2T = "" if ($D2 == 1);
$D3T = "" if ($D3 == 0);
$D3T = "" if ($D3 == 1);
$D4T = "" if ($D4 == 0);
$D4T = "output overpressure" if ($D4 == 1);
$D5T = "" if ($D5 == 0);
$D5T = "boost overpressure" if ($D5 == 1);
$D6T = "" if ($D6 == 0);
$D6T = "high voltage side short circuit" if ($D6 == 1);
$D7T = "" if ($D7 == 0);
$D7T = "input overpressure" if ($D7 == 1);
$D8T = "" if ($D8 == 0);
$D8T = "output voltage abnormal" if ($D8 == 1);
$D9T = "" if ($D9 == 0);
$D9T = "unable to stop discharging" if ($D9 == 1);
$D10T = "" if ($D10 == 0);
$D10T = "unable to discharge" if ($D10 == 1);
$D11T = "" if ($D11 == 0);
$D11T = "short circuit" if ($D11 == 1);
$D12_13T = "output power 00 light load" if ($D12_13 == 0);
$D12_13T = "output power 01 moderate load" if ($D12_13 == 1);
$D12_13T = "output power 02 rated load" if ($D12_13 == 2);
$D12_13T = "output power 03 overload" if ($D12_13 == 3);
$D14_15T = "00 normal" if ($D14_15 == 0);
$D14_15T = "01 low" if ($D14_15 == 1);
$D14_15T = "02 High" if ($D14_15 == 2);
$D14_15T = "03 no access" if ($D14_15 == 3);

my $Discharge_Fehlercode = ($Zahl.", ".$D0T.", ".$D1T.", ".$D2T.", ".$D3T.", ".$D4T.", ".$D5T.", ".$D6T.", ".$D7T.", ".$D8T.", ".$D9T.", ".$D10T.", ".$D11T.", ".$D12_13T.", ".$D14_15T);
#log 1, "EPSOLAR_1 Discharging_equipment_status_Text $Discharge_Fehlercode \n";
#setreading("EPSOLAR_1","Discharging_equipment_status_Text",$Discharge_Fehlercode);
fhem("setreading EPSOLAR_1 Discharging_equipment_Textstatus $Discharge_Fehlercode");
# print($Zahl.",".$D0T.",".$D1T.",".$D2T.",".$D3T.",".$D4T.",".$D5T.",".$D6T.",".$D7T.",".$D8T.",".$D9T.",".$D10T.",".$D11T.",".$D12_13T.",".$D14_15T."\n");
return $Discharge_Fehlercode;
}


Vielleicht klappt es ja noch die Doku einzufügen:


springber

Anbei der Auszug aus der EPEVER Modus Dokumentation Modbus Protokoll V2.3 - Seite 4-5 Fehlercodes Battery, Charging und Discharging.

Und für falls es jemandem hilf auch die ganze Doku.

Viel Grüße

springber

laserrichi

Hallo springber,

jetzt erst den Post gesehen. Ich habe das im Modul ja so drin:
          "i12800" =>  {          'expr' => 'if($val==4){$val="Fault"}elsif($val==3){$val="zu niedrige Spannung Disconnect"}elsif($val==2){$val="Unterspannung"}elsif($val==1){$val="Überspannung"}elsif($val==16){$val="Übertemperatur"}elsif($val==17){$val="Untertemperatur"}elsif($val==128){$val="Batteriewiderstand"}elsif($val==32768){$val="Falsche Batteriespannung"} else{$val="OK"}',
                               'reading' => 'BattStatus',
                       },
          "i12801" =>  {           'map' => '0:Standby 0, 1:Lädtnicht, 3:Fehler, 7:Ladeerhaltung, 11:Boostladung, 15:Equalizing, 16:Panel Kurzschluss , 128:Ausgangs Mosfet Kurzschluss , 256:Ausgangs Kurzschluss , 512:Last Überstrom , 1024:Panel Überstrom , 2048:Anti-reverse MOSFET is short, 4096:Charging or Anti-reverse MOSFET is short, 8192:Charging MOSFET is short, 16384:kein Panel verbunden, 16385:Panelspannung zu hoch, 16386:Panel Spannungsfehler',
                               'reading' => 'SolarladerStatus',
                       },


Meine Philosophie ist alles in ein Modul und keine weiteren Abhängigkeiten in myutils.

Ok beim ersten reading mit if elsif ist das sicher nicht geschickt, bei dem zweiten mit mapping finde ich das schicker.
Hier könnte ich das sicher noch verfeinern.
Das Bitmuster abzubilden ist wohl im Modul selbst so nicht umzusetzen.
Von den annehmbaren zuständen der Bits denke ich das es hier zu keinen mehrfachen Werten kommt. Also das z.b. Batteriewiderstand und Falsche Batteriespannung gleichzeitig auftreten.
Aber sag niemals nie :-) Und die Software in dem China Ladern ist vermutlich auch nicht so ausgereift.

RaspberryPi 4 Bullseye,Homematic,Z-Wave,Rademacher Duofern,Signalduino,Fritz7590,ESPEasy,Tasmota,Robonect,Kameras,1-Wire,Modbus,Solar,Maranz,VU+,ulanzi tc001 mit awtrix light