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' | ||||
| CURRENT_ELECTRICITY_USAGE = r'\d-\d:1\.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' | ||||
| SHORT_POWER_FAILURE_COUNT = r'96\.7\.21.+?\r\n' | ||||
| POWER_EVENT_FAILURE_LOG = r'99\.97\.0.+?\r\n' | ||||
| LONG_POWER_FAILURE_COUNT = r'\d-\d:96\.7\.9.+?\r\n' | ||||
| SHORT_POWER_FAILURE_COUNT = r'\d-\d:96\.7\.21.+?\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_L2_COUNT = r'\d-\d:52\.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._item_names = self._get_item_names() | ||||
| 
 | ||||
|     def add(self, obis_reference, value): | ||||
|         self._telegram_data[obis_reference].append(value) | ||||
|     def add(self, obis_reference, dsmr_object): | ||||
|         self._telegram_data[obis_reference].append(dsmr_object) | ||||
| 
 | ||||
|     def get(self, obis_reference, channel): | ||||
|     # TODO experiment with api to see what is nice | ||||
|     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): | ||||
|         """ will only get called for undefined attributes """ | ||||
| @ -66,13 +73,10 @@ class DSMRObject(object): | ||||
|     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 | ||||
| 
 | ||||
|     @property | ||||
|     def channel(self): | ||||
|         return 0  # TODO | ||||
| 
 | ||||
| 
 | ||||
| class MBusObject(DSMRObject): | ||||
| 
 | ||||
| @ -203,8 +207,8 @@ class ProfileGenericObject(DSMRObject): | ||||
|     containing the datetime (timestamp) and the value. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, values): | ||||
|         super().__init__(values) | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         super().__init__(*args, **kwargs) | ||||
|         self._buffer_list = None | ||||
| 
 | ||||
|     @property | ||||
| @ -230,9 +234,16 @@ class ProfileGenericObject(DSMRObject): | ||||
|         if self._buffer_list is None: | ||||
|             self._buffer_list = [] | ||||
|             values_offset = 2 | ||||
| 
 | ||||
|             for i in range(self.buffer_length): | ||||
|                 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 | ||||
| 
 | ||||
|     def __str__(self): | ||||
|  | ||||
| @ -18,7 +18,7 @@ logger = logging.getLogger(__name__) | ||||
| class TelegramParser(object): | ||||
|     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 apply_checksum_validation: validate checksum if applicable for | ||||
| @ -87,12 +87,12 @@ class TelegramParser(object): | ||||
|             # so only parse lines that match | ||||
|             for match in matches: | ||||
|                 try: | ||||
|                     value = parser.parse(match) | ||||
|                     dsmr_object = parser.parse(match) | ||||
|                 except Exception: | ||||
|                     logger.error("ignore line with signature {}, because parsing failed.".format(signature), | ||||
|                                  exc_info=True) | ||||
|                 else: | ||||
|                     telegram.add(obis_reference=signature, value=value) | ||||
|                     telegram.add(obis_reference=signature, dsmr_object=dsmr_object) | ||||
| 
 | ||||
|         return telegram | ||||
| 
 | ||||
| @ -174,6 +174,20 @@ class DSMRObjectParser(object): | ||||
|         return [self.value_formats[i].parse(value) | ||||
|                 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): | ||||
|         # Match value groups, but exclude the parentheses | ||||
|         pattern = re.compile(r'((?<=\()[0-9a-zA-Z\.\*\-\:]{0,}(?=\)))') | ||||
| @ -207,7 +221,10 @@ class MBusParser(DSMRObjectParser): | ||||
|     """ | ||||
| 
 | ||||
|     def parse(self, line): | ||||
|         return MBusObject(self._parse(line)) | ||||
|         return MBusObject( | ||||
|             channel=self._parse_channel(line), | ||||
|             values=self._parse(line) | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| class MaxDemandParser(DSMRObjectParser): | ||||
| @ -235,6 +252,8 @@ class MaxDemandParser(DSMRObjectParser): | ||||
|         pattern = re.compile(r'((?<=\()[0-9a-zA-Z\.\*\-\:]{0,}(?=\)))') | ||||
|         values = re.findall(pattern, line) | ||||
| 
 | ||||
|         channel = self._parse_channel(line) | ||||
| 
 | ||||
|         objects = [] | ||||
| 
 | ||||
|         count = int(values[0]) | ||||
| @ -242,7 +261,10 @@ class MaxDemandParser(DSMRObjectParser): | ||||
|             timestamp_month = ValueParser(timestamp).parse(values[i * 3 + 1]) | ||||
|             timestamp_occurred = ValueParser(timestamp).parse(values[i * 3 + 1]) | ||||
|             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 | ||||
| 
 | ||||
| @ -268,7 +290,10 @@ class CosemParser(DSMRObjectParser): | ||||
|     """ | ||||
| 
 | ||||
|     def parse(self, line): | ||||
|         return CosemObject(self._parse(line)) | ||||
|         return CosemObject( | ||||
|             channel=self._parse_channel(line), | ||||
|             values=self._parse(line) | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| class ProfileGenericParser(DSMRObjectParser): | ||||
| @ -327,7 +352,10 @@ class ProfileGenericParser(DSMRObjectParser): | ||||
|         return [self.value_formats[i].parse(value) for i, value in enumerate(values)] | ||||
| 
 | ||||
|     def parse(self, line): | ||||
|         return ProfileGenericObject(self._parse(line)) | ||||
|         return ProfileGenericObject( | ||||
|             channel=self._parse_channel(line), | ||||
|             values=self._parse(line) | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| class ValueParser(object): | ||||
| @ -335,7 +363,7 @@ class ValueParser(object): | ||||
|     Parses a single value from DSMRObject's. | ||||
| 
 | ||||
|     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: | ||||
|         (42) becomes {'value': '42', 'unit': None} | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user