mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-10 03:06:37 +00:00
WMBUS: correct decoding of hour in timestamp, convert manufacturer to upper case, implemented more VIFs
git-svn-id: https://svn.fhem.de/fhem/trunk@6418 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
f9f71cf54c
commit
9b559ebb93
@ -114,7 +114,7 @@ WMBUS_Define($$)
|
||||
if ($mb->parseApplicationLayer()) {
|
||||
if ($mb->{cifield} == WMBus::CI_RESP_12) {
|
||||
$hash->{Meter_Id} = $mb->{meter_id};
|
||||
$hash->{Meter_Manufacturer} = $mb->manId2ascii($mb->{meter_man});
|
||||
$hash->{Meter_Manufacturer} = $mb->{meter_manufacturer};
|
||||
$hash->{Meter_Version} = $mb->{meter_vers};
|
||||
$hash->{Meter_Dev} = $mb->{meter_devtypestring};
|
||||
$hash->{Access_No} = $mb->{access_no};
|
||||
@ -241,6 +241,9 @@ sub WMBUS_SetReadings($$$)
|
||||
readingsBulkUpdate($hash, "$dataBlock->{number}:type", $dataBlock->{type});
|
||||
readingsBulkUpdate($hash, "$dataBlock->{number}:value", $dataBlock->{value});
|
||||
readingsBulkUpdate($hash, "$dataBlock->{number}:unit", $dataBlock->{unit});
|
||||
if ($dataBlock->{errormsg}) {
|
||||
readingsBulkUpdate($hash, "$dataBlock->{number}:errormsg", $dataBlock->{errormsg});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ require Exporter;
|
||||
my @ISA = qw(Exporter);
|
||||
my @EXPORT = qw(new parse parseLinkLayer parseApplicationLayer manId2ascii type2string);
|
||||
|
||||
sub manId2ascii($$);
|
||||
|
||||
|
||||
use constant {
|
||||
# sent by meter
|
||||
@ -128,10 +130,17 @@ sub valueCalcDateTime($$) {
|
||||
|
||||
|
||||
my $datePart = $value >> 16;
|
||||
my $min = ($value & 0b111111);
|
||||
my $hour = ($value & 0b11111) >> 6;
|
||||
my $timeInvalid = $value & 0b10000000;
|
||||
|
||||
return valueCalcDate($datePart, $dataBlock) . sprintf(' %02d:%02d', $hour, $min);
|
||||
my $dateTime = valueCalcDate($datePart, $dataBlock);
|
||||
if ($timeInvalid == 0) {
|
||||
my $min = ($value & 0b111111);
|
||||
my $hour = ($value >> 6) & 0b11111;
|
||||
my $su = ($value & 0b10000000000000000);
|
||||
$dateTime .= sprintf(' %02d:%02d %s', $hour, $min, $su ? 'DST' : '');
|
||||
}
|
||||
|
||||
return $dateTime;
|
||||
}
|
||||
|
||||
sub valueCalcHex($$) {
|
||||
@ -331,8 +340,24 @@ my %VIFInfo = (
|
||||
},
|
||||
);
|
||||
|
||||
# Codes used with extension indicator $FD
|
||||
my %VIFInfo_FD = (
|
||||
# Codes used with extension indicator $FD, see 8.4.4 on page 80
|
||||
my %VIFInfo_FD = (
|
||||
VIF_CREDIT => { # Credit of 10nn-3 of the nominal local legal currency units
|
||||
typeMask => 0b01111100,
|
||||
expMask => 0b00000011,
|
||||
type => 0b00000000,
|
||||
bias => -3,
|
||||
unit => '€',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
},
|
||||
VIF_DEBIT => { # Debit of 10nn-3 of the nominal local legal currency units
|
||||
typeMask => 0b01111100,
|
||||
expMask => 0b00000011,
|
||||
type => 0b00000100,
|
||||
bias => -3,
|
||||
unit => '€',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
},
|
||||
VIF_ACCESS_NO => { # Access number (transmission count)
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
@ -341,6 +366,14 @@ my %VIFInfo_FD = (
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
},
|
||||
VIF_MEDIUM => { # Medium (as in fixed header)
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
type => 0b00001001,
|
||||
bias => 0,
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
},
|
||||
VIF_MODEL_VERSION => { # Model / Version
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
@ -349,7 +382,7 @@ my %VIFInfo_FD = (
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
},
|
||||
VIF_ERROR_FLAGS => { # Error flags (binary)
|
||||
VIF_ERROR_FLAGS => { # Error flags (binary)
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
type => 0b00010111,
|
||||
@ -357,6 +390,30 @@ my %VIFInfo_FD = (
|
||||
unit => '',
|
||||
calcFunc => \&valueCalcHex,
|
||||
},
|
||||
VIF_VOLTAGE => { # 10nnnn-9 Volts
|
||||
typeMask => 0b01110000,
|
||||
expMask => 0b00001111,
|
||||
type => 0b01000000,
|
||||
bias => -9,
|
||||
unit => 'V',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
},
|
||||
VIF_ELECTRICAL_CURRENT => { # 10nnnn-12 Ampere
|
||||
typeMask => 0b01110000,
|
||||
expMask => 0b00001111,
|
||||
type => 0b01010000,
|
||||
bias => -12,
|
||||
unit => 'A',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
},
|
||||
VIF_RECEPTION_LEVEL => { # reception level of a received radio device.
|
||||
typeMask => 0b01111111,
|
||||
expMask => 0b00000000,
|
||||
type => 0b01110001,
|
||||
bias => 0,
|
||||
unit => 'dBm',
|
||||
calcFunc => \&valueCalcNumeric,
|
||||
},
|
||||
);
|
||||
|
||||
# Codes used with extension indicator $FB
|
||||
@ -506,7 +563,7 @@ sub removeCRC($$)
|
||||
|
||||
sub manId2hex($$)
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = shift;
|
||||
my $idascii = shift;
|
||||
|
||||
return (ord(substr($idascii,1,1))-64) << 10 | (ord(substr($idascii,2,1))-64) << 5 | (ord(substr($idascii,3,1))-64);
|
||||
@ -514,7 +571,7 @@ sub manId2hex($$)
|
||||
|
||||
sub manId2ascii($$)
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = shift;
|
||||
my $idhex = shift;
|
||||
|
||||
return chr(($idhex >> 10) + 64) . chr((($idhex >> 5) & 0b00011111) + 64) . chr(($idhex & 0b00011111) + 64);
|
||||
@ -576,6 +633,7 @@ sub decodeValueInformationBlock($$$) {
|
||||
my $bias;
|
||||
my $exponent;
|
||||
my $vifInfoRef = \%VIFInfo;
|
||||
my $vifExtension = 0;
|
||||
|
||||
$vif = unpack('C', $vib);
|
||||
$offset = 1;
|
||||
@ -584,18 +642,20 @@ sub decodeValueInformationBlock($$$) {
|
||||
|
||||
if ($isExtension) {
|
||||
# switch to extension codes
|
||||
if ($vif == 0xFD) {
|
||||
$vifExtension = $vif;
|
||||
if ($vifExtension == 0xFD) {
|
||||
$vifInfoRef = \%VIFInfo_FD;
|
||||
} elsif ($vif == 0xFB) {
|
||||
} elsif ($vifExtension == 0xFB) {
|
||||
$vifInfoRef = \%VIFInfo_FB;
|
||||
} elsif ($vif == 0xFF) {
|
||||
} elsif ($vifExtension == 0xFF) {
|
||||
# manufacturer specific data, can't be interpreted
|
||||
$dataBlockRef->{type} = "MANUFACTURER SPECIFIC";
|
||||
$dataBlockRef->{unit} = "";
|
||||
$dataBlockRef->{value} = "";
|
||||
return $offset;
|
||||
} else {
|
||||
$self->{errormsg} = "unknown VIFE " . sprintf("%x", $vif) . " at offset $offset-1";
|
||||
$self->{errorcode} = ERR_UNKNOWN_VIFE;
|
||||
$dataBlockRef->{errormsg} = "unknown VIFE " . sprintf("%x", $vifExtension) . " at offset $offset-1";
|
||||
$dataBlockRef->{errorcode} = ERR_UNKNOWN_VIFE;
|
||||
}
|
||||
$vif = unpack('C', substr($vib,$offset++,1));
|
||||
}
|
||||
@ -626,8 +686,8 @@ sub decodeValueInformationBlock($$$) {
|
||||
}
|
||||
|
||||
if ($dataBlockRef->{type} eq '') {
|
||||
$self->{errormsg} = "unknown VIF " . sprintf("%x",$vif);
|
||||
$self->{errorcode} = ERR_UNKNOWN_VIF;
|
||||
$dataBlockRef->{errormsg} = sprintf("in VIFExtension %x unknown VIF %x",$vifExtension, $vif);
|
||||
$dataBlockRef->{errorcode} = ERR_UNKNOWN_VIF;
|
||||
}
|
||||
|
||||
return $offset;
|
||||
@ -663,8 +723,8 @@ sub decodeDataInformationBlock($$$) {
|
||||
$isExtension = $dif & DIF_EXTENSION_BIT;
|
||||
$difExtNo++;
|
||||
if ($difExtNo > 10) {
|
||||
$self->{errormsg} = 'too many DIFE';
|
||||
$self->{errorcode} = ERR_TOO_MANY_DIFE;
|
||||
$dataBlockRef->{errormsg} = 'too many DIFE';
|
||||
$dataBlockRef->{errorcode} = ERR_TOO_MANY_DIFE;
|
||||
last EXTENSION;
|
||||
}
|
||||
|
||||
@ -720,6 +780,7 @@ sub decodePayload($$) {
|
||||
# create a new anonymous hash reference
|
||||
$dataBlock = {};
|
||||
$dataBlock->{number} = $dataBlockNo;
|
||||
$dataBlock->{unit} = '';
|
||||
|
||||
while (unpack('C',substr($payload,$offset,1)) == 0x2f) {
|
||||
# skip filler bytes
|
||||
@ -731,7 +792,6 @@ sub decodePayload($$) {
|
||||
}
|
||||
|
||||
$offset += $self->decodeDataRecordHeader(substr($payload,$offset), $dataBlock);
|
||||
|
||||
#printf("No. %d, type %x at offset %d\n", $dataBlockNo, $dataBlock->{dataField}, $offset-1);
|
||||
|
||||
if ($dataBlock->{dataField} == DIF_NONE || $dataBlock->{dataField} == DIF_READOUT) {
|
||||
@ -787,6 +847,8 @@ sub decodePayload($$) {
|
||||
if (defined $dataBlock->{calcFunc}) {
|
||||
$dataBlock->{value} = $dataBlock->{calcFunc}->($value, $dataBlock);
|
||||
#print "Value raw " . $value . " value calc " . $dataBlock->{value} ."\n";
|
||||
} else {
|
||||
$dataBlock->{value} = "";
|
||||
}
|
||||
|
||||
push @dataBlocks, $dataBlock;
|
||||
@ -840,7 +902,7 @@ sub decodeApplicationLayer($) {
|
||||
($self->{meter_id}, $self->{meter_man}, $self->{meter_vers}, $self->{meter_dev}, $self->{access_no}, $self->{status}, $self->{cw})
|
||||
= unpack('VvCCCCn', substr($applicationlayer,$offset));
|
||||
$self->{meter_devtypestring} = $validDeviceTypes{$self->{meter_dev}} || 'unknown';
|
||||
$self->{meter_manufacturer} = $self->manId2ascii($self->{meter_man});
|
||||
# $self->{meter_manufacturer} = uc($self->manId2ascii($self->{meter_man}));
|
||||
$offset += 12;
|
||||
} else {
|
||||
# unsupported
|
||||
@ -919,7 +981,10 @@ sub decodeLinkLayer($$)
|
||||
return 0;
|
||||
}
|
||||
|
||||
$self->{manufacturer} = $self->manId2ascii($self->{mfield});
|
||||
# according to the MBus spec only upper case letters are allowed.
|
||||
# some devices send lower case letters none the less
|
||||
# convert to upper case to make them spec conformant
|
||||
$self->{manufacturer} = uc($self->manId2ascii($self->{mfield}));
|
||||
$self->{typestring} = $validDeviceTypes{$self->{afield_type}} || 'unknown';
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user