2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-28 23:14:10 +00:00

70_PylonLowVoltage: contrib V0.1.8

git-svn-id: https://svn.fhem.de/fhem/trunk@27991 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2023-09-23 18:20:14 +00:00
parent 487b265bab
commit 1e4f1458d6

View File

@ -122,6 +122,7 @@ BEGIN {
# Versions History intern (Versions history by Heiko Maaz) # Versions History intern (Versions history by Heiko Maaz)
my %vNotesIntern = ( my %vNotesIntern = (
"0.1.8" => "23.09.2023 new Attr userBatterytype, change manufacturerInfo command hash to LENID=0 ",
"0.1.7" => "20.09.2023 extend possible number of bats from 6 to 8 ", "0.1.7" => "20.09.2023 extend possible number of bats from 6 to 8 ",
"0.1.6" => "19.09.2023 rework of _callAnalogValue, support of more than 15 cells ", "0.1.6" => "19.09.2023 rework of _callAnalogValue, support of more than 15 cells ",
"0.1.5" => "19.09.2023 internal code change ", "0.1.5" => "19.09.2023 internal code change ",
@ -141,6 +142,7 @@ my $invalid = 'unknown'; # default v
my $definterval = 30; # default Abrufintervall der Batteriewerte my $definterval = 30; # default Abrufintervall der Batteriewerte
my $defto = 0.5; # default connection Timeout zum RS485 Gateway my $defto = 0.5; # default connection Timeout zum RS485 Gateway
my @blackl = qw(state nextCycletime); # Ausnahmeliste deleteReadingspec my @blackl = qw(state nextCycletime); # Ausnahmeliste deleteReadingspec
my $age1def = 60; # default Zyklus Abrufklasse statische Werte (s)
# Steuerhashes # Steuerhashes
############### ###############
@ -212,23 +214,24 @@ my %hrsnb = ( # Codierung
# ADR: n=Batterienummer (2-x), m=Group Nr. (0-8), ADR = 0x0n + (0x10 * m) -> f. Batterie 1 = 0x02 + (0x10 * 0) = 0x02 # ADR: n=Batterienummer (2-x), m=Group Nr. (0-8), ADR = 0x0n + (0x10 * m) -> f. Batterie 1 = 0x02 + (0x10 * 0) = 0x02
# CID1: Kommando spezifisch, hier 46H # CID1: Kommando spezifisch, hier 46H
# CID2: Kommando spezifisch, hier 51H # CID2: Kommando spezifisch, hier 51H
# LENGTH: LENID + LCHKSUM -> Pylon LFP V2.8 Doku # LENGTH: LENID + LCHKSUM -> Pylon LFP V3.3 Doku
# INFO: muß hier mit ADR übereinstimmen # LENID = 0 -> LENID = 0000B + 0000B + 0000B = 0000B -> modulo 16 -> 0000B -> bitweise invert = 1111 -> +1 = 0001 0000 -> LCHKSUM = 0000B -> LENGTH = 0000 0000 0000 0000 -> 0000H
# CHKSUM: 32+30+30+32+34+36+35+31+45+30+30+32+30+32 = 02CDH -> modulo 65536 = 02CDH -> bitweise invert = 1111 1101 0011 0010 -> +1 = 1111 1101 0011 0011 -> FD33H # wenn LENID = 0, dann ist INFO empty (Doku LFP V3.3 S.8)
# CHKSUM: 32+30+30+33+34+36+35+31+30+30+30+30 = 0255H -> modulo 65536 = 0255H -> bitweise invert = 1111 1101 1010 1010 -> +1 = 1111 1101 1010 1011 -> FDABH
# #
# SOI VER ADR CID1 CID2 LENGTH INFO CHKSUM # SOI VER ADR CID1 CID2 LENGTH INFO CHKSUM
# ~ 20 02 46 51 E0 02 02 FD 33 # ~ 20 02 46 51 00 00 empty FD AC
# 7E 32 30 30 32 34 36 35 31 45 30 30 32 30 32 46 44 32 44 # 7E 32 30 30 33 34 36 35 31 30 30 30 30 - - 46 44 41 43
# #
my %hrmfi = ( # Codierung Abruf manufacturerInfo, mlen = Mindestlänge Antwortstring my %hrmfi = ( # Codierung Abruf manufacturerInfo, mlen = Mindestlänge Antwortstring
1 => { cmd => "~20024651E00202FD33\x{0d}", mlen => 82 }, 1 => { cmd => "~200246510000FDAC\x{0d}", mlen => 82 },
2 => { cmd => "~20034651E00203FD31\x{0d}", mlen => 82 }, 2 => { cmd => "~200346510000FDAB\x{0d}", mlen => 82 },
3 => { cmd => "~20044651E00204FD2F\x{0d}", mlen => 82 }, 3 => { cmd => "~200446510000FDAA\x{0d}", mlen => 82 },
4 => { cmd => "~20054651E00205FD2D\x{0d}", mlen => 82 }, 4 => { cmd => "~200546510000FDA9\x{0d}", mlen => 82 },
5 => { cmd => "~20064651E00206FD2B\x{0d}", mlen => 82 }, 5 => { cmd => "~200646510000FDA8\x{0d}", mlen => 82 },
6 => { cmd => "~20074651E00207FD29\x{0d}", mlen => 82 }, 6 => { cmd => "~200746510000FDA7\x{0d}", mlen => 82 },
7 => { cmd => "~20084651E00208FD27\x{0d}", mlen => 82 }, 7 => { cmd => "~200846510000FDA6\x{0d}", mlen => 82 },
8 => { cmd => "~20094651E00209FD25\x{0d}", mlen => 82 }, 8 => { cmd => "~200946510000FDA5\x{0d}", mlen => 82 },
); );
# request command für '1': ~20024651E00202FD33 + CR # request command für '1': ~20024651E00202FD33 + CR
@ -326,6 +329,7 @@ sub Initialize {
$hash->{AttrList} = "disable:1,0 ". $hash->{AttrList} = "disable:1,0 ".
"interval ". "interval ".
"timeout ". "timeout ".
"userBatterytype ".
$readingFnAttributes; $readingFnAttributes;
eval { FHEM::Meta::InitMod( __FILE__, $hash ) }; ## no critic 'eval' eval { FHEM::Meta::InitMod( __FILE__, $hash ) }; ## no critic 'eval'
@ -443,15 +447,20 @@ sub Attr {
} }
} }
if ($aName eq "interval") { if ($aName eq 'interval') {
if (!looks_like_number($aVal)) { if (!looks_like_number($aVal)) {
return qq{The value for $aName is invalid, it must be numeric!}; return qq{The value for $aName is invalid, it must be numeric!};
} }
InternalTimer(gettimeofday()+1.0, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0); InternalTimer(gettimeofday()+1.0, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0);
} }
if ($aName eq 'userBatterytype') {
$hash->{HELPER}{AGE1} = 0;
InternalTimer(gettimeofday()+1.0, "FHEM::PylonLowVoltage::manageUpdate", $hash, 0);
}
if ($aName eq "timeout") { if ($aName eq 'timeout') {
if (!looks_like_number($aVal)) { if (!looks_like_number($aVal)) {
return qq{The value for $aName is invalid, it must be numeric!}; return qq{The value for $aName is invalid, it must be numeric!};
} }
@ -465,7 +474,9 @@ 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;
RemoveInternalTimer ($hash); RemoveInternalTimer ($hash);
@ -497,7 +508,7 @@ sub manageUpdate {
if ($timeout < 1.0) { if ($timeout < 1.0) {
BlockingKill ($hash->{HELPER}{BKRUNNING}) if(defined $hash->{HELPER}{BKRUNNING}); BlockingKill ($hash->{HELPER}{BKRUNNING}) if(defined $hash->{HELPER}{BKRUNNING});
Log3 ($name, 4, qq{$name - Cycle started in main process}); Log3 ($name, 4, qq{$name - Cycle started in main process});
startUpdate ({ name => $name, timeout => $timeout, readings => $readings}); startUpdate ({name => $name, timeout => $timeout, readings => $readings, age1 => $age1});
} }
else { else {
delete $hash->{HELPER}{BKRUNNING} if(defined $hash->{HELPER}{BKRUNNING} && $hash->{HELPER}{BKRUNNING}{pid} =~ /DEAD/xs); delete $hash->{HELPER}{BKRUNNING} if(defined $hash->{HELPER}{BKRUNNING} && $hash->{HELPER}{BKRUNNING}{pid} =~ /DEAD/xs);
@ -511,7 +522,7 @@ sub manageUpdate {
my $blto = sprintf "%.0f", ($timeout + 10); my $blto = sprintf "%.0f", ($timeout + 10);
$hash->{HELPER}{BKRUNNING} = BlockingCall ( "FHEM::PylonLowVoltage::startUpdate", $hash->{HELPER}{BKRUNNING} = BlockingCall ( "FHEM::PylonLowVoltage::startUpdate",
{block => 1, name => $name, timeout => $timeout, readings => $readings}, {name => $name, timeout => $timeout, readings => $readings, age1 => $age1, block => 1},
"FHEM::PylonLowVoltage::finishUpdate", "FHEM::PylonLowVoltage::finishUpdate",
$blto, # Blocking Timeout höher als INET-Timeout! $blto, # Blocking Timeout höher als INET-Timeout!
"FHEM::PylonLowVoltage::abortUpdate", "FHEM::PylonLowVoltage::abortUpdate",
@ -539,6 +550,7 @@ sub startUpdate {
my $timeout = $paref->{timeout}; my $timeout = $paref->{timeout};
my $readings = $paref->{readings}; my $readings = $paref->{readings};
my $block = $paref->{block} // 0; my $block = $paref->{block} // 0;
my $age1 = $paref->{age1};
my $hash = $defs{$name}; my $hash = $defs{$name};
my $success = 0; my $success = 0;
@ -556,7 +568,7 @@ sub startUpdate {
$block ? return ($serial) : return \&finishUpdate ($serial); $block ? return ($serial) : return \&finishUpdate ($serial);
} }
if (ReadingsAge ($name, "serialNumber", 601) >= 60) { # Abrufklasse statische Werte if (ReadingsAge ($name, "serialNumber", 6000) >= $age1) { # Abrufklasse statische Werte
for my $idx (sort keys %fns1) { for my $idx (sort keys %fns1) {
if (&{$fns1{$idx}{fn}} ($hash, $socket, $readings)) { if (&{$fns1{$idx}{fn}} ($hash, $socket, $readings)) {
$serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), ""); $serial = encode_base64 (Serialize ( {name => $name, readings => $readings} ), "");
@ -786,13 +798,15 @@ sub _callManufacturerInfo {
} }
__resultLog ($hash, $res); __resultLog ($hash, $res);
my $BatteryHex = substr ($res, 13, 20); my $name = $hash->{NAME};
my $ubtt = AttrVal ($name, 'userBatterytype', ''); # evtl. Batterietyp manuell überschreiben
my $BatteryHex = substr ($res, 13, 20);
# my $softwareVersion = 'V'.hex (substr ($res, 33, 2)).'.'.hex (substr ($res, 35, 2)); # unklare Bedeutung # my $softwareVersion = 'V'.hex (substr ($res, 33, 2)).'.'.hex (substr ($res, 35, 2)); # unklare Bedeutung
my $ManufacturerHex = substr ($res, 37, 40); my $ManufacturerHex = substr ($res, 37, 40);
$readings->{batteryType} = pack ("H*", $BatteryHex); $readings->{batteryType} = $ubtt ? $ubtt.' (adapted)' : pack ("H*", $BatteryHex);
$readings->{Manufacturer} = pack ("H*", $ManufacturerHex); $readings->{Manufacturer} = pack ("H*", $ManufacturerHex);
return; return;
} }
@ -906,7 +920,7 @@ sub _callSystemParameters {
$readings->{paramModuleUnderVoltLimit} = sprintf "%.3f", (hex substr ($res, 47, 4)) / 1000; # Schutz Limit $readings->{paramModuleUnderVoltLimit} = sprintf "%.3f", (hex substr ($res, 47, 4)) / 1000; # Schutz Limit
$readings->{paramDischargeHighTempLimit} = sprintf "%.1f", ((hex substr ($res, 51, 4)) - 2731) / 10; $readings->{paramDischargeHighTempLimit} = sprintf "%.1f", ((hex substr ($res, 51, 4)) - 2731) / 10;
$readings->{paramDischargeLowTempLimit} = sprintf "%.1f", ((hex substr ($res, 55, 4)) - 2731) / 10; $readings->{paramDischargeLowTempLimit} = sprintf "%.1f", ((hex substr ($res, 55, 4)) - 2731) / 10;
$readings->{paramDischargeCurrentLimit} = sprintf "%.3f", (65535 - (hex substr ($res, 59, 4))) * 100 / 1000; # mit Symbol (-) $readings->{paramDischargeCurrentLimit} = sprintf "%.3f", (65535 - (hex substr ($res, 59, 4))) * 100 / 1000; # mit Symbol (-)
return; return;
} }
@ -1036,18 +1050,14 @@ sub _callAnalogValue {
my $pcc = hex (substr($res, $bpos, 2)); # Anzahl Zellen (15 od. 16) my $pcc = hex (substr($res, $bpos, 2)); # Anzahl Zellen (15 od. 16)
$bpos += 2; # Pos 19 $bpos += 2; # Pos 19
$readings->{packCellcount} = $pcc; for my $z (1..$pcc) {
my $fz = sprintf "%02d", $z; # formatierter Zähler
for my $z (0..$pcc-1) { $readings->{'cellVoltage_'.$fz} = sprintf "%.3f", hex(substr($res, $bpos, 4)) / 1000; # Pos 19 - 75 bei 15 Zellen
my $fz = sprintf "%02d", ($z + 1); # formatierter Zähler $bpos += 4; # letzter Durchlauf: Pos 79 bei 15 Zellen, Pos 83 bei 16 Zellen
my $pos = $bpos + ($z * 4); # Startposition
$readings->{'cellVoltage_'.$fz} = sprintf "%.3f", hex(substr($res, $pos, 4)) / 1000; # Pos 19 - 75 bei 15 Zellen
} }
$bpos += $pcc * 4; # Pos 79 bei 15 Zellen, Pos 83 bei 16 Zellen
$readings->{numberTempPos} = hex(substr($res, $bpos, 2)); # Anzahl der jetzt folgenden Teperaturpositionen -> 5 $readings->{numberTempPos} = hex(substr($res, $bpos, 2)); # Anzahl der jetzt folgenden Teperaturpositionen -> 5
$bpos += 2; $bpos += 2;
$readings->{bmsTemperature} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 81 bei 15 Zellen $readings->{bmsTemperature} = (hex (substr($res, $bpos, 4)) - 2731) / 10; # Pos 81 bei 15 Zellen
$bpos += 4; $bpos += 4;
@ -1112,8 +1122,9 @@ sub _callAnalogValue {
if ($current & 0x8000) { if ($current & 0x8000) {
$current = $current - 0x10000; $current = $current - 0x10000;
} }
$readings->{packCurrent} = sprintf "%.3f", $current / 10; $readings->{packCellcount} = $pcc;
$readings->{packCurrent} = sprintf "%.3f", $current / 10;
return; return;
} }
@ -1472,6 +1483,12 @@ management system via the RS485 interface.
(BlockingCall) so that write or read delays on the RS485 interface do not lead to blocking states in FHEM. (BlockingCall) so that write or read delays on the RS485 interface do not lead to blocking states in FHEM.
</li> </li>
<br> <br>
<a id="PylonLowVoltage-attr-userBatterytype"></a>
<li><b>userBatterytype</b><br>
The automatically determined battery type (Reading batteryType) is replaced by the specified string.
</li>
<br>
</ul> </ul>
<a id="PylonLowVoltage-readings"></a> <a id="PylonLowVoltage-readings"></a>
@ -1643,6 +1660,12 @@ Batteriemanagementsystem über die RS485-Schnittstelle zur Verfügung stellt.
blockierenden Zuständen in FHEM führen. blockierenden Zuständen in FHEM führen.
</li> </li>
<br> <br>
<a id="PylonLowVoltage-attr-userBatterytype"></a>
<li><b>userBatterytype</b><br>
Der automatisch ermittelte Batterietyp (Reading batteryType) durch die angegebene Zeichenfolge ersetzt.
</li>
<br>
</ul> </ul>
<a id="PylonLowVoltage-readings"></a> <a id="PylonLowVoltage-readings"></a>