mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-26 04:24:53 +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:
parent
08e43eab08
commit
a45c7b6514
fhem
@ -1,5 +1,6 @@
|
||||
# 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
|
||||
- feature: 70_PylonLowVoltage: add specific Alarm readings, support of US5000
|
||||
- bugfix: 73_PRESENCE2: BlockingCall loglevel = GetVerbose($name)
|
||||
- bugfix: 73_PRESENCE: BlockingCall loglevel = GetVerbose($name)
|
||||
- bugfix: 98_CDCOpenData: BlockingCall loglevel = GetVerbose($name)
|
||||
|
@ -122,6 +122,8 @@ BEGIN {
|
||||
|
||||
# Versions History intern (Versions history by Heiko Maaz)
|
||||
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.3" => "19.03.2024 edit commandref ",
|
||||
"0.2.2" => "20.02.2024 correct commandref ",
|
||||
@ -177,10 +179,16 @@ my %fns1 = ( #
|
||||
);
|
||||
|
||||
my %fns2 = ( # Abrufklasse dynamische Werte:
|
||||
1 => { fn => \&_callAlarmInfo }, # alarmInfo
|
||||
2 => { fn => \&_callChargeManagmentInfo }, # chargeManagmentInfo
|
||||
3 => { fn => \&_callAnalogValue }, # analogValue
|
||||
|
||||
1 => { fn => \&_callAnalogValue }, # analogValue
|
||||
2 => { fn => \&_callAlarmInfo }, # alarmInfo
|
||||
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,30 +574,29 @@ return;
|
||||
###############################################################
|
||||
sub manageUpdate {
|
||||
my $hash = shift;
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
my $age1 = delete $hash->{HELPER}{AGE1} // $age1def;
|
||||
|
||||
RemoveInternalTimer ($hash);
|
||||
|
||||
if(!$init_done) {
|
||||
if (!$init_done) {
|
||||
InternalTimer(gettimeofday() + 2, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
return if(IsDisabled ($name));
|
||||
|
||||
my $interval = AttrVal ($name, 'interval', $definterval); # 0 -> manuell gesteuert
|
||||
my $timeout = AttrVal ($name, 'timeout', $defto);
|
||||
my $interval = AttrVal ($name, 'interval', $definterval); # 0 -> manuell gesteuert
|
||||
my $timeout = AttrVal ($name, 'timeout', $defto);
|
||||
my $readings;
|
||||
|
||||
if(!$interval) {
|
||||
if (!$interval) {
|
||||
$hash->{OPMODE} = 'Manual';
|
||||
$readings->{nextCycletime} = 'Manual';
|
||||
}
|
||||
else {
|
||||
my $new = gettimeofday() + $interval;
|
||||
InternalTimer ($new, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0); # Wiederholungsintervall
|
||||
InternalTimer ($new, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0); # Wiederholungsintervall
|
||||
|
||||
$hash->{OPMODE} = 'Automatic';
|
||||
$readings->{nextCycletime} = FmtTime($new);
|
||||
@ -1025,6 +1032,130 @@ sub _callSystemParameters {
|
||||
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
|
||||
###############################################################
|
||||
@ -1054,19 +1185,77 @@ sub _callAlarmInfo {
|
||||
}
|
||||
|
||||
__resultLog ($hash, $res);
|
||||
|
||||
my ($alm, $aval);
|
||||
|
||||
my $bpos = 17; # Startposition
|
||||
$readings->{packCellcount} = hex (substr($res, $bpos, 2)); # Pos. 17
|
||||
$bpos += 2;
|
||||
|
||||
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;
|
||||
|
||||
$readings->{packCellcount} = hex (substr($res, 17, 2));
|
||||
|
||||
if (substr($res, 19, 30) eq "000000000000000000000000000000" &&
|
||||
substr($res, 51, 10) eq "0000000000" &&
|
||||
substr($res, 67, 2) eq "00" &&
|
||||
substr($res, 73, 4) eq "0000") {
|
||||
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";
|
||||
}
|
||||
else {
|
||||
$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;
|
||||
}
|
||||
|
||||
@ -1115,124 +1304,6 @@ sub _callChargeManagmentInfo {
|
||||
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
|
||||
###############################################################
|
||||
@ -1385,7 +1456,7 @@ sub pseudoHexToText {
|
||||
my $charcode;
|
||||
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
|
||||
next if($charcode == 45); # Hyphen '-' ausblenden
|
||||
|
||||
@ -1520,6 +1591,7 @@ return;
|
||||
<li> US2000 Plus </li>
|
||||
<li> US3000 </li>
|
||||
<li> US3000C </li>
|
||||
<li> US5000 </li>
|
||||
</ul>
|
||||
|
||||
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_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_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"
|
||||
cell packs are connected in series. Each cell pack consists of single cells
|
||||
connected in parallel. </li>
|
||||
@ -1743,6 +1816,7 @@ return;
|
||||
<li> US2000 Plus </li>
|
||||
<li> US3000 </li>
|
||||
<li> US3000C </li>
|
||||
<li> US5000 </li>
|
||||
</ul>
|
||||
|
||||
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_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_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"
|
||||
Zellenpacks in Serie geschaltet verbaut. Jedes Zellenpack besteht aus parallel
|
||||
geschalten Einzelzellen. </li>
|
||||
|
Loading…
x
Reference in New Issue
Block a user