mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 18:59:33 +00:00
WMBus: some more fixes for Easymeter, new attribute useVIFasReadingName, new set rawmsg
git-svn-id: https://svn.fhem.de/fhem/trunk@20084 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
c69ee18b06
commit
3eacd88eeb
@ -1,5 +1,5 @@
|
||||
#
|
||||
# kaihs@FHEM_Forum (forum.fhem.de)
|
||||
# kaihs@FHEM_Forum (forum.fhem.de)
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
@ -22,7 +22,7 @@ sub WMBUS_Initialize($) {
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{Match} = "^b.*";
|
||||
#$hash->{SetFn} = "WMBUS_Set";
|
||||
$hash->{SetFn} = "WMBUS_Set";
|
||||
#$hash->{GetFn} = "WMBUS_Get";
|
||||
$hash->{DefFn} = "WMBUS_Define";
|
||||
$hash->{UndefFn} = "WMBUS_Undef";
|
||||
@ -35,7 +35,9 @@ sub WMBUS_Initialize($) {
|
||||
" rawmsg_as_reading:0,1".
|
||||
" ignoreUnknownDataBlocks:0,1".
|
||||
" ignoreMasterMessages:0,1".
|
||||
" $readingFnAttributes";
|
||||
" useVIFasReadingName:0,1".
|
||||
" $readingFnAttributes"
|
||||
;
|
||||
}
|
||||
|
||||
sub
|
||||
@ -70,11 +72,11 @@ WMBUS_Define($$)
|
||||
{
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
my $mb;
|
||||
my $rssi;
|
||||
my $mb;
|
||||
my $rssi;
|
||||
|
||||
if(@a != 6 && @a != 3) {
|
||||
my $msg = "wrong syntax: define <name> WMBUS [<ManufacturerID> <SerialNo> <Version> <Type> [<MessageEncoding>]]|b<HexMessage>";
|
||||
my $msg = "wrong syntax: define <name> WMBUS <ManufacturerID> <SerialNo> <Version> <Type> [<MessageEncoding>]|b[<MessageEncoding>]<HexMessage>";
|
||||
Log3 undef, 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
@ -82,70 +84,70 @@ WMBUS_Define($$)
|
||||
my $name = $a[0];
|
||||
|
||||
if (@a == 3) {
|
||||
# unparsed message
|
||||
my $msg = $a[2];
|
||||
$mb = new WMBus;
|
||||
|
||||
|
||||
($msg, $rssi, $hash->{MessageEncoding}) = WMBUS_HandleEncoding($mb, $msg);
|
||||
|
||||
my $minSize = ($mb->getCRCsize() + WMBus::TL_BLOCK_SIZE) * 2;
|
||||
# unparsed message
|
||||
my $msg = $a[2];
|
||||
$mb = new WMBus;
|
||||
|
||||
|
||||
($msg, $rssi, $hash->{MessageEncoding}) = WMBUS_HandleEncoding($mb, $msg);
|
||||
|
||||
my $minSize = ($mb->getCRCsize() + WMBus::TL_BLOCK_SIZE) * 2;
|
||||
my $reMinSize = qr/b[a-zA-Z0-9]{${minSize},}/;
|
||||
|
||||
return "a WMBus message must be a least $minSize bytes long, $msg" if $msg !~ m/${reMinSize}/;
|
||||
|
||||
if ($mb->parseLinkLayer(pack('H*',substr($msg,1)))) {
|
||||
$hash->{Manufacturer} = $mb->{manufacturer};
|
||||
$hash->{IdentNumber} = $mb->{afield_id};
|
||||
$hash->{Version} = $mb->{afield_ver};
|
||||
$hash->{DeviceType} = $mb->{afield_type};
|
||||
if ($mb->{errormsg}) {
|
||||
$hash->{Error} = $mb->{errormsg};
|
||||
} else {
|
||||
delete $hash->{Error};
|
||||
}
|
||||
WMBUS_SetRSSI($hash, $mb, $rssi);
|
||||
} else {
|
||||
|
||||
return "a WMBus message must be a least $minSize bytes long, $msg" if $msg !~ m/${reMinSize}/;
|
||||
|
||||
if ($mb->parseLinkLayer(pack('H*',substr($msg,1)))) {
|
||||
$hash->{Manufacturer} = $mb->{manufacturer};
|
||||
$hash->{IdentNumber} = $mb->{afield_id};
|
||||
$hash->{Version} = $mb->{afield_ver};
|
||||
$hash->{DeviceType} = $mb->{afield_type};
|
||||
if ($mb->{errormsg}) {
|
||||
$hash->{Error} = $mb->{errormsg};
|
||||
} else {
|
||||
delete $hash->{Error};
|
||||
}
|
||||
WMBUS_SetRSSI($hash, $mb, $rssi);
|
||||
} else {
|
||||
my $error = "failed to parse msg: $mb->{errormsg}";
|
||||
if ($mb->{errorcode} == WMBus::ERR_MSG_TOO_SHORT && $hash->{MessageEncoding} eq 'CUL') {
|
||||
if ($mb->{errorcode} == WMBus::ERR_MSG_TOO_SHORT && $hash->{MessageEncoding} eq 'CUL') {
|
||||
$error .= ". Please make sure that TTY_BUFSIZE in culfw is at least two times the message length + 1";
|
||||
}
|
||||
return $error;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
my $encoding = "CUL";
|
||||
# manual specification
|
||||
} else {
|
||||
my $encoding = "CUL";
|
||||
# manual specification
|
||||
if ($a[2] !~ m/[A-Z]{3}/) {
|
||||
return "$a[2] is not a valid WMBUS manufacturer id";
|
||||
}
|
||||
return "$a[2] is not a valid WMBUS manufacturer id";
|
||||
}
|
||||
|
||||
if ($a[3] !~ m/[0-9]{1,8}/) {
|
||||
return "$a[3] is not a valid WMBUS serial number";
|
||||
}
|
||||
return "$a[3] is not a valid WMBUS serial number";
|
||||
}
|
||||
|
||||
if ($a[4] !~ m/[0-9]{1,2}/) {
|
||||
return "$a[4] is not a valid WMBUS version";
|
||||
}
|
||||
return "$a[4] is not a valid WMBUS version";
|
||||
}
|
||||
|
||||
if ($a[5] !~ m/[0-9]{1,2}/) {
|
||||
return "$a[5] is not a valid WMBUS type";
|
||||
}
|
||||
|
||||
if (defined($a[6])) {
|
||||
return "$a[5] is not a valid WMBUS type";
|
||||
}
|
||||
|
||||
if (defined($a[6])) {
|
||||
$encoding = $a[6];
|
||||
}
|
||||
if ($encoding ne "CUL" && $encoding ne "AMB") {
|
||||
return "$a[6] isn't a supported encoding, use either CUL or AMB";
|
||||
}
|
||||
|
||||
|
||||
|
||||
$hash->{Manufacturer} = $a[2];
|
||||
$hash->{IdentNumber} = sprintf("%08d",$a[3]);
|
||||
$hash->{Version} = $a[4];
|
||||
$hash->{DeviceType} = $a[5];
|
||||
$hash->{MessageEncoding} = $encoding;
|
||||
|
||||
$hash->{Manufacturer} = $a[2];
|
||||
$hash->{IdentNumber} = sprintf("%08d",$a[3]);
|
||||
$hash->{Version} = $a[4];
|
||||
$hash->{DeviceType} = $a[5];
|
||||
$hash->{MessageEncoding} = $encoding;
|
||||
|
||||
}
|
||||
my $addr = join("_", $hash->{Manufacturer},$hash->{IdentNumber},$hash->{Version},$hash->{DeviceType}) ;
|
||||
|
||||
@ -162,24 +164,17 @@ WMBUS_Define($$)
|
||||
}
|
||||
|
||||
$hash->{DEF} = join(" ", $hash->{Manufacturer},$hash->{IdentNumber},$hash->{Version},$hash->{DeviceType});
|
||||
|
||||
$hash->{DeviceMedium} = WMBus::->type2string($hash->{DeviceType});
|
||||
if (defined($mb)) {
|
||||
|
||||
if ($mb->parseApplicationLayer()) {
|
||||
if ($mb->{cifield} == WMBus::CI_RESP_12) {
|
||||
$hash->{Meter_Id} = $mb->{meter_id};
|
||||
$hash->{Meter_Manufacturer} = $mb->{meter_manufacturer};
|
||||
$hash->{Meter_Version} = $mb->{meter_vers};
|
||||
$hash->{Meter_Dev} = $mb->{meter_devtypestring};
|
||||
$hash->{Access_No} = $mb->{access_no};
|
||||
$hash->{Status} = $mb->{status};
|
||||
}
|
||||
WMBUS_SetReadings($hash, $name, $mb);
|
||||
} else {
|
||||
$hash->{Error} = $mb->{errormsg};
|
||||
}
|
||||
}
|
||||
|
||||
$hash->{DeviceMedium} = WMBus::->type2string($hash->{DeviceType});
|
||||
if (defined($mb)) {
|
||||
|
||||
if ($mb->parseApplicationLayer()) {
|
||||
|
||||
WMBUS_SetReadings($hash, $name, $mb);
|
||||
} else {
|
||||
$hash->{Error} = $mb->{errormsg};
|
||||
}
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
@ -231,58 +226,60 @@ WMBUS_Parse($$)
|
||||
# $hash is the hash of the IODev!
|
||||
|
||||
if( $rawMsg =~ m/^b/ ) {
|
||||
# WMBus message received
|
||||
|
||||
Log3 $name, 5, "WMBUS raw msg " . $rawMsg;
|
||||
|
||||
my $mb = new WMBus;
|
||||
|
||||
($msg, $rssi, $hash->{MessageEncoding}) = WMBUS_HandleEncoding($mb, $rawMsg);
|
||||
|
||||
if (uc(substr($msg, 0, 8)) eq "1144FF03") {
|
||||
# WMBus message received
|
||||
|
||||
Log3 $name, 5, "WMBUS raw msg " . $rawMsg;
|
||||
|
||||
$hash->{internal}{rawMsg} = $rawMsg;
|
||||
|
||||
my $mb = new WMBus;
|
||||
|
||||
($msg, $rssi, $hash->{MessageEncoding}) = WMBUS_HandleEncoding($mb, $rawMsg);
|
||||
|
||||
if (uc(substr($msg, 0, 8)) eq "1144FF03") {
|
||||
Log3 $name, 2, "received possible KNX-RF message, ignoring it";
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ($mb->parseLinkLayer(pack('H*',substr($msg,1)))) {
|
||||
$addr = join("_", $mb->{manufacturer}, $mb->{afield_id}, $mb->{afield_ver}, $mb->{afield_type});
|
||||
|
||||
if ($mb->parseLinkLayer(pack('H*',substr($msg,1)))) {
|
||||
$addr = join("_", $mb->{manufacturer}, $mb->{afield_id}, $mb->{afield_ver}, $mb->{afield_type});
|
||||
|
||||
$rhash = $modules{WMBUS}{defptr}{$addr};
|
||||
$rhash = $modules{WMBUS}{defptr}{$addr};
|
||||
|
||||
if( !$rhash ) {
|
||||
Log3 $name, 3, "WMBUS Unknown device $rawMsg, please define it";
|
||||
|
||||
return "UNDEFINED WMBUS_$addr WMBUS $rawMsg";
|
||||
}
|
||||
|
||||
if( !$rhash ) {
|
||||
Log3 $name, 3, "WMBUS Unknown device $rawMsg, please define it";
|
||||
|
||||
return "UNDEFINED WMBUS_$addr WMBUS $rawMsg";
|
||||
}
|
||||
|
||||
my $rname = $rhash->{NAME};
|
||||
return "" if(IsIgnored($rname));
|
||||
|
||||
|
||||
$rhash->{model} =join("_", $mb->{manufacturer}, $mb->{afield_type}, $mb->{afield_ver});
|
||||
WMBUS_SetRSSI($rhash, $mb, $rssi);
|
||||
WMBUS_SetRSSI($rhash, $mb, $rssi);
|
||||
|
||||
my $aeskey;
|
||||
my $aeskey;
|
||||
|
||||
if ($aeskey = AttrVal($rname, 'AESkey', undef)) {
|
||||
$mb->{aeskey} = pack("H*",$aeskey);
|
||||
} else {
|
||||
$mb->{aeskey} = undef;
|
||||
}
|
||||
if ($mb->parseApplicationLayer()) {
|
||||
return WMBUS_SetReadings($rhash, $rname, $mb);
|
||||
} else {
|
||||
Log3 $rname, 2, "WMBUS $rname Error during ApplicationLayer parse:" . $mb->{errormsg};
|
||||
readingsSingleUpdate($rhash, "state", $mb->{errormsg}, 1);
|
||||
return $rname;
|
||||
}
|
||||
} else {
|
||||
# error
|
||||
Log3 $name, 2, "WMBUS Error during LinkLayer parse:" . $mb->{errormsg};
|
||||
if ($mb->{errorcode} == WMBus::ERR_MSG_TOO_SHORT && $hash->{MessageEncoding} eq 'CUL') {
|
||||
if ($aeskey = AttrVal($rname, 'AESkey', undef)) {
|
||||
$mb->{aeskey} = pack("H*",$aeskey);
|
||||
} else {
|
||||
$mb->{aeskey} = undef;
|
||||
}
|
||||
if ($mb->parseApplicationLayer()) {
|
||||
return WMBUS_SetReadings($rhash, $rname, $mb);
|
||||
} else {
|
||||
Log3 $rname, 2, "WMBUS $rname Error during ApplicationLayer parse:" . $mb->{errormsg};
|
||||
readingsSingleUpdate($rhash, "state", $mb->{errormsg}, 1);
|
||||
return $rname;
|
||||
}
|
||||
} else {
|
||||
# error
|
||||
Log3 $name, 2, "WMBUS Error during LinkLayer parse:" . $mb->{errormsg};
|
||||
if ($mb->{errorcode} == WMBus::ERR_MSG_TOO_SHORT && $hash->{MessageEncoding} eq 'CUL') {
|
||||
Log3 $name, 2, "Please make sure that TTY_BUFSIZE in culfw is at least two times the message length + 1";
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
} else {
|
||||
DoTrigger($name, "UNKNOWNCODE $rawMsg");
|
||||
Log3 $name, 3, "$name: Unknown code $rawMsg, help me!";
|
||||
@ -297,86 +294,109 @@ WMBUS_Parse($$)
|
||||
# If it is a valid RSSI it will be ignored by the WMBus parser (the data contains the length of the data itself
|
||||
# and only that much is parsed).
|
||||
sub WMBUS_RSSIAsRaw($) {
|
||||
my $rssi = shift;
|
||||
|
||||
if (defined $rssi) {
|
||||
if ($rssi < -74) {
|
||||
$b = ($rssi+74)*2+256;
|
||||
} else {
|
||||
$b = ($rssi+74)*2;
|
||||
}
|
||||
return sprintf("%02X", $b);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
my $rssi = shift;
|
||||
|
||||
if (defined $rssi) {
|
||||
if ($rssi < -74) {
|
||||
$b = ($rssi+74)*2+256;
|
||||
} else {
|
||||
$b = ($rssi+74)*2;
|
||||
}
|
||||
return sprintf("%02X", $b);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
sub WMBUS_SetRSSI($$$) {
|
||||
my ($hash, $mb, $rssi) = @_;
|
||||
|
||||
if (defined $mb->{remainingData} && length($mb->{remainingData}) >= 2) {
|
||||
# if there are trailing bytes after the WMBUS message it is the LQI and the RSSI
|
||||
readingsBeginUpdate($hash);
|
||||
my ($lqi, $rssi) = unpack("CC", $mb->{remainingData});
|
||||
my ($hash, $mb, $rssi) = @_;
|
||||
|
||||
if (defined $mb->{remainingData} && length($mb->{remainingData}) >= 2) {
|
||||
# if there are trailing bytes after the WMBUS message it is the LQI and the RSSI
|
||||
readingsBeginUpdate($hash);
|
||||
my ($lqi, $rssi) = unpack("CC", $mb->{remainingData});
|
||||
$rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74));
|
||||
|
||||
readingsBulkUpdate($hash, "RSSI", $rssi);
|
||||
readingsBulkUpdate($hash, "LQI", unpack("C", $mb->{remainingData}));
|
||||
readingsEndUpdate($hash,1);
|
||||
}
|
||||
readingsBulkUpdate($hash, "RSSI", $rssi);
|
||||
readingsBulkUpdate($hash, "LQI", unpack("C", $mb->{remainingData}));
|
||||
readingsEndUpdate($hash,1);
|
||||
}
|
||||
}
|
||||
|
||||
sub WMBUS_SetReadings($$$)
|
||||
{
|
||||
my ($hash, $name, $mb) = @_;
|
||||
|
||||
my @list;
|
||||
push(@list, $name);
|
||||
my ($hash, $name, $mb) = @_;
|
||||
|
||||
my @list;
|
||||
push(@list, $name);
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
|
||||
if ($mb->{decrypted} &&
|
||||
# decode messages sent from master to slave/meter only if it is explictly enabled
|
||||
( $mb->{sent_from_master} == 0 || AttrVal($name, "ignoreMasterMessages", 1) )
|
||||
if ($mb->{cifield} == WMBus::CI_RESP_12) {
|
||||
$hash->{Meter_Id} = $mb->{meter_id};
|
||||
$hash->{Meter_Manufacturer} = $mb->{meter_manufacturer};
|
||||
$hash->{Meter_Version} = $mb->{meter_vers};
|
||||
$hash->{Meter_Dev} = $mb->{meter_devtypestring};
|
||||
$hash->{Access_No} = $mb->{access_no};
|
||||
$hash->{Status} = $mb->{status};
|
||||
}
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
|
||||
if ($mb->{decrypted} &&
|
||||
# decode messages sent from master to slave/meter only if it is explictly enabled
|
||||
( $mb->{sent_from_master} == 0 || AttrVal($name, "ignoreMasterMessages", 1) )
|
||||
)
|
||||
{
|
||||
my $dataBlocks = $mb->{datablocks};
|
||||
my $dataBlock;
|
||||
|
||||
for $dataBlock ( @$dataBlocks ) {
|
||||
my $dataBlocks = $mb->{datablocks};
|
||||
my $dataBlock;
|
||||
my $readingBase;
|
||||
my $useVIFasReadingName = defined($hash->{internal}{useVIFasReadingName}) ?
|
||||
$hash->{internal}{useVIFasReadingName} : AttrVal($name, "useVIFasReadingName", 0);
|
||||
|
||||
for $dataBlock ( @$dataBlocks ) {
|
||||
next if AttrVal($name, "ignoreUnknownDataBlocks", 0) && $dataBlock->{type} eq 'MANUFACTURER SPECIFIC'; #WMBus::VIF_TYPE_MANUFACTURER_SPECIFIC
|
||||
readingsBulkUpdate($hash, "$dataBlock->{number}_storage_no", $dataBlock->{storageNo});
|
||||
readingsBulkUpdate($hash, "$dataBlock->{number}_type", $dataBlock->{type});
|
||||
readingsBulkUpdate($hash, "$dataBlock->{number}_value", $dataBlock->{value});
|
||||
readingsBulkUpdate($hash, "$dataBlock->{number}_unit", $dataBlock->{unit});
|
||||
readingsBulkUpdate($hash, "$dataBlock->{number}_value_type", $dataBlock->{functionFieldText});
|
||||
if (defined($dataBlock->{extension})) {
|
||||
readingsBulkUpdate($hash, "$dataBlock->{number}_extension", $dataBlock->{extension});
|
||||
if ($useVIFasReadingName) {
|
||||
$readingBase = "$dataBlock->{storageNo}_$dataBlock->{type}";
|
||||
if (defined($dataBlock->{extension_value})) {
|
||||
$readingBase .= "_$dataBlock->{extension_value}";
|
||||
}
|
||||
} else {
|
||||
$readingBase = $dataBlock->{number};
|
||||
readingsBulkUpdate($hash, "${readingBase}_type", $dataBlock->{type});
|
||||
readingsBulkUpdate($hash, "${readingBase}_storage_no", $dataBlock->{storageNo});
|
||||
if (defined($dataBlock->{extension_value})) {
|
||||
readingsBulkUpdate($hash, "${readingBase}_extension_value", $dataBlock->{extension_value});
|
||||
}
|
||||
}
|
||||
readingsBulkUpdate($hash, "${readingBase}_value", $dataBlock->{value});
|
||||
readingsBulkUpdate($hash, "${readingBase}_unit", $dataBlock->{unit});
|
||||
readingsBulkUpdate($hash, "${readingBase}_value_type", $dataBlock->{functionFieldText});
|
||||
if (defined($dataBlock->{extension_unit})) {
|
||||
readingsBulkUpdate($hash, "${readingBase}_extension_unit", $dataBlock->{extension_unit});
|
||||
}
|
||||
if ($dataBlock->{errormsg}) {
|
||||
readingsBulkUpdate($hash, "$dataBlock->{number}_errormsg", $dataBlock->{errormsg});
|
||||
}
|
||||
}
|
||||
if ($dataBlock->{errormsg}) {
|
||||
readingsBulkUpdate($hash, "${readingBase}_errormsg", $dataBlock->{errormsg});
|
||||
}
|
||||
}
|
||||
readingsBulkUpdate($hash, "batteryState", $mb->{status} & 4 ? "low" : "ok");
|
||||
|
||||
WMBUS_SetDeviceSpecificReadings($hash, $name, $mb);
|
||||
}
|
||||
readingsBulkUpdate($hash, "is_encrypted", $mb->{isEncrypted});
|
||||
readingsBulkUpdate($hash, "decryption_ok", $mb->{decrypted});
|
||||
|
||||
if ($mb->{decrypted}) {
|
||||
readingsBulkUpdate($hash, "state", $mb->{statusstring});
|
||||
} else {
|
||||
readingsBulkUpdate($hash, "state", 'decryption failed');
|
||||
}
|
||||
|
||||
if (AttrVal($name, "rawmsg_as_reading", 0)) {
|
||||
readingsBulkUpdate($hash, "is_encrypted", $mb->{isEncrypted});
|
||||
readingsBulkUpdate($hash, "decryption_ok", $mb->{decrypted});
|
||||
|
||||
if ($mb->{decrypted}) {
|
||||
readingsBulkUpdate($hash, "state", $mb->{statusstring});
|
||||
} else {
|
||||
readingsBulkUpdate($hash, "state", 'decryption failed');
|
||||
}
|
||||
|
||||
if (AttrVal($name, "rawmsg_as_reading", 0)) {
|
||||
readingsBulkUpdate($hash, "rawmsg", $mb->getFrameType() eq WMBus::FRAME_TYPE_B ? "Y" : "" . unpack("H*",$mb->{msg}));
|
||||
}
|
||||
|
||||
readingsEndUpdate($hash,1);
|
||||
|
||||
readingsEndUpdate($hash,1);
|
||||
|
||||
return @list;
|
||||
return @list;
|
||||
|
||||
}
|
||||
|
||||
@ -422,15 +442,19 @@ WMBUS_Set($@)
|
||||
my $name = shift @a;
|
||||
my $cmd = shift @a;
|
||||
my $arg = join(" ", @a);
|
||||
my $list = "rawmsg";
|
||||
|
||||
|
||||
my $list = "resetAccumulatedPower";
|
||||
# only for Letrika solar inverters
|
||||
$list .= " requestCurrentPower requestTotalEnergy" if $hash->{Manufacturer} eq 'LET' and $hash->{DeviceType} == 2;
|
||||
return $list if( $cmd eq '?' || $cmd eq '');
|
||||
|
||||
|
||||
if($cmd eq "resetAccumulatedPower") {
|
||||
CommandAttr(undef, "$name accumulatedPowerOffset " . $hash->{READINGS}{accumulatedPowerMeasured}{VAL});
|
||||
}
|
||||
if ($cmd eq 'rawmsg') {
|
||||
WMBUS_Parse($hash, 'b'.$arg);
|
||||
} elsif ($cmd eq "requestCurrentPower") {
|
||||
IOWrite($hash, "", "bss");
|
||||
} elsif ($cmd eq "requestTotalEnergy") {
|
||||
}
|
||||
else {
|
||||
return "Unknown argument $cmd, choose one of ".$list;
|
||||
}
|
||||
@ -442,18 +466,28 @@ sub
|
||||
WMBUS_Attr(@)
|
||||
{
|
||||
my ($cmd, $name, $attrName, $attrVal) = @_;
|
||||
my $hash = $defs{$name};
|
||||
my $msg = '';
|
||||
my $hash = $defs{$name};
|
||||
my $msg = '';
|
||||
|
||||
if ($attrName eq 'AESkey') {
|
||||
if ($attrVal =~ /^[0-9A-Fa-f]{32}$/) {
|
||||
$hash->{wmbus}->{aeskey} = $attrVal;
|
||||
} else {
|
||||
$msg = "AESkey must be a 32 digit hexadecimal value";
|
||||
}
|
||||
|
||||
}
|
||||
return ($msg) ? $msg : undef;
|
||||
if ($attrName eq 'AESkey') {
|
||||
if ($attrVal =~ /^[0-9A-Fa-f]{32}$/) {
|
||||
$hash->{wmbus}->{aeskey} = $attrVal;
|
||||
} else {
|
||||
$msg = "AESkey must be a 32 digit hexadecimal value";
|
||||
}
|
||||
} elsif ($attrName eq 'useVIFasReadingName') {
|
||||
if ($attrVal ne AttrVal($name, 'useVIFasReadingName', '0')) {
|
||||
# delete all readings on change of namimg format
|
||||
fhem "deletereading $name .*";
|
||||
# and recreate them
|
||||
if (defined($hash->{internal}{rawMsg})) {
|
||||
$hash->{internal}{useVIFasReadingName} = $attrVal;
|
||||
WMBUS_Parse($hash, $hash->{internal}{rawMsg});
|
||||
delete $hash->{internal}{useVIFasReadingName};
|
||||
}
|
||||
}
|
||||
}
|
||||
return ($msg) ? $msg : undef;
|
||||
}
|
||||
|
||||
1;
|
||||
@ -499,11 +533,11 @@ WMBUS_Attr(@)
|
||||
<br>
|
||||
For a manual definition there are two ways.
|
||||
<ul>
|
||||
<li>
|
||||
<li>
|
||||
By specifying a raw WMBus message as received by an IODev. Such a message starts with a lower case 'b' and contains at least 24 hexadecimal digits.
|
||||
The WMBUS module extracts all relevant information from such a message.
|
||||
</li>
|
||||
<li>
|
||||
The WMBUS module extracts all relevant information from such a message.
|
||||
</li>
|
||||
<li>
|
||||
Explictly specify the information that uniquely identifies a WMBus device. <br>
|
||||
The manufacturer code, which is is a three letter shortcut of the manufacturer name. See
|
||||
<a href="https://www.dlms.com/flag-id/flag-id-list">dlms.com</a> for a list of registered ids.<br>
|
||||
@ -518,7 +552,13 @@ WMBUS_Attr(@)
|
||||
<br>
|
||||
|
||||
<a name="WMBUSset"></a>
|
||||
<b>Set</b> <ul>N/A</ul><br>
|
||||
<b>Set</b>
|
||||
<ul>
|
||||
<li>
|
||||
rawmsg hexadecimal contents of a raw message (without the leading b)<br>
|
||||
Will be parsed as if the message has been received by the IODev. Mainly useful for debugging.
|
||||
</li>
|
||||
</ul><br>
|
||||
<a name="WMBUSget"></a>
|
||||
<b>Get</b> <ul>N/A</ul><br>
|
||||
|
||||
@ -529,11 +569,11 @@ WMBUS_Attr(@)
|
||||
<li><a href="#IODev">IODev</a><br>
|
||||
Set the IO or physical device which should be used for receiving signals
|
||||
for this "logical" device. An example for the physical device is a CUL.
|
||||
</li><br>
|
||||
</li><br>
|
||||
<a name="AESkey"></a>
|
||||
<li>AESkey<br>
|
||||
A 16 byte AES-Key in hexadecimal digits. Used to decrypt messages from meters which have encryption enabled.
|
||||
</li><br>
|
||||
A 16 byte AES-Key in hexadecimal digits. Used to decrypt messages from meters which have encryption enabled.
|
||||
</li><br>
|
||||
<li>
|
||||
<a name="ignore"></a>
|
||||
<a href="#ignore">ignore</a>
|
||||
@ -552,9 +592,28 @@ WMBUS_Attr(@)
|
||||
<li>ignoreMasterMessages<br>
|
||||
Some devices (e.g. Letrika solar inverters) only send data if they have received a special message from a master device.
|
||||
The messages sent by the master are ignored unless explictly enabled by this attribute.
|
||||
</li><br>
|
||||
<a name="useVIFasReadingName"></a>
|
||||
<li>useVIFasReadingName<br>
|
||||
Some devices send several types of messages with different logical content. As the readings are normally numbered consecutively they will be overwitten
|
||||
by blocks with a different semantic meaning.
|
||||
If ths attribute is set to 1 the naming of the readings will be changed to start with storage number and VIF (Value Information Field) name.
|
||||
Therefor each semantically different value will get a unique reading name.<br>
|
||||
Example:<br>
|
||||
<pre>
|
||||
1_storage_no 0
|
||||
1_type VIF_ENERGY_WATT
|
||||
1_unit Wh
|
||||
1_value 1234.5
|
||||
</pre>
|
||||
will be changed to<br>
|
||||
<pre>
|
||||
0_VIF_ENERGY_WATT_unit Wh
|
||||
0_VIF_ENERGY_WATT_value 1234.5
|
||||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
<a name="WMBUSreadings"></a>
|
||||
<b>Readings</b><br>
|
||||
<ul>
|
||||
@ -567,8 +626,8 @@ WMBUS_Attr(@)
|
||||
<code>1_type VIF_ENERGY_WATT</code><br>
|
||||
<code>1_unit Wh</code><br>
|
||||
<code>1_value 2948787</code><br>
|
||||
</ul>
|
||||
<br>
|
||||
</ul>
|
||||
<br>
|
||||
There is also a fixed set of readings.
|
||||
<ul>
|
||||
<li><code>is_encrypted</code> is 1 if the received message is encrypted.</li>
|
||||
@ -592,8 +651,8 @@ WMBUS_Attr(@)
|
||||
Dieses Modul unterstützt Zähler mit Wireless M-Bus, z. B. für Wasser, Gas oder Elektrizität.
|
||||
Wireless M-Bus ist ein standardisiertes Protokoll das von unterschiedlichen Herstellern unterstützt wird.
|
||||
|
||||
Es verwendet das 868 MHz Band für Radioübertragungen.
|
||||
Daher wird ein Gerät benötigt das die Wireless M-Bus Nachrichten empfangen kann, z. B. ein <a href="#CUL">CUL</a> mit culfw >= 1.59 oder ein AMBER Wireless AMB8465-M.
|
||||
Es verwendet das 868 MHz Band für Radioübertragungen.
|
||||
Daher wird ein Gerät benötigt das die Wireless M-Bus Nachrichten empfangen kann, z. B. ein <a href="#CUL">CUL</a> mit culfw >= 1.59 oder ein AMBER Wireless AMB8465-M.
|
||||
<br>
|
||||
WMBus verwendet drei unterschiedliche Radioprotokolle, T-Mode, S-Mode und C-Mode. Der Empfänger muss daher so konfiguriert werden, dass er das selbe Protokoll
|
||||
verwendet wie der Sender. Im Falle eines CUL kann das erreicht werden, in dem das Attribut <a href="#rfmode">rfmode</a> auf WMBus_T, WMBus_S bzw. WMBus_C gesetzt wird.
|
||||
@ -605,7 +664,7 @@ WMBUS_Attr(@)
|
||||
Andernfalls wird die Entschlüsselung fehlschlagen und es können keine relevanten Daten ausgelesen werden. Das Modul kann mit Security Profile A oder B (Mode 5 und 7) verschlüsselte Nachrichten entschlüsseln.
|
||||
<br><br>
|
||||
<b>Voraussetzungen</b><br>
|
||||
Dieses Modul benötigt die perl Module Digest::CRC, Crypt::Mode::CBC, Crypt::ModeL::CTR und Digest::CMAC (die letzten drei Module werden nur benötigt wenn verschlüsselte Nachrichten verarbeitet werden sollen).<br>
|
||||
Dieses Modul benötigt die perl Module Digest::CRC, Crypt::Mode::CBC, Crypt::Mode::CTR und Digest::CMAC (die letzten drei Module werden nur benötigt wenn verschlüsselte Nachrichten verarbeitet werden sollen).<br>
|
||||
Bei einem Debian basierten System können diese so installiert werden<br>
|
||||
<code>
|
||||
sudo apt-get install libdigest-crc-perl<br>
|
||||
@ -622,14 +681,14 @@ WMBUS_Attr(@)
|
||||
<br>
|
||||
Für eine manuelle Definition gibt es zwei Wege.
|
||||
<ul>
|
||||
<li>
|
||||
Durch Verwendung einer WMBus Rohnachricht wie sie vom IODev empfangen wurde. So eine Nachricht beginnt mit einem kleinen 'b' und enthält mindestens
|
||||
24 hexadezimale Zeichen.
|
||||
Das WMBUS Modul extrahiert daraus alle benötigten Informationen.
|
||||
</li>
|
||||
<li>
|
||||
Durch explizite Angabe der Informationen die ein WMBus Gerät eindeutig identfizieren.<br>
|
||||
Der Hersteller Code, besteht aus drei Buchstaben als Abkürzung des Herstellernamens. Eine Liste der Abkürzungen findet sich unter
|
||||
<li>
|
||||
Durch Verwendung einer WMBus Rohnachricht wie sie vom IODev empfangen wurde. So eine Nachricht beginnt mit einem kleinen 'b' und enthält mindestens
|
||||
24 hexadezimale Zeichen.
|
||||
Das WMBUS Modul extrahiert daraus alle benötigten Informationen.
|
||||
</li>
|
||||
<li>
|
||||
Durch explizite Angabe der Informationen die ein WMBus Gerät eindeutig identfizieren.<br>
|
||||
Der Hersteller Code, besteht aus drei Buchstaben als Abkürzung des Herstellernamens. Eine Liste der Abkürzungen findet sich unter
|
||||
<a href="https://www.dlms.com/flag-id/flag-id-list">dlms.com</a><br>
|
||||
Die Idenitfikationsnummer ist die Seriennummer des Zählers.<br>
|
||||
Version ist ein Versionscode des Zählers.<br>
|
||||
@ -642,7 +701,13 @@ WMBUS_Attr(@)
|
||||
<br>
|
||||
|
||||
<a name="WMBUSset"></a>
|
||||
<b>Set</b> <ul>N/A</ul><br>
|
||||
<b>Set</b>
|
||||
<ul>
|
||||
<li>
|
||||
rawmsg Hexadezimaler Inhalt einer Rohnachricht (ohne führendes b)<br>
|
||||
Wird interpretiert als ob die Nachricht von einem IODev empfangen worden wäre. Hauptsächlich nützlich zum debuggen.
|
||||
</li>
|
||||
</ul><br>
|
||||
<a name="WMBUSget"></a>
|
||||
<b>Get</b> <ul>N/A</ul><br>
|
||||
|
||||
@ -651,14 +716,14 @@ WMBUS_Attr(@)
|
||||
<ul>
|
||||
<a name="IODev"></a>
|
||||
<li><a href="#IODev">IODev</a><br>
|
||||
Setzt den IO oder physisches Gerät welches für den Empfang der Signale für dieses 'logische' Gerät verwendet werden soll.
|
||||
Ein Beispiel für ein solches Gerät ist ein CUL.
|
||||
</li><br>
|
||||
Setzt den IO oder physisches Gerät welches für den Empfang der Signale für dieses 'logische' Gerät verwendet werden soll.
|
||||
Ein Beispiel für ein solches Gerät ist ein CUL.
|
||||
</li><br>
|
||||
<a name="AESkey"></a>
|
||||
<li>AESKey<br>
|
||||
Ein 16 Bytes langer AES-Schlüssel in hexadezimaler Schreibweise. Wird verwendet um Nachrichten von Zählern zu entschlüsseln bei denen
|
||||
die Verschlüsselung aktiviert ist.
|
||||
</li><br>
|
||||
<li>AESKey<br>
|
||||
Ein 16 Bytes langer AES-Schlüssel in hexadezimaler Schreibweise. Wird verwendet um Nachrichten von Zählern zu entschlüsseln bei denen
|
||||
die Verschlüsselung aktiviert ist.
|
||||
</li><br>
|
||||
<li>
|
||||
<a name="ignore"></a>
|
||||
<a href="#ignore">ignore</a>
|
||||
@ -676,8 +741,27 @@ WMBUS_Attr(@)
|
||||
Einige Geräte (z. B. Letrika Wechselrichter) senden nur dann Daten wenn sie eine spezielle Nachricht von einem Mastergerät erhalten haben.
|
||||
Die Nachrichten von dem Master werden ignoriert es sei denn es wird explizit mit diesem Attribut eingeschaltet.
|
||||
</li>
|
||||
<a name="useVIFasReadingName"></a>
|
||||
<li>useVIFasReadingName<br>
|
||||
Einige Geräte senden verschiedene Arten von Nachrichten mit logisch unterschiedlichem Inhalt. Da die Readings normalerweise aufsteigend nummeriert werden
|
||||
können Readings durch semantisch unterschiedliche Readings überschrieben werden.
|
||||
Wenn dieses Attribut auf 1 gesetzt ist ändert sich die Namenskonvention der Readings. Die Namen setzen sich dann aus der Storagenumber und dem
|
||||
VIF (Value Information Field) zusammen. Dadurch bekommt jeder semantisch unterschiedliche Wert einen eindeutigen Readingnamen.
|
||||
Beispiel:<br>
|
||||
<pre>
|
||||
1_storage_no 0
|
||||
1_type VIF_ENERGY_WATT
|
||||
1_unit Wh
|
||||
1_value 1234.5
|
||||
</pre>
|
||||
wird zu<br>
|
||||
<pre>
|
||||
0_VIF_ENERGY_WATT_unit Wh
|
||||
0_VIF_ENERGY_WATT_value 1234.5
|
||||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
<a name="WMBUSreadings"></a>
|
||||
<b>Readings</b><br>
|
||||
<ul>
|
||||
@ -691,9 +775,9 @@ WMBUS_Attr(@)
|
||||
<code>1_type VIF_ENERGY_WATT</code><br>
|
||||
<code>1_unit Wh</code><br>
|
||||
<code>1_value 2948787</code><br>
|
||||
</ul>
|
||||
<br>
|
||||
Es gibt auch eine Anzahl von festen Readings.
|
||||
</ul>
|
||||
<br>
|
||||
Es gibt auch eine Anzahl von festen Readings.
|
||||
<ul>
|
||||
<li><code>is_encrypted</code> ist 1 wenn die empfangene Nachricht verschlüsselt ist.</li>
|
||||
<li><code>decryption_ok</code> ist 1 wenn die Nachricht entweder erfolgreich entschlüsselt wurde oder gar nicht verschlüsselt war.</li>
|
||||
|
@ -109,6 +109,13 @@ use constant {
|
||||
FRAME_TYPE_A => 'A',
|
||||
FRAME_TYPE_B => 'B',
|
||||
|
||||
# content type (CC bits of configuration field)
|
||||
# stored in $self->{cw_parts}{content}
|
||||
CONTENT_STANDARD => 0b00, # Standard data message with unsigned variable meter data
|
||||
CONTENT_STATIC => 0b10, # Static message (consists of parameter, OBIS definitions and other data points
|
||||
# which are not frequently changed – see also 4.3.2.4).
|
||||
|
||||
|
||||
};
|
||||
|
||||
sub valueCalcNumeric($$) {
|
||||
@ -193,7 +200,19 @@ sub valueCalcHex($$) {
|
||||
my $value = shift;
|
||||
my $dataBlock = shift;
|
||||
|
||||
return sprintf("%x", $value);
|
||||
return unpack("H*", $value);
|
||||
}
|
||||
|
||||
sub valueCalcAscii($$) {
|
||||
my $value = shift;
|
||||
my $dataBlock = shift;
|
||||
|
||||
my $result = unpack('a*',$value);
|
||||
|
||||
# replace non printable chars
|
||||
$result =~ s/[\x00-\x1f\x7f-\xff]/?/g;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub valueCalcu($$) {
|
||||
@ -453,7 +472,7 @@ my %VIFInfo = (
|
||||
type => 0b01111000,
|
||||
bias => 0,
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
calcFunc => \&valueCalcAscii,
|
||||
},
|
||||
VIF_OWNER_NO => { # Eigentumsnummer (used by Easymeter even though the standard allows this only for writing to a slave)
|
||||
typeMask => 0b01111111,
|
||||
@ -556,7 +575,7 @@ my %VIFInfo_FD = (
|
||||
type => 0b00001001,
|
||||
bias => 0,
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
calcFunc => \&valueCalcAscii,
|
||||
},
|
||||
VIF_MANUFACTURER => { # Manufacturer (as in fixed header)
|
||||
typeMask => 0b01111111,
|
||||
@ -606,6 +625,57 @@ my %VIFInfo_FD = (
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
},
|
||||
|
||||
|
||||
VIF_CUSTOMER_LOCATION => { # Customer location
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
type => 0b00010000,
|
||||
bias => 0,
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcHex
|
||||
},
|
||||
VIF_CUSTOMER_CUSTOMER => { # Customer
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
type => 0b00010001,
|
||||
bias => 0,
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcHex
|
||||
},
|
||||
VIF_ACCESS_CODE_USER => { # Access code user
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
type => 0b00010010,
|
||||
bias => 0,
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcHex
|
||||
},
|
||||
VIF_ACCESS_CODE_OPERATOR => { # Access code operator
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
type => 0b00010011,
|
||||
bias => 0,
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcHex
|
||||
},
|
||||
VIF_ACCESS_CODE_SYSTEM_OPERATOR => { # Access code system operator
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
type => 0b00010100,
|
||||
bias => 0,
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcHex
|
||||
},
|
||||
VIF_PASSWORD => { # Password
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
type => 0b00010110,
|
||||
bias => 0,
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcHex
|
||||
},
|
||||
|
||||
VIF_ERROR_FLAGS => { # Error flags (binary)
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
@ -960,6 +1030,9 @@ my %VIFInfo_ESY = (
|
||||
unit => 'W',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
},
|
||||
);
|
||||
|
||||
my %VIFInfo_ESY2 = (
|
||||
VIF_ELECTRIC_POWER_PHASE_NO => {
|
||||
typeMask => 0b01111110,
|
||||
expMask => 0b00000000,
|
||||
@ -1346,8 +1419,10 @@ sub decodeValueInformationBlock($$$) {
|
||||
if ($self->{manufacturer} eq 'ESY') {
|
||||
# Easymeter
|
||||
$vif = unpack('C', substr($vib,$offset++,1));
|
||||
#printf("ESY VIF %x\n", $vif);
|
||||
$vifInfoRef = \%VIFInfo_ESY;
|
||||
} elsif ($self->{manufacturer} eq 'KAM') {
|
||||
# Kamstrup
|
||||
$vif = unpack('C', substr($vib,$offset++,1));
|
||||
$vifInfoRef = \%VIFInfo_KAM;
|
||||
} else {
|
||||
@ -1363,7 +1438,8 @@ sub decodeValueInformationBlock($$$) {
|
||||
#print "other extension\n";
|
||||
$dataBlockExt = {};
|
||||
if ($self->{manufacturer} eq 'ESY') {
|
||||
$vifInfoRef = \%VIFInfo_ESY;
|
||||
#print "ESY\n";
|
||||
$vifInfoRef = \%VIFInfo_ESY2;
|
||||
$dataBlockExt->{value} = unpack('C',substr($vib,2,1)) * 100;
|
||||
} else {
|
||||
$dataBlockExt->{value} = $vif;
|
||||
@ -1386,7 +1462,7 @@ sub decodeValueInformationBlock($$$) {
|
||||
# Plaintext VIF
|
||||
$offset = $self->decodePlaintext($vib, $dataBlockRef, $offset);
|
||||
} elsif (findVIF($vif, $vifInfoRef, $dataBlockRef) == 0) {
|
||||
$dataBlockRef->{errormsg} = "unknown VIF " . sprintf("%x", $vifExtension) . " at offset " . ($offset-1);
|
||||
$dataBlockRef->{errormsg} = "unknown VIFE " . sprintf("%x", $vifExtension) . " at offset " . ($offset-1);
|
||||
$dataBlockRef->{errorcode} = ERR_UNKNOWN_VIFE;
|
||||
}
|
||||
}
|
||||
@ -1564,10 +1640,7 @@ sub decodePayload($$) {
|
||||
#print "VALUE: " . $value . "\n";
|
||||
} else {
|
||||
# ASCII string with LVAR characters
|
||||
$value = unpack('a*',substr($payload, $offset, $lvar));
|
||||
|
||||
# replace non printable chars
|
||||
$value =~ s/[\x00-\x1f\x7f]/?/g;
|
||||
$value = valueCalcAscii(substr($payload, $offset, $lvar), $dataBlock);
|
||||
|
||||
if ($self->{manufacturer} eq 'ESY') {
|
||||
# Easymeter stores the string backwards!
|
||||
@ -1610,12 +1683,13 @@ sub decodePayload($$) {
|
||||
|
||||
my $VIFExtensions = $dataBlock->{VIFExtensions};
|
||||
for my $VIFExtension (@$VIFExtensions) {
|
||||
$dataBlock->{extension} = $VIFExtension->{unit};
|
||||
$dataBlock->{extension_unit} = $VIFExtension->{unit};
|
||||
#printf("extension unit %s\n", $dataBlock->{extension_unit});
|
||||
if (defined $VIFExtension->{calcFunc}) {
|
||||
#printf("Extension value %d, valueFactor %d\n", $VIFExtension->{value}, $VIFExtension->{valueFactor});
|
||||
$dataBlock->{extension} .= ", " . $VIFExtension->{calcFunc}->($VIFExtension->{value}, $dataBlock);
|
||||
$dataBlock->{extension_value} = $VIFExtension->{calcFunc}->($VIFExtension->{value}, $dataBlock);
|
||||
} elsif (defined $VIFExtension->{value}) {
|
||||
$dataBlock->{extension} .= ", " . sprintf("%x",$VIFExtension->{value});
|
||||
$dataBlock->{extension_value} = sprintf("%x",$VIFExtension->{value});
|
||||
} else {
|
||||
#$dataBlock->{extension} = "";
|
||||
}
|
||||
@ -2312,4 +2386,62 @@ sub parseApplicationLayer($)
|
||||
return $self->decodeApplicationLayer();
|
||||
}
|
||||
|
||||
sub dumpResult($)
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
if ($self->{linkLayerOk}) {
|
||||
printf("Manufacturer %x %s\n", $self->{mfield}, $self->{manufacturer});
|
||||
printf("IdentNumber %s\n", $self->{afield_id});
|
||||
printf("Version %d\n", $self->{afield_ver});
|
||||
printf("Type %x %s\n", $self->{afield_type}, $self->{typestring});
|
||||
printf("IsEncrypted %d\n", $self->{isEncrypted});
|
||||
|
||||
printf("Status: %x %s\n", $self->{status}, $self->{statusstring});
|
||||
if ($self->{cw_parts}{mode} == 5) {
|
||||
print "Codeword:\n";
|
||||
print "bidirectional: ". $self->{cw_parts}{bidirectional} . "\n";
|
||||
print "accessability: ". $self->{cw_parts}{accessability} . "\n";
|
||||
print "synchronous: $self->{cw_parts}{synchronous}\n";
|
||||
print "mode: $self->{cw_parts}{mode}\n";
|
||||
print "encrypted_blocks: $self->{cw_parts}{encrypted_blocks}\n";
|
||||
print "content: $self->{cw_parts}{content}\n";
|
||||
print "hops: $self->{cw_parts}{hops}\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($self->{errorcode} == ERR_NO_ERROR) {
|
||||
if ($self->{cifield} == CI_RESP_12) {
|
||||
printf("Meter Id %d\n", $self->{meter_id});
|
||||
printf("Meter Manufacturer %x %s\n", $self->{meter_man}, $self->manId2ascii($self->{meter_man}));
|
||||
printf("Meter Version %d\n", $self->{meter_vers});
|
||||
printf("Meter Dev %x %s\n", $self->{meter_dev}, $self->type2string($self->{meter_dev}));
|
||||
printf("Access No %d\n", $self->{access_no});
|
||||
printf("Status %x\n", $self->{status});
|
||||
}
|
||||
|
||||
my $dataBlocks = $self->{datablocks};
|
||||
my $dataBlock;
|
||||
|
||||
for $dataBlock ( @$dataBlocks ) {
|
||||
#if ( $dataBlock->{type} eq "MANUFACTURER SPECIFIC") {
|
||||
# print $dataBlock->{number} . " " . $dataBlock->{type} . "\n";
|
||||
#} else {
|
||||
print $dataBlock->{number} . ". StorageNo " . $dataBlock->{storageNo} . " " ;
|
||||
print $dataBlock->{functionFieldText} . " ";
|
||||
print $dataBlock->{type} . " " . $dataBlock->{value} . " " . $dataBlock->{unit};
|
||||
if ($dataBlock->{errormsg}) {
|
||||
print "(" . $dataBlock->{errormsg} . ")";
|
||||
}
|
||||
if (defined($dataBlock->{extension_unit})) {
|
||||
print " [" . $dataBlock->{extension_unit} . ", " . $dataBlock->{extension_value} . "]";
|
||||
}
|
||||
print "\n";
|
||||
#}
|
||||
}
|
||||
} else {
|
||||
printf("Error %d: %s\n", $self->{errorcode}, $self->{errormsg});
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
Loading…
Reference in New Issue
Block a user