[ModBusAttr] Werte schreiben als Text ?

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

Vorheriges Thema - Nächstes Thema

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