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:
parent
487b265bab
commit
1e4f1458d6
@ -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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user