2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-26 10:34:52 +00:00

70_PylonLowVoltage: add specific Alarm readings, support of US5000

git-svn-id: https://svn.fhem.de/fhem/trunk@28745 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2024-04-03 18:07:33 +00:00
parent 08e43eab08
commit a45c7b6514
2 changed files with 212 additions and 136 deletions

View File

@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it # Do not insert empty lines here, update check depends on it
- feature: 70_PylonLowVoltage: add specific Alarm readings, support of US5000
- bugfix: 73_PRESENCE2: BlockingCall loglevel = GetVerbose($name) - bugfix: 73_PRESENCE2: BlockingCall loglevel = GetVerbose($name)
- bugfix: 73_PRESENCE: BlockingCall loglevel = GetVerbose($name) - bugfix: 73_PRESENCE: BlockingCall loglevel = GetVerbose($name)
- bugfix: 98_CDCOpenData: BlockingCall loglevel = GetVerbose($name) - bugfix: 98_CDCOpenData: BlockingCall loglevel = GetVerbose($name)

View File

@ -122,6 +122,8 @@ BEGIN {
# Versions History intern (Versions history by Heiko Maaz) # Versions History intern (Versions history by Heiko Maaz)
my %vNotesIntern = ( my %vNotesIntern = (
"0.2.5" => "02.04.2024 _callAnalogValue / _callAlarmInfo: integrate a Cell and Temperature Position counter ".
"add specific Alarm readings ",
"0.2.4" => "29.03.2024 avoid possible Illegal division by zero at line 1438 ", "0.2.4" => "29.03.2024 avoid possible Illegal division by zero at line 1438 ",
"0.2.3" => "19.03.2024 edit commandref ", "0.2.3" => "19.03.2024 edit commandref ",
"0.2.2" => "20.02.2024 correct commandref ", "0.2.2" => "20.02.2024 correct commandref ",
@ -177,10 +179,16 @@ my %fns1 = ( #
); );
my %fns2 = ( # Abrufklasse dynamische Werte: my %fns2 = ( # Abrufklasse dynamische Werte:
1 => { fn => \&_callAlarmInfo }, # alarmInfo 1 => { fn => \&_callAnalogValue }, # analogValue
2 => { fn => \&_callChargeManagmentInfo }, # chargeManagmentInfo 2 => { fn => \&_callAlarmInfo }, # alarmInfo
3 => { fn => \&_callAnalogValue }, # analogValue 3 => { fn => \&_callChargeManagmentInfo }, # chargeManagmentInfo
);
my %halm = ( # Codierung Alarme
'00' => { alm => 'normal' },
'01' => { alm => 'below lower limit' },
'02' => { alm => 'above higher limit'},
'F0' => { alm => 'other error' },
); );
################################################################################################################################################################## ##################################################################################################################################################################
@ -566,7 +574,6 @@ return;
############################################################### ###############################################################
sub manageUpdate { sub manageUpdate {
my $hash = shift; my $hash = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $age1 = delete $hash->{HELPER}{AGE1} // $age1def; my $age1 = delete $hash->{HELPER}{AGE1} // $age1def;
@ -1025,6 +1032,130 @@ sub _callSystemParameters {
return; return;
} }
#################################################################################
# Abruf analogValue
# Answer from US2000 = 128 Bytes, from US3000 = 140 Bytes
# Remain capacity US2000 hex(substr($res,109,4), US3000 hex(substr($res,123,6)
# Module capacity US2000 hex(substr($res,115,4), US3000 hex(substr($res,129,6)
#################################################################################
sub _callAnalogValue {
my $hash = shift;
my $socket = shift;
my $readings = shift; # Referenz auf das Hash der zu erstellenden Readings
my $name = $hash->{NAME};
my $res = Request ({ hash => $hash,
socket => $socket,
cmd => $hrcmn{$hash->{BATADDRESS}}{cmd},
cmdtxt => 'analogValue'
}
);
my $rtnerr = responseCheck ($res, $hrcmn{$hash->{BATADDRESS}}{mlen});
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
res => $res,
state => $rtnerr
}
);
return $rtnerr;
}
__resultLog ($hash, $res);
my $bpos = 17; # Startposition
my $pcc = hex (substr($res, $bpos, 2)); # Anzahl Zellen (15 od. 16)
$bpos += 2; # Pos 19
for my $z (1..$pcc) {
my $fz = sprintf "%02d", $z; # formatierter Zähler
$readings->{'cellVoltage_'.$fz} = sprintf "%.3f", hex(substr($res, $bpos, 4)) / 1000; # Pos 19 -> 75 bei 15 Zellen
$bpos += 4; # letzter Durchlauf: Pos 79 bei 15 Zellen, Pos 83 bei 16 Zellen
}
$readings->{numberTempPos} = hex(substr($res, $bpos, 2)); # Anzahl der jetzt folgenden Temperaturpositionen -> 5 oder mehr (US5000: 6)
$bpos += 2;
$readings->{bmsTemperature} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 81 bei 15 Zellen
$bpos += 4;
$readings->{cellTemperature_0104} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 85
$bpos += 4;
$readings->{cellTemperature_0508} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 89
$bpos += 4;
$readings->{cellTemperature_0912} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 93
$bpos += 4;
$readings->{'cellTemperature_13'.$pcc} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 97
$bpos += 4;
for my $t (6..$readings->{numberTempPos}) {
$t = 'Pos_'.sprintf "%02d", $t;
$readings->{'cellTemperature_'.$t} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # mehr als 5 Temperaturpositionen (z.B. US5000)
$bpos += 4; # Position bei 5 Temp.Angaben (bei 6 Temperaturen)
}
my $current = hex (substr($res, $bpos, 4)); # Pos 101 (105)
$bpos += 4;
$readings->{packVolt} = sprintf "%.3f", hex (substr($res, $bpos, 4)) / 1000; # Pos 105 (109)
$bpos += 4;
my $remcap1 = sprintf "%.3f", hex (substr($res, $bpos, 4)) / 1000; # Pos 109 (113)
$bpos += 4;
my $udi = hex substr($res, $bpos, 2); # Pos 113 (117) user defined item=Entscheidungskriterium -> 2: Batterien <= 65Ah, 4: Batterien > 65Ah
$bpos += 2;
my $totcap1 = sprintf "%.3f", hex (substr($res, $bpos, 4)) / 1000; # Pos 115 (119)
$bpos += 4;
$readings->{packCycles} = hex substr($res, $bpos, 4); # Pos 119 (123)
$bpos += 4;
my $remcap2 = sprintf "%.3f", hex (substr($res, $bpos, 6)) / 1000; # Pos 123 (127)
$bpos += 6;
my $totcap2 = sprintf "%.3f", hex (substr($res, $bpos, 6)) / 1000; # Pos 129 (133)
$bpos += 6;
# kalkulierte Werte generieren
################################
if ($udi == 2) {
$readings->{packCapacityRemain} = $remcap1;
$readings->{packCapacity} = $totcap1;
}
elsif ($udi == 4) {
$readings->{packCapacityRemain} = $remcap2;
$readings->{packCapacity} = $totcap2;
}
else {
my $err = 'wrong value retrieve analogValue -> user defined items: '.$udi;
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
res => '',
state => $err
}
);
return $err;
}
if ($current & 0x8000) {
$current = $current - 0x10000;
}
$readings->{packCellcount} = $pcc;
$readings->{packCurrent} = sprintf "%.3f", $current / 10;
return;
}
############################################################### ###############################################################
# Abruf alarmInfo # Abruf alarmInfo
############################################################### ###############################################################
@ -1055,18 +1186,76 @@ sub _callAlarmInfo {
__resultLog ($hash, $res); __resultLog ($hash, $res);
$readings->{packCellcount} = hex (substr($res, 17, 2)); my ($alm, $aval);
if (substr($res, 19, 30) eq "000000000000000000000000000000" && my $bpos = 17; # Startposition
substr($res, 51, 10) eq "0000000000" && $readings->{packCellcount} = hex (substr($res, $bpos, 2)); # Pos. 17
substr($res, 67, 2) eq "00" && $bpos += 2;
substr($res, 73, 4) eq "0000") {
for my $cnt (1..$readings->{packCellcount}) { # Start Pos. 19
$cnt = sprintf "%02d", $cnt;
$aval = substr ($res, $bpos, 2);
$readings->{'almCellVoltage_'.$cnt} = $halm{$aval}{alm};
$alm = 1 if(int $aval);
$bpos += 2;
}
my $ntp = hex (substr($res, $bpos, 2)); # Pos. 49 bei 15 Zellen (Anzahl der Temperaturpositionen)
$bpos += 2;
for my $nt (1..$ntp) { # Start Pos. 51 bei 15 Zellen
$nt = sprintf "%02d", $nt;
$aval = substr ($res, $bpos, 2);
$readings->{'almTemperature_'.$nt} = $halm{$aval}{alm};
$alm = 1 if(int $aval);
$bpos += 2;
}
$aval = substr ($res, $bpos, 2); # Pos. 61 b. 15 Zellen u. 5 Temp.positionen
$readings->{almChargeCurrent} = $halm{$aval}{alm};
$alm = 1 if(int $aval);
$bpos += 2;
$aval = substr ($res, $bpos, 2); # Pos. 63 b. 15 Zellen u. 5 Temp.positionen
$readings->{almModuleVoltage} = $halm{$aval}{alm};
$alm = 1 if(int $aval);
$bpos += 2;
$aval = substr ($res, $bpos, 2); # Pos. 65 b. 15 Zellen u. 5 Temp.positionen
$readings->{almDischargeCurrent} = $halm{$aval}{alm};
$alm = 1 if(int $aval);
$bpos += 2;
my $stat1alm = substr ($res, $bpos, 2); # Pos. 67 b. 15 Zellen u. 5 Temp.positionen
$bpos += 2;
my $stat2alm = substr ($res, $bpos, 2); # Pos. 69 b. 15 Zellen u. 5 Temp.positionen
$bpos += 2;
my $stat3alm = substr ($res, $bpos, 2); # Pos. 71 b. 15 Zellen u. 5 Temp.positionen
$bpos += 2;
my $stat4alm = substr ($res, $bpos, 2); # Pos. 73 b. 15 Zellen u. 5 Temp.positionen
$bpos += 2;
my $stat5alm = substr ($res, $bpos, 2); # Pos. 75 b. 15 Zellen u. 5 Temp.positionen
if (!$alm) {
$readings->{packAlarmInfo} = "ok"; $readings->{packAlarmInfo} = "ok";
} }
else { else {
$readings->{packAlarmInfo} = "failure"; $readings->{packAlarmInfo} = "failure";
} }
my $name = $hash->{NAME};
if (AttrVal ($name, 'verbose', 3) > 4) {
Log3 ($name, 5, "$name - Alarminfo - Status 1 alarm: $stat1alm");
Log3 ($name, 5, "$name - Alarminfo - Status 2 Info: $stat2alm");
Log3 ($name, 5, "$name - Alarminfo - Status 3 Info: $stat3alm");
Log3 ($name, 5, "$name - Alarminfo - Status 4 alarm: $stat4alm");
Log3 ($name, 5, "$name - Alarminfo - Status 5 alarm: $stat5alm \n");
}
return; return;
} }
@ -1115,124 +1304,6 @@ sub _callChargeManagmentInfo {
return; return;
} }
#################################################################################
# Abruf analogValue
# Answer from US2000 = 128 Bytes, from US3000 = 140 Bytes
# Remain capacity US2000 hex(substr($res,109,4), US3000 hex(substr($res,123,6)
# Module capacity US2000 hex(substr($res,115,4), US3000 hex(substr($res,129,6)
#################################################################################
sub _callAnalogValue {
my $hash = shift;
my $socket = shift;
my $readings = shift; # Referenz auf das Hash der zu erstellenden Readings
my $name = $hash->{NAME};
my $res = Request ({ hash => $hash,
socket => $socket,
cmd => $hrcmn{$hash->{BATADDRESS}}{cmd},
cmdtxt => 'analogValue'
}
);
my $rtnerr = responseCheck ($res, $hrcmn{$hash->{BATADDRESS}}{mlen});
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
res => $res,
state => $rtnerr
}
);
return $rtnerr;
}
__resultLog ($hash, $res);
my $bpos = 17; # Startposition
my $pcc = hex (substr($res, $bpos, 2)); # Anzahl Zellen (15 od. 16)
$bpos += 2; # Pos 19
for my $z (1..$pcc) {
my $fz = sprintf "%02d", $z; # formatierter Zähler
$readings->{'cellVoltage_'.$fz} = sprintf "%.3f", hex(substr($res, $bpos, 4)) / 1000; # Pos 19 - 75 bei 15 Zellen
$bpos += 4; # letzter Durchlauf: Pos 79 bei 15 Zellen, Pos 83 bei 16 Zellen
}
$readings->{numberTempPos} = hex(substr($res, $bpos, 2)); # Anzahl der jetzt folgenden Teperaturpositionen -> 5
$bpos += 2;
$readings->{bmsTemperature} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 81 bei 15 Zellen
$bpos += 4;
$readings->{cellTemperature_0104} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 85
$bpos += 4;
$readings->{cellTemperature_0508} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 89
$bpos += 4;
$readings->{cellTemperature_0912} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 93
$bpos += 4;
$readings->{'cellTemperature_13'.$pcc} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 97
$bpos += 4;
my $current = hex (substr($res, $bpos, 4)); # Pos 101
$bpos += 4;
$readings->{packVolt} = sprintf "%.3f", hex (substr($res, $bpos, 4)) / 1000; # Pos 105
$bpos += 4;
my $remcap1 = sprintf "%.3f", hex (substr($res, $bpos, 4)) / 1000; # Pos 109
$bpos += 4;
my $udi = hex substr($res, $bpos, 2); # Pos 113, user defined item=Entscheidungskriterium -> 2: Batterien <= 65Ah, 4: Batterien > 65Ah
$bpos += 2;
my $totcap1 = sprintf "%.3f", hex (substr($res, $bpos, 4)) / 1000; # Pos 115
$bpos += 4;
$readings->{packCycles} = hex substr($res, $bpos, 4); # Pos 119
$bpos += 4;
my $remcap2 = sprintf "%.3f", hex (substr($res, $bpos, 6)) / 1000; # Pos 123
$bpos += 6;
my $totcap2 = sprintf "%.3f", hex (substr($res, $bpos, 6)) / 1000; # Pos 129
$bpos += 6;
# kalkulierte Werte generieren
################################
if ($udi == 2) {
$readings->{packCapacityRemain} = $remcap1;
$readings->{packCapacity} = $totcap1;
}
elsif ($udi == 4) {
$readings->{packCapacityRemain} = $remcap2;
$readings->{packCapacity} = $totcap2;
}
else {
my $err = 'wrong value retrieve analogValue -> user defined items: '.$udi;
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
res => '',
state => $err
}
);
return $err;
}
if ($current & 0x8000) {
$current = $current - 0x10000;
}
$readings->{packCellcount} = $pcc;
$readings->{packCurrent} = sprintf "%.3f", $current / 10;
return;
}
############################################################### ###############################################################
# Logausgabe Result # Logausgabe Result
############################################################### ###############################################################
@ -1385,7 +1456,7 @@ sub pseudoHexToText {
my $charcode; my $charcode;
my $text = ''; my $text = '';
for (my $i = 0; $i < length($string); $i = $i + 2) { for (my $i = 0; $i < length($string); $i += 2) {
$charcode = hex substr ($string, $i, 2); # charcode = aquivalente Dezimalzahl der angegebenen Hexadezimalzahl $charcode = hex substr ($string, $i, 2); # charcode = aquivalente Dezimalzahl der angegebenen Hexadezimalzahl
next if($charcode == 45); # Hyphen '-' ausblenden next if($charcode == 45); # Hyphen '-' ausblenden
@ -1520,6 +1591,7 @@ return;
<li> US2000 Plus </li> <li> US2000 Plus </li>
<li> US3000 </li> <li> US3000 </li>
<li> US3000C </li> <li> US3000C </li>
<li> US5000 </li>
</ul> </ul>
The following devices have been successfully used as RS485 Ethernet gateways to date: <br> The following devices have been successfully used as RS485 Ethernet gateways to date: <br>
@ -1676,6 +1748,7 @@ return;
<li><b>cellTemperature_0508</b><br> Temperature (°C) of cell packs 5 to 8 </li> <li><b>cellTemperature_0508</b><br> Temperature (°C) of cell packs 5 to 8 </li>
<li><b>cellTemperature_0912</b><br> Temperature (°C) of the cell packs 9 to 12 </li> <li><b>cellTemperature_0912</b><br> Temperature (°C) of the cell packs 9 to 12 </li>
<li><b>cellTemperature_1315</b><br> Temperature (°C) of the cell packs 13 to 15 </li> <li><b>cellTemperature_1315</b><br> Temperature (°C) of the cell packs 13 to 15 </li>
<li><b>cellTemperature_Pos_XX</b><br> Temperature (°C) of position XX (not further specified) </li>
<li><b>cellVoltage_XX</b><br> Cell voltage (V) of the cell pack XX. In the battery module "packCellcount" <li><b>cellVoltage_XX</b><br> Cell voltage (V) of the cell pack XX. In the battery module "packCellcount"
cell packs are connected in series. Each cell pack consists of single cells cell packs are connected in series. Each cell pack consists of single cells
connected in parallel. </li> connected in parallel. </li>
@ -1743,6 +1816,7 @@ return;
<li> US2000 Plus </li> <li> US2000 Plus </li>
<li> US3000 </li> <li> US3000 </li>
<li> US3000C </li> <li> US3000C </li>
<li> US5000 </li>
</ul> </ul>
Als RS485-Ethernet-Gateways wurden bisher folgende Geräte erfolgreich eingesetzt: <br> Als RS485-Ethernet-Gateways wurden bisher folgende Geräte erfolgreich eingesetzt: <br>
@ -1900,6 +1974,7 @@ return;
<li><b>cellTemperature_0508</b><br> Temperatur (°C) der Zellenpacks 5 bis 8 </li> <li><b>cellTemperature_0508</b><br> Temperatur (°C) der Zellenpacks 5 bis 8 </li>
<li><b>cellTemperature_0912</b><br> Temperatur (°C) der Zellenpacks 9 bis 12 </li> <li><b>cellTemperature_0912</b><br> Temperatur (°C) der Zellenpacks 9 bis 12 </li>
<li><b>cellTemperature_1315</b><br> Temperatur (°C) der Zellenpacks 13 bis 15 </li> <li><b>cellTemperature_1315</b><br> Temperatur (°C) der Zellenpacks 13 bis 15 </li>
<li><b>cellTemperature_Pos_XX</b><br> Temperatur (°C) der Position XX (nicht näher spezifiziert) </li>
<li><b>cellVoltage_XX</b><br> Zellenspannung (V) des Zellenpacks XX. In dem Batteriemodul sind "packCellcount" <li><b>cellVoltage_XX</b><br> Zellenspannung (V) des Zellenpacks XX. In dem Batteriemodul sind "packCellcount"
Zellenpacks in Serie geschaltet verbaut. Jedes Zellenpack besteht aus parallel Zellenpacks in Serie geschaltet verbaut. Jedes Zellenpack besteht aus parallel
geschalten Einzelzellen. </li> geschalten Einzelzellen. </li>