Merge pull request #40 from lowdef/add_a_true_telegram_object
Add a true telegram object
This commit is contained in:
		
						commit
						659560222a
					
				
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -6,3 +6,7 @@ | |||||||
| /.project | /.project | ||||||
| /.pydevproject | /.pydevproject | ||||||
| /.coverage | /.coverage | ||||||
|  | build/ | ||||||
|  | dist/ | ||||||
|  | *.*~ | ||||||
|  | *~ | ||||||
							
								
								
									
										113
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								README.rst
									
									
									
									
									
								
							| @ -85,8 +85,8 @@ into a dictionary. | |||||||
|      telegram = parser.parse(telegram_str) |      telegram = parser.parse(telegram_str) | ||||||
|      print(telegram)  # see 'Telegram object' docs below |      print(telegram)  # see 'Telegram object' docs below | ||||||
| 
 | 
 | ||||||
| Telegram object | Telegram dictionary | ||||||
| --------------- | ------------------- | ||||||
| 
 | 
 | ||||||
| A dictionary of which the key indicates the field type. These regex values | A dictionary of which the key indicates the field type. These regex values | ||||||
| correspond to one of dsmr_parser.obis_reference constants. | correspond to one of dsmr_parser.obis_reference constants. | ||||||
| @ -138,6 +138,115 @@ Example to get some of the values: | |||||||
|     # See dsmr_reader.obis_references for all readable telegram values. |     # See dsmr_reader.obis_references for all readable telegram values. | ||||||
|     # Note that the avilable values differ per DSMR version. |     # Note that the avilable values differ per DSMR version. | ||||||
| 
 | 
 | ||||||
|  | Telegram as an Object | ||||||
|  | --------------------- | ||||||
|  | An object version of the telegram is available as well. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | .. code-block:: python | ||||||
|  | 
 | ||||||
|  |     # DSMR v4.2 p1 using dsmr_parser and telegram objects | ||||||
|  | 
 | ||||||
|  |     from dsmr_parser import telegram_specifications | ||||||
|  |     from dsmr_parser.clients import SerialReader, SERIAL_SETTINGS_V5 | ||||||
|  |     from dsmr_parser.objects import CosemObject, MBusObject, Telegram | ||||||
|  |     from dsmr_parser.parsers import TelegramParser | ||||||
|  |     import os | ||||||
|  | 
 | ||||||
|  |     serial_reader = SerialReader( | ||||||
|  |         device='/dev/ttyUSB0', | ||||||
|  |         serial_settings=SERIAL_SETTINGS_V5, | ||||||
|  |         telegram_specification=telegram_specifications.V4 | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     # telegram = next(serial_reader.read_as_object()) | ||||||
|  |     # print(telegram) | ||||||
|  | 
 | ||||||
|  |     for telegram in serial_reader.read_as_object(): | ||||||
|  |         os.system('clear') | ||||||
|  |         print(telegram) | ||||||
|  | 
 | ||||||
|  | Example of output of print of the telegram object: | ||||||
|  | 
 | ||||||
|  | .. code-block:: console | ||||||
|  | 
 | ||||||
|  |     P1_MESSAGE_HEADER: 	 42 	[None] | ||||||
|  |     P1_MESSAGE_TIMESTAMP: 	 2016-11-13 19:57:57+00:00 	[None] | ||||||
|  |     EQUIPMENT_IDENTIFIER: 	 3960221976967177082151037881335713 	[None] | ||||||
|  |     ELECTRICITY_USED_TARIFF_1: 	 1581.123 	[kWh] | ||||||
|  |     ELECTRICITY_USED_TARIFF_2: 	 1435.706 	[kWh] | ||||||
|  |     ELECTRICITY_DELIVERED_TARIFF_1: 	 0.000 	[kWh] | ||||||
|  |     ELECTRICITY_DELIVERED_TARIFF_2: 	 0.000 	[kWh] | ||||||
|  |     ELECTRICITY_ACTIVE_TARIFF: 	 0002 	[None] | ||||||
|  |     CURRENT_ELECTRICITY_USAGE: 	 2.027 	[kW] | ||||||
|  |     CURRENT_ELECTRICITY_DELIVERY: 	 0.000 	[kW] | ||||||
|  |     LONG_POWER_FAILURE_COUNT: 	 7 	[None] | ||||||
|  |     VOLTAGE_SAG_L1_COUNT: 	 0 	[None] | ||||||
|  |     VOLTAGE_SAG_L2_COUNT: 	 0 	[None] | ||||||
|  |     VOLTAGE_SAG_L3_COUNT: 	 0 	[None] | ||||||
|  |     VOLTAGE_SWELL_L1_COUNT: 	 0 	[None] | ||||||
|  |     VOLTAGE_SWELL_L2_COUNT: 	 0 	[None] | ||||||
|  |     VOLTAGE_SWELL_L3_COUNT: 	 0 	[None] | ||||||
|  |     TEXT_MESSAGE_CODE: 	 None 	[None] | ||||||
|  |     TEXT_MESSAGE: 	 None 	[None] | ||||||
|  |     DEVICE_TYPE: 	 3 	[None] | ||||||
|  |     INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE: 	 0.170 	[kW] | ||||||
|  |     INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE: 	 1.247 	[kW] | ||||||
|  |     INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE: 	 0.209 	[kW] | ||||||
|  |     INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE: 	 0.000 	[kW] | ||||||
|  |     INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE: 	 0.000 	[kW] | ||||||
|  |     INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE: 	 0.000 	[kW] | ||||||
|  |     EQUIPMENT_IDENTIFIER_GAS: 	 4819243993373755377509728609491464 	[None] | ||||||
|  |     HOURLY_GAS_METER_READING: 	 981.443 	[m3] | ||||||
|  | 
 | ||||||
|  | Accessing the telegrams information as  attributes directly: | ||||||
|  | 
 | ||||||
|  | .. code-block:: python | ||||||
|  | 
 | ||||||
|  |     telegram | ||||||
|  |     Out[3]: <dsmr_parser.objects.Telegram at 0x7f5e995d9898> | ||||||
|  |     telegram.CURRENT_ELECTRICITY_USAGE | ||||||
|  |     Out[4]: <dsmr_parser.objects.CosemObject at 0x7f5e98ae5ac8> | ||||||
|  |     telegram.CURRENT_ELECTRICITY_USAGE.value | ||||||
|  |     Out[5]: Decimal('2.027') | ||||||
|  |     telegram.CURRENT_ELECTRICITY_USAGE.unit | ||||||
|  |     Out[6]: 'kW' | ||||||
|  | 
 | ||||||
|  | The telegram object has an iterator, can be used to find all the information elements in the current telegram: | ||||||
|  | 
 | ||||||
|  | .. code-block:: python | ||||||
|  | 
 | ||||||
|  |     [attr for attr, value in telegram] | ||||||
|  |     Out[11]: | ||||||
|  |     ['P1_MESSAGE_HEADER', | ||||||
|  |      'P1_MESSAGE_TIMESTAMP', | ||||||
|  |      'EQUIPMENT_IDENTIFIER', | ||||||
|  |      'ELECTRICITY_USED_TARIFF_1', | ||||||
|  |      'ELECTRICITY_USED_TARIFF_2', | ||||||
|  |      'ELECTRICITY_DELIVERED_TARIFF_1', | ||||||
|  |      'ELECTRICITY_DELIVERED_TARIFF_2', | ||||||
|  |      'ELECTRICITY_ACTIVE_TARIFF', | ||||||
|  |      'CURRENT_ELECTRICITY_USAGE', | ||||||
|  |      'CURRENT_ELECTRICITY_DELIVERY', | ||||||
|  |      'LONG_POWER_FAILURE_COUNT', | ||||||
|  |      'VOLTAGE_SAG_L1_COUNT', | ||||||
|  |      'VOLTAGE_SAG_L2_COUNT', | ||||||
|  |      'VOLTAGE_SAG_L3_COUNT', | ||||||
|  |      'VOLTAGE_SWELL_L1_COUNT', | ||||||
|  |      'VOLTAGE_SWELL_L2_COUNT', | ||||||
|  |      'VOLTAGE_SWELL_L3_COUNT', | ||||||
|  |      'TEXT_MESSAGE_CODE', | ||||||
|  |      'TEXT_MESSAGE', | ||||||
|  |      'DEVICE_TYPE', | ||||||
|  |      'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE', | ||||||
|  |      'INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE', | ||||||
|  |      'INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE', | ||||||
|  |      'INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE', | ||||||
|  |      'INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE', | ||||||
|  |      'INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE', | ||||||
|  |      'EQUIPMENT_IDENTIFIER_GAS', | ||||||
|  |      'HOURLY_GAS_METER_READING'] | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| Installation | Installation | ||||||
| ------------ | ------------ | ||||||
|  | |||||||
							
								
								
									
										122
									
								
								dsmr_parser/clients/filereader.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								dsmr_parser/clients/filereader.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,122 @@ | |||||||
|  | import logging | ||||||
|  | import fileinput | ||||||
|  | 
 | ||||||
|  | from dsmr_parser.clients.telegram_buffer import TelegramBuffer | ||||||
|  | from dsmr_parser.exceptions import ParseError, InvalidChecksumError | ||||||
|  | from dsmr_parser.objects import Telegram | ||||||
|  | from dsmr_parser.parsers import TelegramParser | ||||||
|  | 
 | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  | 
 | ||||||
|  | class FileReader(object): | ||||||
|  |     """ | ||||||
|  |      Filereader to read and parse raw telegram strings from a file and instantiate Telegram objects | ||||||
|  |      for each read telegram. | ||||||
|  |      Usage: | ||||||
|  |         from dsmr_parser import telegram_specifications | ||||||
|  |         from dsmr_parser.clients.filereader import FileReader | ||||||
|  | 
 | ||||||
|  |         if __name__== "__main__": | ||||||
|  | 
 | ||||||
|  |             infile = '/data/smartmeter/readings.txt' | ||||||
|  | 
 | ||||||
|  |             file_reader = FileReader( | ||||||
|  |                 file = infile, | ||||||
|  |                 telegram_specification = telegram_specifications.V4 | ||||||
|  |                 ) | ||||||
|  | 
 | ||||||
|  |             for telegram in file_reader.read_as_object(): | ||||||
|  |                 print(telegram) | ||||||
|  | 
 | ||||||
|  |      The file can be created like: | ||||||
|  |         from dsmr_parser import telegram_specifications | ||||||
|  |         from dsmr_parser.clients import SerialReader, SERIAL_SETTINGS_V5 | ||||||
|  | 
 | ||||||
|  |         if __name__== "__main__": | ||||||
|  | 
 | ||||||
|  |             outfile = '/data/smartmeter/readings.txt' | ||||||
|  | 
 | ||||||
|  |             serial_reader = SerialReader( | ||||||
|  |                 device='/dev/ttyUSB0', | ||||||
|  |                 serial_settings=SERIAL_SETTINGS_V5, | ||||||
|  |                 telegram_specification=telegram_specifications.V4 | ||||||
|  |             ) | ||||||
|  | 
 | ||||||
|  |             for telegram in serial_reader.read_as_object(): | ||||||
|  |                 f=open(outfile,"ab+") | ||||||
|  |                 f.write(telegram._telegram_data.encode()) | ||||||
|  |                 f.close() | ||||||
|  |      """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, file, telegram_specification): | ||||||
|  |         self._file = file | ||||||
|  |         self.telegram_parser = TelegramParser(telegram_specification) | ||||||
|  |         self.telegram_buffer = TelegramBuffer() | ||||||
|  |         self.telegram_specification = telegram_specification | ||||||
|  | 
 | ||||||
|  |     def read_as_object(self): | ||||||
|  |         """ | ||||||
|  |         Read complete DSMR telegram's from a file and return a Telegram object. | ||||||
|  |         :rtype: generator | ||||||
|  |         """ | ||||||
|  |         with open(self._file,"rb") as file_handle: | ||||||
|  |             while True: | ||||||
|  |                 data = file_handle.readline() | ||||||
|  |                 str = data.decode() | ||||||
|  |                 self.telegram_buffer.append(str) | ||||||
|  | 
 | ||||||
|  |                 for telegram in self.telegram_buffer.get_all(): | ||||||
|  |                     try: | ||||||
|  |                         yield Telegram(telegram, self.telegram_parser, self.telegram_specification) | ||||||
|  |                     except InvalidChecksumError as e: | ||||||
|  |                         logger.warning(str(e)) | ||||||
|  |                     except ParseError as e: | ||||||
|  |                         logger.error('Failed to parse telegram: %s', e) | ||||||
|  | 
 | ||||||
|  | class FileInputReader(object): | ||||||
|  |     """ | ||||||
|  |      Filereader to read and parse raw telegram strings from stdin or files specified at the commandline | ||||||
|  |      and instantiate Telegram objects for each read telegram. | ||||||
|  |      Usage python script "syphon_smartmeter_readings_stdin.py": | ||||||
|  |         from dsmr_parser import telegram_specifications | ||||||
|  |         from dsmr_parser.clients.filereader import FileInputReader | ||||||
|  | 
 | ||||||
|  |         if __name__== "__main__": | ||||||
|  | 
 | ||||||
|  |             fileinput_reader = FileReader( | ||||||
|  |                 file = infile, | ||||||
|  |                 telegram_specification = telegram_specifications.V4 | ||||||
|  |                 ) | ||||||
|  | 
 | ||||||
|  |             for telegram in fileinput_reader.read_as_object(): | ||||||
|  |                 print(telegram) | ||||||
|  | 
 | ||||||
|  |     Command line: | ||||||
|  |         tail -f /data/smartmeter/readings.txt | python3 syphon_smartmeter_readings_stdin.py | ||||||
|  | 
 | ||||||
|  |      """ | ||||||
|  | 
 | ||||||
|  |     def __init__(self, telegram_specification): | ||||||
|  |         self.telegram_parser = TelegramParser(telegram_specification) | ||||||
|  |         self.telegram_buffer = TelegramBuffer() | ||||||
|  |         self.telegram_specification = telegram_specification | ||||||
|  | 
 | ||||||
|  |     def read_as_object(self): | ||||||
|  |         """ | ||||||
|  |         Read complete DSMR telegram's from stdin of filearguments specified on teh command line | ||||||
|  |         and return a Telegram object. | ||||||
|  |         :rtype: generator | ||||||
|  |         """ | ||||||
|  |         with fileinput.input(mode='rb') as file_handle: | ||||||
|  |             while True: | ||||||
|  |                 data = file_handle.readline() | ||||||
|  |                 str = data.decode() | ||||||
|  |                 self.telegram_buffer.append(str) | ||||||
|  | 
 | ||||||
|  |                 for telegram in self.telegram_buffer.get_all(): | ||||||
|  |                     try: | ||||||
|  |                         yield Telegram(telegram, self.telegram_parser, self.telegram_specification) | ||||||
|  |                     except InvalidChecksumError as e: | ||||||
|  |                         logger.warning(str(e)) | ||||||
|  |                     except ParseError as e: | ||||||
|  |                         logger.error('Failed to parse telegram: %s', e) | ||||||
| @ -6,6 +6,7 @@ import serial_asyncio | |||||||
| from dsmr_parser.clients.telegram_buffer import TelegramBuffer | from dsmr_parser.clients.telegram_buffer import TelegramBuffer | ||||||
| from dsmr_parser.exceptions import ParseError, InvalidChecksumError | from dsmr_parser.exceptions import ParseError, InvalidChecksumError | ||||||
| from dsmr_parser.parsers import TelegramParser | from dsmr_parser.parsers import TelegramParser | ||||||
|  | from dsmr_parser.objects import Telegram | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
| @ -20,6 +21,7 @@ class SerialReader(object): | |||||||
| 
 | 
 | ||||||
|         self.telegram_parser = TelegramParser(telegram_specification) |         self.telegram_parser = TelegramParser(telegram_specification) | ||||||
|         self.telegram_buffer = TelegramBuffer() |         self.telegram_buffer = TelegramBuffer() | ||||||
|  |         self.telegram_specification = telegram_specification | ||||||
| 
 | 
 | ||||||
|     def read(self): |     def read(self): | ||||||
|         """ |         """ | ||||||
| @ -41,6 +43,25 @@ class SerialReader(object): | |||||||
|                     except ParseError as e: |                     except ParseError as e: | ||||||
|                         logger.error('Failed to parse telegram: %s', e) |                         logger.error('Failed to parse telegram: %s', e) | ||||||
| 
 | 
 | ||||||
|  |     def read_as_object(self): | ||||||
|  |         """ | ||||||
|  |         Read complete DSMR telegram's from the serial interface and return a Telegram object. | ||||||
|  | 
 | ||||||
|  |         :rtype: generator | ||||||
|  |         """ | ||||||
|  |         with serial.Serial(**self.serial_settings) as serial_handle: | ||||||
|  |             while True: | ||||||
|  |                 data = serial_handle.readline() | ||||||
|  |                 self.telegram_buffer.append(data.decode('ascii')) | ||||||
|  | 
 | ||||||
|  |                 for telegram in self.telegram_buffer.get_all(): | ||||||
|  |                     try: | ||||||
|  |                         yield Telegram(telegram, self.telegram_parser, self.telegram_specification) | ||||||
|  |                     except InvalidChecksumError as e: | ||||||
|  |                         logger.warning(str(e)) | ||||||
|  |                     except ParseError as e: | ||||||
|  |                         logger.error('Failed to parse telegram: %s', e) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class AsyncSerialReader(SerialReader): | class AsyncSerialReader(SerialReader): | ||||||
|     """Serial reader using asyncio pyserial.""" |     """Serial reader using asyncio pyserial.""" | ||||||
|  | |||||||
							
								
								
									
										54
									
								
								dsmr_parser/obis_name_mapping.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								dsmr_parser/obis_name_mapping.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | |||||||
|  | from dsmr_parser import obis_references as obis | ||||||
|  | 
 | ||||||
|  | """ | ||||||
|  | dsmr_parser.obis_name_mapping | ||||||
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  | 
 | ||||||
|  | This module contains a mapping of obis references to names. | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | EN = { | ||||||
|  |     obis.P1_MESSAGE_HEADER: 'P1_MESSAGE_HEADER', | ||||||
|  |     obis.P1_MESSAGE_TIMESTAMP: 'P1_MESSAGE_TIMESTAMP', | ||||||
|  |     obis.ELECTRICITY_IMPORTED_TOTAL : 'ELECTRICITY_IMPORTED_TOTAL', | ||||||
|  |     obis.ELECTRICITY_USED_TARIFF_1 : 'ELECTRICITY_USED_TARIFF_1', | ||||||
|  |     obis.ELECTRICITY_USED_TARIFF_2 : 'ELECTRICITY_USED_TARIFF_2', | ||||||
|  |     obis.ELECTRICITY_DELIVERED_TARIFF_1 : 'ELECTRICITY_DELIVERED_TARIFF_1', | ||||||
|  |     obis.ELECTRICITY_DELIVERED_TARIFF_2 : 'ELECTRICITY_DELIVERED_TARIFF_2', | ||||||
|  |     obis.ELECTRICITY_ACTIVE_TARIFF : 'ELECTRICITY_ACTIVE_TARIFF', | ||||||
|  |     obis.EQUIPMENT_IDENTIFIER : 'EQUIPMENT_IDENTIFIER', | ||||||
|  |     obis.CURRENT_ELECTRICITY_USAGE : 'CURRENT_ELECTRICITY_USAGE', | ||||||
|  |     obis.CURRENT_ELECTRICITY_DELIVERY : 'CURRENT_ELECTRICITY_DELIVERY', | ||||||
|  |     obis.LONG_POWER_FAILURE_COUNT : 'LONG_POWER_FAILURE_COUNT', | ||||||
|  |     obis.SHORT_POWER_FAILURE_COUNT : 'SHORT_POWER_FAILURE_COUNT', | ||||||
|  |     obis.POWER_EVENT_FAILURE_LOG : 'POWER_EVENT_FAILURE_LOG', | ||||||
|  |     obis.VOLTAGE_SAG_L1_COUNT : 'VOLTAGE_SAG_L1_COUNT', | ||||||
|  |     obis.VOLTAGE_SAG_L2_COUNT : 'VOLTAGE_SAG_L2_COUNT', | ||||||
|  |     obis.VOLTAGE_SAG_L3_COUNT : 'VOLTAGE_SAG_L3_COUNT', | ||||||
|  |     obis.VOLTAGE_SWELL_L1_COUNT : 'VOLTAGE_SWELL_L1_COUNT', | ||||||
|  |     obis.VOLTAGE_SWELL_L2_COUNT : 'VOLTAGE_SWELL_L2_COUNT', | ||||||
|  |     obis.VOLTAGE_SWELL_L3_COUNT : 'VOLTAGE_SWELL_L3_COUNT', | ||||||
|  |     obis.INSTANTANEOUS_VOLTAGE_L1 : 'INSTANTANEOUS_VOLTAGE_L1', | ||||||
|  |     obis.INSTANTANEOUS_VOLTAGE_L2 : 'INSTANTANEOUS_VOLTAGE_L2', | ||||||
|  |     obis.INSTANTANEOUS_VOLTAGE_L3 : 'INSTANTANEOUS_VOLTAGE_L3', | ||||||
|  |     obis.INSTANTANEOUS_CURRENT_L1 : 'INSTANTANEOUS_CURRENT_L1', | ||||||
|  |     obis.INSTANTANEOUS_CURRENT_L2 : 'INSTANTANEOUS_CURRENT_L2', | ||||||
|  |     obis.INSTANTANEOUS_CURRENT_L3 : 'INSTANTANEOUS_CURRENT_L3', | ||||||
|  |     obis.TEXT_MESSAGE_CODE : 'TEXT_MESSAGE_CODE', | ||||||
|  |     obis.TEXT_MESSAGE : 'TEXT_MESSAGE', | ||||||
|  |     obis.DEVICE_TYPE : 'DEVICE_TYPE', | ||||||
|  |     obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE : 'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE', | ||||||
|  |     obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE : 'INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE', | ||||||
|  |     obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE : 'INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE', | ||||||
|  |     obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE : 'INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE', | ||||||
|  |     obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE : 'INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE', | ||||||
|  |     obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE : 'INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE', | ||||||
|  |     obis.EQUIPMENT_IDENTIFIER_GAS : 'EQUIPMENT_IDENTIFIER_GAS', | ||||||
|  |     obis.HOURLY_GAS_METER_READING : 'HOURLY_GAS_METER_READING', | ||||||
|  |     obis.GAS_METER_READING : 'GAS_METER_READING', | ||||||
|  |     obis.ACTUAL_TRESHOLD_ELECTRICITY : 'ACTUAL_TRESHOLD_ELECTRICITY', | ||||||
|  |     obis.ACTUAL_SWITCH_POSITION : 'ACTUAL_SWITCH_POSITION', | ||||||
|  |     obis.VALVE_POSITION_GAS : 'VALVE_POSITION_GAS' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | REVERSE_EN = dict([ (v,k) for k,v in EN.items()]) | ||||||
| @ -1,3 +1,56 @@ | |||||||
|  | import dsmr_parser.obis_name_mapping | ||||||
|  | 
 | ||||||
|  | class Telegram(object): | ||||||
|  |     """ | ||||||
|  |     Container for raw and parsed telegram data. | ||||||
|  |     Initializing: | ||||||
|  |         from dsmr_parser import telegram_specifications | ||||||
|  |         from dsmr_parser.exceptions import InvalidChecksumError, ParseError | ||||||
|  |         from dsmr_parser.objects import CosemObject, MBusObject, Telegram | ||||||
|  |         from dsmr_parser.parsers import TelegramParser | ||||||
|  |         from test.example_telegrams import TELEGRAM_V4_2 | ||||||
|  |         parser = TelegramParser(telegram_specifications.V4) | ||||||
|  |         telegram = Telegram(TELEGRAM_V4_2, parser, telegram_specifications.V4) | ||||||
|  | 
 | ||||||
|  |     Attributes can be accessed on a telegram object by addressing by their english name, for example: | ||||||
|  |         telegram.ELECTRICITY_USED_TARIFF_1 | ||||||
|  | 
 | ||||||
|  |     All attributes in a telegram can be iterated over, for example: | ||||||
|  |         [k for k,v in telegram] | ||||||
|  |     yields: | ||||||
|  |     ['P1_MESSAGE_HEADER',  'P1_MESSAGE_TIMESTAMP', 'EQUIPMENT_IDENTIFIER', ...] | ||||||
|  |     """ | ||||||
|  |     def __init__(self, telegram_data, telegram_parser, telegram_specification): | ||||||
|  |         self._telegram_data = telegram_data | ||||||
|  |         self._telegram_specification = telegram_specification | ||||||
|  |         self._telegram_parser = telegram_parser | ||||||
|  |         self._obis_name_mapping = dsmr_parser.obis_name_mapping.EN | ||||||
|  |         self._reverse_obis_name_mapping = dsmr_parser.obis_name_mapping.REVERSE_EN | ||||||
|  |         self._dictionary = self._telegram_parser.parse(telegram_data) | ||||||
|  |         self._item_names = self._get_item_names() | ||||||
|  | 
 | ||||||
|  |     def __getattr__(self, name): | ||||||
|  |         ''' will only get called for undefined attributes ''' | ||||||
|  |         obis_reference = self._reverse_obis_name_mapping[name] | ||||||
|  |         value = self._dictionary[obis_reference] | ||||||
|  |         setattr(self, name, value) | ||||||
|  |         return value | ||||||
|  | 
 | ||||||
|  |     def _get_item_names(self): | ||||||
|  |         return [self._obis_name_mapping[k] for k, v in self._dictionary.items()] | ||||||
|  | 
 | ||||||
|  |     def __iter__(self): | ||||||
|  |         for attr in self._item_names: | ||||||
|  |             value = getattr(self, attr) | ||||||
|  |             yield attr, value | ||||||
|  | 
 | ||||||
|  |     def __str__(self): | ||||||
|  |         output = "" | ||||||
|  |         for attr, value in self: | ||||||
|  |             output += "{}: \t {} \t[{}]\n".format(attr,str(value.value),str(value.unit)) | ||||||
|  |         return output | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class DSMRObject(object): | class DSMRObject(object): | ||||||
|     """ |     """ | ||||||
|     Represents all data from a single telegram line. |     Represents all data from a single telegram line. | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ import re | |||||||
| 
 | 
 | ||||||
| from PyCRC.CRC16 import CRC16 | from PyCRC.CRC16 import CRC16 | ||||||
| 
 | 
 | ||||||
| from dsmr_parser.objects import MBusObject, CosemObject | from dsmr_parser.objects import MBusObject, CosemObject, Telegram | ||||||
| from dsmr_parser.exceptions import ParseError, InvalidChecksumError | from dsmr_parser.exceptions import ParseError, InvalidChecksumError | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							| @ -6,7 +6,7 @@ setup( | |||||||
|     author='Nigel Dokter', |     author='Nigel Dokter', | ||||||
|     author_email='nigel@nldr.net', |     author_email='nigel@nldr.net', | ||||||
|     url='https://github.com/ndokter/dsmr_parser', |     url='https://github.com/ndokter/dsmr_parser', | ||||||
|     version='0.16', |     version='0.17', | ||||||
|     packages=find_packages(), |     packages=find_packages(), | ||||||
|     install_requires=[ |     install_requires=[ | ||||||
|         'pyserial>=3,<4', |         'pyserial>=3,<4', | ||||||
|  | |||||||
							
								
								
									
										14
									
								
								test/experiment_telegram.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								test/experiment_telegram.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | from decimal import Decimal | ||||||
|  | import datetime | ||||||
|  | import unittest | ||||||
|  | import pytz | ||||||
|  | from dsmr_parser import obis_references as obis | ||||||
|  | from dsmr_parser import telegram_specifications | ||||||
|  | from dsmr_parser.exceptions import InvalidChecksumError, ParseError | ||||||
|  | from dsmr_parser.objects import CosemObject, MBusObject, Telegram | ||||||
|  | from dsmr_parser.parsers import TelegramParser | ||||||
|  | from example_telegrams import TELEGRAM_V4_2 | ||||||
|  | parser = TelegramParser(telegram_specifications.V4) | ||||||
|  | telegram = Telegram(TELEGRAM_V4_2, parser, telegram_specifications.V4) | ||||||
|  | 
 | ||||||
|  | print(telegram) | ||||||
							
								
								
									
										30
									
								
								test/test_telegram.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								test/test_telegram.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | from decimal import Decimal | ||||||
|  | 
 | ||||||
|  | import datetime | ||||||
|  | import unittest | ||||||
|  | 
 | ||||||
|  | import pytz | ||||||
|  | 
 | ||||||
|  | from dsmr_parser import obis_references as obis | ||||||
|  | from dsmr_parser import telegram_specifications | ||||||
|  | from dsmr_parser.exceptions import InvalidChecksumError, ParseError | ||||||
|  | from dsmr_parser.objects import CosemObject, MBusObject, Telegram | ||||||
|  | from dsmr_parser.parsers import TelegramParser | ||||||
|  | from test.example_telegrams import TELEGRAM_V4_2 | ||||||
|  | 
 | ||||||
|  | class TelegramTest(unittest.TestCase): | ||||||
|  |     """ Test instantiation of Telegram object """ | ||||||
|  | 
 | ||||||
|  |     def test_instantiate(self): | ||||||
|  |         parser = TelegramParser(telegram_specifications.V4) | ||||||
|  |         #result = parser.parse(TELEGRAM_V4_2) | ||||||
|  |         telegram = Telegram(TELEGRAM_V4_2, parser, telegram_specifications.V4) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         # P1_MESSAGE_HEADER (1-3:0.2.8) | ||||||
|  |         #assert isinstance(result[obis.P1_MESSAGE_HEADER], CosemObject) | ||||||
|  |         #assert result[obis.P1_MESSAGE_HEADER].unit is None | ||||||
|  |         #assert isinstance(result[obis.P1_MESSAGE_HEADER].value, str) | ||||||
|  |         #assert result[obis.P1_MESSAGE_HEADER].value == '50' | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user