2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-25 09:55:38 +00:00

70_PylonLowVoltage: contrib V0.1.2

git-svn-id: https://svn.fhem.de/fhem/trunk@27862 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2023-08-20 15:32:47 +00:00
parent a97e70a2f8
commit 1ec6cbe744

View File

@ -116,7 +116,7 @@ BEGIN {
# Versions History intern (Versions history by Heiko Maaz)
my %vNotesIntern = (
"0.1.2" => "20.08.2023 commandref revised, analogValue -> use 'user defined items' ",
"0.1.2" => "20.08.2023 commandref revised, analogValue -> use 'user defined items', refactoring according PBP ",
"0.1.1" => "16.08.2023 integrate US3000C, add print request command in HEX to Logfile, attr timeout ".
"change validation of received data, change DEF format, extend evaluation of chargeManagmentInfo ".
"add evaluate systemParameters, additional own values packImbalance, packState ",
@ -471,8 +471,6 @@ sub Update {
my $interval = AttrVal ($name, 'interval', $definterval); # 0 -> manuell gesteuert
my $timeout = AttrVal ($name, 'timeout', $defto);
my %readings = ();
my $protocol = 'tcp';
my $rtnerr = q{};
my ($socket, $success);
@ -494,270 +492,20 @@ sub Update {
local $SIG{ALRM} = sub { croak 'gatewaytimeout' };
ualarm ($timeout * 1000000); # ualarm in Mikrosekunden
$socket = IO::Socket::INET->new( Proto => $protocol,
PeerAddr => $hash->{HOST},
PeerPort => $hash->{PORT},
Timeout => $timeout
);
if (!$socket) {
doOnError ({ hash => $hash,
readings => \%readings,
state => 'no socket is established to RS485 gateway'
}
);
return;
}
if (!$socket->connected()) {
doOnError ({ hash => $hash,
readings => \%readings,
sock => $socket,
state => 'disconnected'
}
);
return;
}
IO::Socket::Timeout->enable_timeouts_on ($socket); # nur notwendig für read or write timeout
my $rwto = $timeout - 0.05;
$rwto = $rwto <= 0 ? 0.005 : $rwto;
$socket = _createSocket ($hash, $timeout, \%readings);
return if(!$socket);
$socket->read_timeout ($rwto); # Read/Writetimeout immer kleiner als Sockettimeout
$socket->write_timeout ($rwto);
$socket->autoflush(1);
my $res;
# relativ statische Werte abrufen
###################################
if (ReadingsAge ($name, "serialNumber", 601) >= 60) {
# Abruf serialNumber
#####################
$res = Request($hash, $socket, $hrsnb{$hash->{BATADDRESS}}{cmd}, 'serialNumber');
$rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => \%readings,
sock => $socket,
state => $rtnerr
}
);
return;
}
my $sernum = substr ($res, 15, 32);
$readings{serialNumber} = pack ("H*", $sernum);
# Abruf manufacturerInfo
#########################
$res = Request($hash, $socket, $hrmfi{$hash->{BATADDRESS}}{cmd}, 'manufacturerInfo');
$rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => \%readings,
sock => $socket,
state => $rtnerr
}
);
return;
}
my $BatteryHex = substr ($res, 13, 20);
$readings{batteryType} = pack ("H*", $BatteryHex);
$readings{softwareVersion} = 'V'.hex (substr ($res, 33, 2)).'.'.hex (substr ($res, 35, 2)); # substr ($res, 33, 4);
my $ManufacturerHex = substr ($res, 37, 40);
$readings{Manufacturer} = pack ("H*", $ManufacturerHex);
# Abruf protocolVersion
########################
$res = Request($hash, $socket, $hrprt{$hash->{BATADDRESS}}{cmd}, 'protocolVersion');
$rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => \%readings,
sock => $socket,
state => $rtnerr
}
);
return;
}
$readings{protocolVersion} = 'V'.hex (substr ($res, 1, 1)).'.'.hex (substr ($res, 2, 1));
# Abruf softwareVersion
########################
$res = Request($hash, $socket, $hrswv{$hash->{BATADDRESS}}{cmd}, 'softwareVersion');
$rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => \%readings,
sock => $socket,
state => $rtnerr
}
);
return;
}
$readings{moduleSoftwareVersion_manufacture} = 'V'.hex (substr ($res, 15, 2)).'.'.hex (substr ($res, 17, 2));
$readings{moduleSoftwareVersion_mainline} = 'V'.hex (substr ($res, 19, 2)).'.'.hex (substr ($res, 21, 2)).'.'.hex (substr ($res, 23, 2));
# Abruf Systemparameter
########################
$res = Request($hash, $socket, $hrspm{$hash->{BATADDRESS}}{cmd}, 'systemParameters');
$rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => \%readings,
sock => $socket,
state => $rtnerr
}
);
return;
}
$readings{paramCellHighVoltLimit} = sprintf "%.3f", (hex substr ($res, 15, 4)) / 1000;
$readings{paramCellLowVoltLimit} = sprintf "%.3f", (hex substr ($res, 19, 4)) / 1000; # Alarm Limit
$readings{paramCellUnderVoltLimit} = sprintf "%.3f", (hex substr ($res, 23, 4)) / 1000; # Schutz Limit
$readings{paramChargeHighTempLimit} = sprintf "%.1f", ((hex substr ($res, 27, 4)) - 2731) / 10;
$readings{paramChargeLowTempLimit} = sprintf "%.1f", ((hex substr ($res, 31, 4)) - 2731) / 10;
$readings{paramChargeCurrentLimit} = sprintf "%.3f", (hex substr ($res, 35, 4)) * 100 / 1000;
$readings{paramModuleHighVoltLimit} = sprintf "%.3f", (hex substr ($res, 39, 4)) / 1000;
$readings{paramModuleLowVoltLimit} = sprintf "%.3f", (hex substr ($res, 43, 4)) / 1000; # Alarm 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{paramDischargeLowTempLimit} = sprintf "%.1f", ((hex substr ($res, 55, 4)) - 2731) / 10;
$readings{paramDischargeCurrentLimit} = sprintf "%.3f", (65535 - (hex substr ($res, 59, 4))) * 100 / 1000; # mit Symbol (-)
}
# Abruf alarmInfo
##################
$res = Request($hash, $socket, $hralm{$hash->{BATADDRESS}}{cmd}, 'alarmInfo');
$rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => \%readings,
sock => $socket,
state => $rtnerr
}
);
return;
}
$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") {
$readings{packAlarmInfo} = "ok";
}
else {
$readings{packAlarmInfo} = "failure";
}
# Abruf chargeManagmentInfo
############################
$res = Request($hash, $socket, $hrcmi{$hash->{BATADDRESS}}{cmd}, 'chargeManagmentInfo');
$rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => \%readings,
sock => $socket,
state => $rtnerr
}
);
return;
}
$readings{chargeVoltageLimit} = sprintf "%.3f", hex (substr ($res, 15, 4)) / 1000; # Genauigkeit 3
$readings{dischargeVoltageLimit} = sprintf "%.3f", hex (substr ($res, 19, 4)) / 1000; # Genauigkeit 3
$readings{chargeCurrentLimit} = sprintf "%.1f", hex (substr ($res, 23, 4)) / 10; # Genauigkeit 1
$readings{dischargeCurrentLimit} = sprintf "%.1f", (65536 - hex substr ($res, 27, 4)) / 10; # Genauigkeit 1, Fixed point, unsigned integer
my $cdstat = sprintf "%08b", hex substr ($res, 31, 2); # Rohstatus
$readings{chargeEnable} = substr ($cdstat, 0, 1) == 1 ? 'yes' : 'no'; # Bit 7
$readings{dischargeEnable} = substr ($cdstat, 1, 1) == 1 ? 'yes' : 'no'; # Bit 6
$readings{chargeImmediatelySOC05} = substr ($cdstat, 2, 1) == 1 ? 'yes' : 'no'; # Bit 5 - SOC 5~9% -> für Wechselrichter, die aktives Batteriemanagement bei gegebener DC-Spannungsfunktion haben oder Wechselrichter, der von sich aus einen niedrigen SOC/Spannungsgrenzwert hat
$readings{chargeImmediatelySOC09} = substr ($cdstat, 3, 1) == 1 ? 'yes' : 'no'; # Bit 4 - SOC 9~13% -> für Wechselrichter hat keine aktive Batterieabschaltung haben
$readings{chargeFullRequest} = substr ($cdstat, 4, 1) == 1 ? 'yes' : 'no'; # Bit 3 - wenn SOC in 30 Tagen nie höher als 97% -> Flag = 1, wenn SOC-Wert ≥ 97% -> Flag = 0
# 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)
###############################################################################
$res = Request($hash, $socket, $hrcmn{$hash->{BATADDRESS}}{cmd}, 'analogValue');
$rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => \%readings,
sock => $socket,
state => $rtnerr
}
);
return;
}
$readings{packCellcount} = hex (substr($res, 17, 2));
$readings{cellVoltage_01} = sprintf "%.3f", hex(substr($res,19,4)) / 1000;
$readings{cellVoltage_02} = sprintf "%.3f", hex(substr($res,23,4)) / 1000;
$readings{cellVoltage_03} = sprintf "%.3f", hex(substr($res,27,4)) / 1000;
$readings{cellVoltage_04} = sprintf "%.3f", hex(substr($res,31,4)) / 1000;
$readings{cellVoltage_05} = sprintf "%.3f", hex(substr($res,35,4)) / 1000;
$readings{cellVoltage_06} = sprintf "%.3f", hex(substr($res,39,4)) / 1000;
$readings{cellVoltage_07} = sprintf "%.3f", hex(substr($res,43,4)) / 1000;
$readings{cellVoltage_08} = sprintf "%.3f", hex(substr($res,47,4)) / 1000;
$readings{cellVoltage_09} = sprintf "%.3f", hex(substr($res,51,4)) / 1000;
$readings{cellVoltage_10} = sprintf "%.3f", hex(substr($res,55,4)) / 1000;
$readings{cellVoltage_11} = sprintf "%.3f", hex(substr($res,59,4)) / 1000;
$readings{cellVoltage_12} = sprintf "%.3f", hex(substr($res,63,4)) / 1000;
$readings{cellVoltage_13} = sprintf "%.3f", hex(substr($res,67,4)) / 1000;
$readings{cellVoltage_14} = sprintf "%.3f", hex(substr($res,71,4)) / 1000;
$readings{cellVoltage_15} = sprintf "%.3f", hex(substr($res,75,4)) / 1000;
# $readings{numberOfTempPos} = hex(substr($res,79,2)); # Anzahl der jetzt folgenden Teperaturpositionen -> 5
$readings{bmsTemperature} = (hex (substr($res, 81, 4)) - 2731) / 10; # 1
$readings{cellTemperature_0104} = (hex (substr($res, 85, 4)) - 2731) / 10; # 2
$readings{cellTemperature_0508} = (hex (substr($res, 89, 4)) - 2731) / 10; # 3
$readings{cellTemperature_0912} = (hex (substr($res, 93, 4)) - 2731) / 10; # 4
$readings{cellTemperature_1315} = (hex (substr($res, 97, 4)) - 2731) / 10; # 5
my $current = hex (substr($res, 101, 4));
$readings{packVolt} = hex (substr($res, 105, 4)) / 1000;
if ($current & 0x8000) {
$current = $current - 0x10000;
}
$readings{packCurrent} = sprintf "%.3f", $current / 10;
my $udi = hex substr($res, 113, 2); # user defined item: 2: Batterien <= 65Ah, 4: Batterien > 65Ah
$readings{packCycles} = hex substr($res, 119, 4);
$udi = 0;
if ($udi == 2) {
$readings{packCapacityRemain} = hex (substr($res, 109, 4)) / 1000;
$readings{packCapacity} = hex (substr($res, 115, 4)) / 1000;
}
elsif ($udi == 4) {
$readings{packCapacityRemain} = hex (substr($res, 123, 6)) / 1000;
$readings{packCapacity} = hex (substr($res, 129, 6)) / 1000;
}
else {
doOnError ({ hash => $hash,
readings => \%readings,
sock => $socket,
state => 'wrong value retrieve analogValue -> user defined items: '.$udi
}
);
return;
}
if (ReadingsAge ($name, "serialNumber", 601) >= 60) { # relativ statische Werte abrufen
return if(_callSerialNumber ($hash, $socket, \%readings)); # Abruf serialNumber
return if(_callManufacturerInfo ($hash, $socket, \%readings)); # Abruf manufacturerInfo
return if(_callProtocolVersion ($hash, $socket, \%readings)); # Abruf protocolVersion
return if(_callSoftwareVersion ($hash, $socket, \%readings)); # Abruf softwareVersion
return if(_callSystemParameters ($hash, $socket, \%readings)); # Abruf systemParameters
}
return if(_callAlarmInfo ($hash, $socket, \%readings)); # Abruf alarmInfo
return if(_callChargeManagmentInfo ($hash, $socket, \%readings)); # Abruf chargeManagmentInfo
return if(_callAnalogValue ($hash, $socket, \%readings)); # Abruf analogValue
$success = 1;
}; # eval
@ -795,6 +543,348 @@ $udi = 0;
return;
}
###############################################################
# Socket erstellen
###############################################################
sub _createSocket {
my $hash = shift;
my $timeout = shift;
my $readings = shift; # Referenz auf das Hash der zu erstellenden Readings
my $socket = IO::Socket::INET->new( Proto => 'tcp',
PeerAddr => $hash->{HOST},
PeerPort => $hash->{PORT},
Timeout => $timeout
);
if (!$socket) {
doOnError ({ hash => $hash,
readings => $readings,
state => 'no socket is established to RS485 gateway'
}
);
return;
}
if (!$socket->connected()) {
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
state => 'disconnected'
}
);
return;
}
IO::Socket::Timeout->enable_timeouts_on ($socket); # nur notwendig für read or write timeout
my $rwto = $timeout - 0.05;
$rwto = $rwto <= 0 ? 0.005 : $rwto;
$socket->read_timeout ($rwto); # Read/Writetimeout immer kleiner als Sockettimeout
$socket->write_timeout ($rwto);
$socket->autoflush(1);
return $socket;
}
###############################################################
# Abruf serialNumber
###############################################################
sub _callSerialNumber {
my $hash = shift;
my $socket = shift;
my $readings = shift; # Referenz auf das Hash der zu erstellenden Readings
my $res = Request($hash, $socket, $hrsnb{$hash->{BATADDRESS}}{cmd}, 'serialNumber');
my $rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
state => $rtnerr
}
);
return $rtnerr;
}
my $sernum = substr ($res, 15, 32);
$readings->{serialNumber} = pack ("H*", $sernum);
return;
}
###############################################################
# Abruf manufacturerInfo
###############################################################
sub _callManufacturerInfo {
my $hash = shift;
my $socket = shift;
my $readings = shift; # Referenz auf das Hash der zu erstellenden Readings
my $res = Request($hash, $socket, $hrmfi{$hash->{BATADDRESS}}{cmd}, 'manufacturerInfo');
my $rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
state => $rtnerr
}
);
return $rtnerr;
}
my $BatteryHex = substr ($res, 13, 20);
$readings->{batteryType} = pack ("H*", $BatteryHex);
$readings->{softwareVersion} = 'V'.hex (substr ($res, 33, 2)).'.'.hex (substr ($res, 35, 2)); # substr ($res, 33, 4);
my $ManufacturerHex = substr ($res, 37, 40);
$readings->{Manufacturer} = pack ("H*", $ManufacturerHex);
return;
}
###############################################################
# Abruf protocolVersion
###############################################################
sub _callProtocolVersion {
my $hash = shift;
my $socket = shift;
my $readings = shift; # Referenz auf das Hash der zu erstellenden Readings
my $res = Request($hash, $socket, $hrprt{$hash->{BATADDRESS}}{cmd}, 'protocolVersion');
my $rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
state => $rtnerr
}
);
return $rtnerr;
}
$readings->{protocolVersion} = 'V'.hex (substr ($res, 1, 1)).'.'.hex (substr ($res, 2, 1));
return;
}
###############################################################
# Abruf softwareVersion
###############################################################
sub _callSoftwareVersion {
my $hash = shift;
my $socket = shift;
my $readings = shift; # Referenz auf das Hash der zu erstellenden Readings
my $res = Request($hash, $socket, $hrswv{$hash->{BATADDRESS}}{cmd}, 'softwareVersion');
my $rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
state => $rtnerr
}
);
return $rtnerr;
}
$readings->{moduleSoftwareVersion_manufacture} = 'V'.hex (substr ($res, 15, 2)).'.'.hex (substr ($res, 17, 2));
$readings->{moduleSoftwareVersion_mainline} = 'V'.hex (substr ($res, 19, 2)).'.'.hex (substr ($res, 21, 2)).'.'.hex (substr ($res, 23, 2));
return;
}
###############################################################
# Abruf systemParameters
###############################################################
sub _callSystemParameters {
my $hash = shift;
my $socket = shift;
my $readings = shift; # Referenz auf das Hash der zu erstellenden Readings
my $res = Request($hash, $socket, $hrspm{$hash->{BATADDRESS}}{cmd}, 'systemParameters');
my $rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
state => $rtnerr
}
);
return $rtnerr;
}
$readings->{paramCellHighVoltLimit} = sprintf "%.3f", (hex substr ($res, 15, 4)) / 1000;
$readings->{paramCellLowVoltLimit} = sprintf "%.3f", (hex substr ($res, 19, 4)) / 1000; # Alarm Limit
$readings->{paramCellUnderVoltLimit} = sprintf "%.3f", (hex substr ($res, 23, 4)) / 1000; # Schutz Limit
$readings->{paramChargeHighTempLimit} = sprintf "%.1f", ((hex substr ($res, 27, 4)) - 2731) / 10;
$readings->{paramChargeLowTempLimit} = sprintf "%.1f", ((hex substr ($res, 31, 4)) - 2731) / 10;
$readings->{paramChargeCurrentLimit} = sprintf "%.3f", (hex substr ($res, 35, 4)) * 100 / 1000;
$readings->{paramModuleHighVoltLimit} = sprintf "%.3f", (hex substr ($res, 39, 4)) / 1000;
$readings->{paramModuleLowVoltLimit} = sprintf "%.3f", (hex substr ($res, 43, 4)) / 1000; # Alarm 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->{paramDischargeLowTempLimit} = sprintf "%.1f", ((hex substr ($res, 55, 4)) - 2731) / 10;
$readings->{paramDischargeCurrentLimit} = sprintf "%.3f", (65535 - (hex substr ($res, 59, 4))) * 100 / 1000; # mit Symbol (-)
return;
}
###############################################################
# Abruf alarmInfo
###############################################################
sub _callAlarmInfo {
my $hash = shift;
my $socket = shift;
my $readings = shift; # Referenz auf das Hash der zu erstellenden Readings
my $res = Request($hash, $socket, $hralm{$hash->{BATADDRESS}}{cmd}, 'alarmInfo');
my $rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
state => $rtnerr
}
);
return $rtnerr;
}
$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") {
$readings->{packAlarmInfo} = "ok";
}
else {
$readings->{packAlarmInfo} = "failure";
}
return;
}
###############################################################
# Abruf chargeManagmentInfo
###############################################################
sub _callChargeManagmentInfo {
my $hash = shift;
my $socket = shift;
my $readings = shift; # Referenz auf das Hash der zu erstellenden Readings
my $res = Request($hash, $socket, $hrcmi{$hash->{BATADDRESS}}{cmd}, 'chargeManagmentInfo');
my $rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
state => $rtnerr
}
);
return $rtnerr;
}
$readings->{chargeVoltageLimit} = sprintf "%.3f", hex (substr ($res, 15, 4)) / 1000; # Genauigkeit 3
$readings->{dischargeVoltageLimit} = sprintf "%.3f", hex (substr ($res, 19, 4)) / 1000; # Genauigkeit 3
$readings->{chargeCurrentLimit} = sprintf "%.1f", hex (substr ($res, 23, 4)) / 10; # Genauigkeit 1
$readings->{dischargeCurrentLimit} = sprintf "%.1f", (65536 - hex substr ($res, 27, 4)) / 10; # Genauigkeit 1, Fixed point, unsigned integer
my $cdstat = sprintf "%08b", hex substr ($res, 31, 2); # Rohstatus
$readings->{chargeEnable} = substr ($cdstat, 0, 1) == 1 ? 'yes' : 'no'; # Bit 7
$readings->{dischargeEnable} = substr ($cdstat, 1, 1) == 1 ? 'yes' : 'no'; # Bit 6
$readings->{chargeImmediatelySOC05} = substr ($cdstat, 2, 1) == 1 ? 'yes' : 'no'; # Bit 5 - SOC 5~9% -> für Wechselrichter, die aktives Batteriemanagement bei gegebener DC-Spannungsfunktion haben oder Wechselrichter, der von sich aus einen niedrigen SOC/Spannungsgrenzwert hat
$readings->{chargeImmediatelySOC09} = substr ($cdstat, 3, 1) == 1 ? 'yes' : 'no'; # Bit 4 - SOC 9~13% -> für Wechselrichter hat keine aktive Batterieabschaltung haben
$readings->{chargeFullRequest} = substr ($cdstat, 4, 1) == 1 ? 'yes' : 'no'; # Bit 3 - wenn SOC in 30 Tagen nie höher als 97% -> Flag = 1, wenn SOC-Wert ≥ 97% -> Flag = 0
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 $res = Request($hash, $socket, $hrcmn{$hash->{BATADDRESS}}{cmd}, 'analogValue');
my $rtnerr = respStat ($res);
if ($rtnerr) {
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
state => $rtnerr
}
);
return $rtnerr;
}
$readings->{packCellcount} = hex (substr($res, 17, 2));
$readings->{cellVoltage_01} = sprintf "%.3f", hex(substr($res,19,4)) / 1000;
$readings->{cellVoltage_02} = sprintf "%.3f", hex(substr($res,23,4)) / 1000;
$readings->{cellVoltage_03} = sprintf "%.3f", hex(substr($res,27,4)) / 1000;
$readings->{cellVoltage_04} = sprintf "%.3f", hex(substr($res,31,4)) / 1000;
$readings->{cellVoltage_05} = sprintf "%.3f", hex(substr($res,35,4)) / 1000;
$readings->{cellVoltage_06} = sprintf "%.3f", hex(substr($res,39,4)) / 1000;
$readings->{cellVoltage_07} = sprintf "%.3f", hex(substr($res,43,4)) / 1000;
$readings->{cellVoltage_08} = sprintf "%.3f", hex(substr($res,47,4)) / 1000;
$readings->{cellVoltage_09} = sprintf "%.3f", hex(substr($res,51,4)) / 1000;
$readings->{cellVoltage_10} = sprintf "%.3f", hex(substr($res,55,4)) / 1000;
$readings->{cellVoltage_11} = sprintf "%.3f", hex(substr($res,59,4)) / 1000;
$readings->{cellVoltage_12} = sprintf "%.3f", hex(substr($res,63,4)) / 1000;
$readings->{cellVoltage_13} = sprintf "%.3f", hex(substr($res,67,4)) / 1000;
$readings->{cellVoltage_14} = sprintf "%.3f", hex(substr($res,71,4)) / 1000;
$readings->{cellVoltage_15} = sprintf "%.3f", hex(substr($res,75,4)) / 1000;
# $readings->{numberOfTempPos} = hex(substr($res,79,2)); # Anzahl der jetzt folgenden Teperaturpositionen -> 5
$readings->{bmsTemperature} = (hex (substr($res, 81, 4)) - 2731) / 10; # 1
$readings->{cellTemperature_0104} = (hex (substr($res, 85, 4)) - 2731) / 10; # 2
$readings->{cellTemperature_0508} = (hex (substr($res, 89, 4)) - 2731) / 10; # 3
$readings->{cellTemperature_0912} = (hex (substr($res, 93, 4)) - 2731) / 10; # 4
$readings->{cellTemperature_1315} = (hex (substr($res, 97, 4)) - 2731) / 10; # 5
my $current = hex (substr($res, 101, 4));
$readings->{packVolt} = hex (substr($res, 105, 4)) / 1000;
if ($current & 0x8000) {
$current = $current - 0x10000;
}
$readings->{packCurrent} = sprintf "%.3f", $current / 10;
my $udi = hex substr($res, 113, 2); # user defined item=Entscheidungskriterium -> 2: Batterien <= 65Ah, 4: Batterien > 65Ah
$readings->{packCycles} = hex substr($res, 119, 4);
if ($udi == 2) {
$readings->{packCapacityRemain} = hex (substr($res, 109, 4)) / 1000;
$readings->{packCapacity} = hex (substr($res, 115, 4)) / 1000;
}
elsif ($udi == 4) {
$readings->{packCapacityRemain} = hex (substr($res, 123, 6)) / 1000;
$readings->{packCapacity} = hex (substr($res, 129, 6)) / 1000;
}
else {
my $err = 'wrong value retrieve analogValue -> user defined items: '.$udi;
doOnError ({ hash => $hash,
readings => $readings,
sock => $socket,
state => $err
}
);
return $err;
}
return;
}
###############################################################
# PylonLowVoltage Request
###############################################################