From edf535f987fdb6df7e18a2790ecc0d37f3562946 Mon Sep 17 00:00:00 2001 From: Jean-Louis Dupond Date: Mon, 30 Jan 2023 14:09:17 +0100 Subject: [PATCH] Fix parsing with invalid timestamps Sometimes the timestamp in the DSMR message is invalid (when no data read read from the mbus meter?), and then parsing fails. Fixing this by handling the exception and returning None for invalid timestamps. Fixes: #120 --- dsmr_parser/value_types.py | 13 +++++++++++-- test/test_parse_v5.py | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/dsmr_parser/value_types.py b/dsmr_parser/value_types.py index 4bc9ef3..487e98c 100644 --- a/dsmr_parser/value_types.py +++ b/dsmr_parser/value_types.py @@ -4,14 +4,23 @@ import pytz def timestamp(value): - naive_datetime = datetime.datetime.strptime(value[:-1], '%y%m%d%H%M%S') + try: + naive_datetime = datetime.datetime.strptime(value[:-1], '%y%m%d%H%M%S') + except ValueError: + return None - # TODO comment on this exception + # Timestamp has the following format: + # YYMMDDhhmmssX + # ASCII presentation of Time stamp with + # Year, Month, Day, Hour, Minute, Second, + # and an indication whether DST is active + # (X=S) or DST is not active (X=W) if len(value) == 13: is_dst = value[12] == 'S' # assume format 160322150000W else: is_dst = False + # TODO : Use system timezone local_tz = pytz.timezone('Europe/Amsterdam') localized_datetime = local_tz.localize(naive_datetime, is_dst=is_dst) diff --git a/test/test_parse_v5.py b/test/test_parse_v5.py index fe3ed84..fcc27db 100644 --- a/test/test_parse_v5.py +++ b/test/test_parse_v5.py @@ -244,3 +244,21 @@ class TelegramParserV5Test(unittest.TestCase): corrupted_telegram = TELEGRAM_V5.replace('!6EEE\r\n', '') with self.assertRaises(ParseError): TelegramParser.validate_checksum(corrupted_telegram) + + def test_gas_timestamp_invalid(self): + # Issue 120 + # Sometimes a MBUS device (For ex a Gas Meter) returns an invalid timestamp + # Instead of failing, we should just ignore the timestamp + invalid_date_telegram = TELEGRAM_V5.replace( + '0-1:24.2.1(170102161005W)(00000.107*m3)\r\n', + '0-1:24.2.1(632525252525S)(00000.000)\r\n' + ) + invalid_date_telegram = invalid_date_telegram.replace('!6EEE\r\n', '!90C2\r\n') + parser = TelegramParser(telegram_specifications.V5) + result = parser.parse(invalid_date_telegram) + + # HOURLY_GAS_METER_READING (0-1:24.2.1) + assert isinstance(result[obis.HOURLY_GAS_METER_READING], MBusObject) + assert result[obis.HOURLY_GAS_METER_READING].unit is None + assert isinstance(result[obis.HOURLY_GAS_METER_READING].value, Decimal) + assert result[obis.HOURLY_GAS_METER_READING].value == Decimal('0.000')