issue-51-telegram WIP
This commit is contained in:
		
							parent
							
								
									3e0332963c
								
							
						
					
					
						commit
						2adcd2b207
					
				| @ -24,9 +24,9 @@ ELECTRICITY_ACTIVE_TARIFF = r'\d-\d:96\.14\.0.+?\r\n' | |||||||
| EQUIPMENT_IDENTIFIER = r'\d-\d:96\.1\.1.+?\r\n' | EQUIPMENT_IDENTIFIER = r'\d-\d:96\.1\.1.+?\r\n' | ||||||
| CURRENT_ELECTRICITY_USAGE = r'\d-\d:1\.7\.0.+?\r\n' | CURRENT_ELECTRICITY_USAGE = r'\d-\d:1\.7\.0.+?\r\n' | ||||||
| CURRENT_ELECTRICITY_DELIVERY = r'\d-\d:2\.7\.0.+?\r\n' | CURRENT_ELECTRICITY_DELIVERY = r'\d-\d:2\.7\.0.+?\r\n' | ||||||
| LONG_POWER_FAILURE_COUNT = r'96\.7\.9.+?\r\n' | LONG_POWER_FAILURE_COUNT = r'\d-\d:96\.7\.9.+?\r\n' | ||||||
| SHORT_POWER_FAILURE_COUNT = r'96\.7\.21.+?\r\n' | SHORT_POWER_FAILURE_COUNT = r'\d-\d:96\.7\.21.+?\r\n' | ||||||
| POWER_EVENT_FAILURE_LOG = r'99\.97\.0.+?\r\n' | POWER_EVENT_FAILURE_LOG = r'\d-\d:99\.97\.0.+?\r\n' | ||||||
| VOLTAGE_SAG_L1_COUNT = r'\d-\d:32\.32\.0.+?\r\n' | VOLTAGE_SAG_L1_COUNT = r'\d-\d:32\.32\.0.+?\r\n' | ||||||
| VOLTAGE_SAG_L2_COUNT = r'\d-\d:52\.32\.0.+?\r\n' | VOLTAGE_SAG_L2_COUNT = r'\d-\d:52\.32\.0.+?\r\n' | ||||||
| VOLTAGE_SAG_L3_COUNT = r'\d-\d:72\.32\.0.+?\r\n' | VOLTAGE_SAG_L3_COUNT = r'\d-\d:72\.32\.0.+?\r\n' | ||||||
|  | |||||||
| @ -24,11 +24,18 @@ class Telegram(object): | |||||||
|         self._reverse_obis_name_mapping = dsmr_parser.obis_name_mapping.REVERSE_EN |         self._reverse_obis_name_mapping = dsmr_parser.obis_name_mapping.REVERSE_EN | ||||||
|         self._item_names = self._get_item_names() |         self._item_names = self._get_item_names() | ||||||
| 
 | 
 | ||||||
|     def add(self, obis_reference, value): |     def add(self, obis_reference, dsmr_object): | ||||||
|         self._telegram_data[obis_reference].append(value) |         self._telegram_data[obis_reference].append(dsmr_object) | ||||||
| 
 | 
 | ||||||
|     def get(self, obis_reference, channel): |     # TODO experiment with api to see what is nice | ||||||
|         return next(filter(lambda x: x.channel == channel, self._telegram_data[obis_reference])) |     def get(self, obis_reference, channel=None): | ||||||
|  |         if channel is None: | ||||||
|  |             return self._telegram_data[obis_reference] | ||||||
|  | 
 | ||||||
|  |         try: | ||||||
|  |             return next(filter(lambda x: x.channel == channel, self._telegram_data[obis_reference])) | ||||||
|  |         except StopIteration: | ||||||
|  |             return None | ||||||
| 
 | 
 | ||||||
|     def __getattr__(self, name): |     def __getattr__(self, name): | ||||||
|         """ will only get called for undefined attributes """ |         """ will only get called for undefined attributes """ | ||||||
| @ -66,13 +73,10 @@ class DSMRObject(object): | |||||||
|     Represents all data from a single telegram line. |     Represents all data from a single telegram line. | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def __init__(self, values): |     def __init__(self, channel, values): | ||||||
|  |         self.channel = channel  # TODO consider if only MBus should have channels | ||||||
|         self.values = values |         self.values = values | ||||||
| 
 | 
 | ||||||
|     @property |  | ||||||
|     def channel(self): |  | ||||||
|         return 0  # TODO |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| class MBusObject(DSMRObject): | class MBusObject(DSMRObject): | ||||||
| 
 | 
 | ||||||
| @ -203,8 +207,8 @@ class ProfileGenericObject(DSMRObject): | |||||||
|     containing the datetime (timestamp) and the value. |     containing the datetime (timestamp) and the value. | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def __init__(self, values): |     def __init__(self, *args, **kwargs): | ||||||
|         super().__init__(values) |         super().__init__(*args, **kwargs) | ||||||
|         self._buffer_list = None |         self._buffer_list = None | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
| @ -230,9 +234,16 @@ class ProfileGenericObject(DSMRObject): | |||||||
|         if self._buffer_list is None: |         if self._buffer_list is None: | ||||||
|             self._buffer_list = [] |             self._buffer_list = [] | ||||||
|             values_offset = 2 |             values_offset = 2 | ||||||
|  | 
 | ||||||
|             for i in range(self.buffer_length): |             for i in range(self.buffer_length): | ||||||
|                 offset = values_offset + i * 2 |                 offset = values_offset + i * 2 | ||||||
|                 self._buffer_list.append(MBusObject([self.values[offset], self.values[offset + 1]])) |                 self._buffer_list.append( | ||||||
|  |                     MBusObject( | ||||||
|  |                         channel=self.channel, | ||||||
|  |                         values=[self.values[offset], self.values[offset + 1]] | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  | 
 | ||||||
|         return self._buffer_list |         return self._buffer_list | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ logger = logging.getLogger(__name__) | |||||||
| class TelegramParser(object): | class TelegramParser(object): | ||||||
|     crc16_tab = [] |     crc16_tab = [] | ||||||
| 
 | 
 | ||||||
|     def __init__(self, telegram_specification, apply_checksum_validation=True, gas_meter_channel=None): |     def __init__(self, telegram_specification, apply_checksum_validation=True): | ||||||
|         """ |         """ | ||||||
|         :param telegram_specification: determines how the telegram is parsed |         :param telegram_specification: determines how the telegram is parsed | ||||||
|         :param apply_checksum_validation: validate checksum if applicable for |         :param apply_checksum_validation: validate checksum if applicable for | ||||||
| @ -87,12 +87,12 @@ class TelegramParser(object): | |||||||
|             # so only parse lines that match |             # so only parse lines that match | ||||||
|             for match in matches: |             for match in matches: | ||||||
|                 try: |                 try: | ||||||
|                     value = parser.parse(match) |                     dsmr_object = parser.parse(match) | ||||||
|                 except Exception: |                 except Exception: | ||||||
|                     logger.error("ignore line with signature {}, because parsing failed.".format(signature), |                     logger.error("ignore line with signature {}, because parsing failed.".format(signature), | ||||||
|                                  exc_info=True) |                                  exc_info=True) | ||||||
|                 else: |                 else: | ||||||
|                     telegram.add(obis_reference=signature, value=value) |                     telegram.add(obis_reference=signature, dsmr_object=dsmr_object) | ||||||
| 
 | 
 | ||||||
|         return telegram |         return telegram | ||||||
| 
 | 
 | ||||||
| @ -174,6 +174,20 @@ class DSMRObjectParser(object): | |||||||
|         return [self.value_formats[i].parse(value) |         return [self.value_formats[i].parse(value) | ||||||
|                 for i, value in enumerate(values)] |                 for i, value in enumerate(values)] | ||||||
| 
 | 
 | ||||||
|  |     def _parse_channel(self, line): | ||||||
|  |         """ | ||||||
|  |         Get the channel identifier of a line. | ||||||
|  | 
 | ||||||
|  |         Line format: | ||||||
|  |         '0-2:24.2.1(200426223001S)(00246.138*m3)' | ||||||
|  |            ^ | ||||||
|  |         channel | ||||||
|  |         """ | ||||||
|  |         try: | ||||||
|  |             return int(line[2]) | ||||||
|  |         except ValueError: | ||||||
|  |             raise ParseError("Invalid channel for line '%s' in '%s'", line, self) | ||||||
|  | 
 | ||||||
|     def _parse(self, line): |     def _parse(self, line): | ||||||
|         # Match value groups, but exclude the parentheses |         # Match value groups, but exclude the parentheses | ||||||
|         pattern = re.compile(r'((?<=\()[0-9a-zA-Z\.\*\-\:]{0,}(?=\)))') |         pattern = re.compile(r'((?<=\()[0-9a-zA-Z\.\*\-\:]{0,}(?=\)))') | ||||||
| @ -207,7 +221,10 @@ class MBusParser(DSMRObjectParser): | |||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def parse(self, line): |     def parse(self, line): | ||||||
|         return MBusObject(self._parse(line)) |         return MBusObject( | ||||||
|  |             channel=self._parse_channel(line), | ||||||
|  |             values=self._parse(line) | ||||||
|  |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class MaxDemandParser(DSMRObjectParser): | class MaxDemandParser(DSMRObjectParser): | ||||||
| @ -235,6 +252,8 @@ class MaxDemandParser(DSMRObjectParser): | |||||||
|         pattern = re.compile(r'((?<=\()[0-9a-zA-Z\.\*\-\:]{0,}(?=\)))') |         pattern = re.compile(r'((?<=\()[0-9a-zA-Z\.\*\-\:]{0,}(?=\)))') | ||||||
|         values = re.findall(pattern, line) |         values = re.findall(pattern, line) | ||||||
| 
 | 
 | ||||||
|  |         channel = self._parse_channel(line) | ||||||
|  | 
 | ||||||
|         objects = [] |         objects = [] | ||||||
| 
 | 
 | ||||||
|         count = int(values[0]) |         count = int(values[0]) | ||||||
| @ -242,7 +261,10 @@ class MaxDemandParser(DSMRObjectParser): | |||||||
|             timestamp_month = ValueParser(timestamp).parse(values[i * 3 + 1]) |             timestamp_month = ValueParser(timestamp).parse(values[i * 3 + 1]) | ||||||
|             timestamp_occurred = ValueParser(timestamp).parse(values[i * 3 + 1]) |             timestamp_occurred = ValueParser(timestamp).parse(values[i * 3 + 1]) | ||||||
|             value = ValueParser(Decimal).parse(values[i * 3 + 2]) |             value = ValueParser(Decimal).parse(values[i * 3 + 2]) | ||||||
|             objects.append(MBusObjectPeak([timestamp_month, timestamp_occurred, value])) |             objects.append(MBusObjectPeak( | ||||||
|  |                 channel=channel, | ||||||
|  |                 values=[timestamp_month, timestamp_occurred, value] | ||||||
|  |             )) | ||||||
| 
 | 
 | ||||||
|         return objects |         return objects | ||||||
| 
 | 
 | ||||||
| @ -268,7 +290,10 @@ class CosemParser(DSMRObjectParser): | |||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def parse(self, line): |     def parse(self, line): | ||||||
|         return CosemObject(self._parse(line)) |         return CosemObject( | ||||||
|  |             channel=self._parse_channel(line), | ||||||
|  |             values=self._parse(line) | ||||||
|  |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ProfileGenericParser(DSMRObjectParser): | class ProfileGenericParser(DSMRObjectParser): | ||||||
| @ -327,7 +352,10 @@ class ProfileGenericParser(DSMRObjectParser): | |||||||
|         return [self.value_formats[i].parse(value) for i, value in enumerate(values)] |         return [self.value_formats[i].parse(value) for i, value in enumerate(values)] | ||||||
| 
 | 
 | ||||||
|     def parse(self, line): |     def parse(self, line): | ||||||
|         return ProfileGenericObject(self._parse(line)) |         return ProfileGenericObject( | ||||||
|  |             channel=self._parse_channel(line), | ||||||
|  |             values=self._parse(line) | ||||||
|  |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ValueParser(object): | class ValueParser(object): | ||||||
| @ -335,7 +363,7 @@ class ValueParser(object): | |||||||
|     Parses a single value from DSMRObject's. |     Parses a single value from DSMRObject's. | ||||||
| 
 | 
 | ||||||
|     Example with coerce_type being int: |     Example with coerce_type being int: | ||||||
|         (002*A) becomes {'value': 1, 'unit': 'A'} |         (002*A) becomes {'value': 2, 'unit': 'A'} | ||||||
| 
 | 
 | ||||||
|     Example with coerce_type being str: |     Example with coerce_type being str: | ||||||
|         (42) becomes {'value': '42', 'unit': None} |         (42) becomes {'value': '42', 'unit': None} | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user