issue-51-telegram work in progress
This commit is contained in:
		
							parent
							
								
									516850481d
								
							
						
					
					
						commit
						ad25fd4182
					
				| @ -23,12 +23,17 @@ class Telegram(object): | |||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self._telegram_data = defaultdict(list) |         self._telegram_data = defaultdict(list) | ||||||
|         self._mbus_channel_devices = {} |         self._mbus_channel_devices = {} | ||||||
|  |         self._item_names = [] | ||||||
| 
 | 
 | ||||||
|     def add(self, obis_reference, dsmr_object): |     def add(self, obis_reference, dsmr_object): | ||||||
|         self._telegram_data[obis_reference].append(dsmr_object) |         self._telegram_data[obis_reference].append(dsmr_object) | ||||||
| 
 | 
 | ||||||
|         # Update name mapping used to get value by attribute. Example: telegram.P1_MESSAGE_HEADER |         # Update name mapping used to get value by attribute. Example: telegram.P1_MESSAGE_HEADER | ||||||
|         setattr(self, obis_name_mapping.EN[obis_reference], dsmr_object) |         # Also keep track of the added names internally | ||||||
|  |         obis_name = obis_name_mapping.EN[obis_reference] | ||||||
|  |         setattr(self, obis_name, dsmr_object) | ||||||
|  |         if obis_name not in self._item_names:  # TODO solve issue with repeating obis references | ||||||
|  |             self._item_names.append(obis_name) | ||||||
| 
 | 
 | ||||||
|         # Group Mbus related values into a MbusDevice object. |         # Group Mbus related values into a MbusDevice object. | ||||||
|         # TODO MaxDemandParser (BELGIUM_MAXIMUM_DEMAND_13_MONTHS) returns a list |         # TODO MaxDemandParser (BELGIUM_MAXIMUM_DEMAND_13_MONTHS) returns a list | ||||||
| @ -63,26 +68,26 @@ class Telegram(object): | |||||||
| 
 | 
 | ||||||
|     def __getitem__(self, obis_reference): |     def __getitem__(self, obis_reference): | ||||||
|         """ |         """ | ||||||
|         Get value by key. Example: telegram[obis_references.P1_MESSAGE_HEADER] |         Deprecated method to get obis_reference by key. Exists for backwards compatibility | ||||||
| 
 | 
 | ||||||
|         For Mbus devices like gas and water meters, it's better to use get_mbus_devices and get_mbus_device_by_channel. |         Example: telegram[obis_references.P1_MESSAGE_HEADER] | ||||||
|         This key approach will only fetch the first found value and therefor might not be accurate. |  | ||||||
|         """ |         """ | ||||||
|         try: |         try: | ||||||
|  |             # TODO use _telegram_data here or else TelegramParserFluviusTest.test_parse breaks | ||||||
|             return self._telegram_data[obis_reference][0] |             return self._telegram_data[obis_reference][0] | ||||||
|  |             # obis_name = obis_name_mapping.EN[obis_reference] | ||||||
|  |             # return getattr(self, obis_name) | ||||||
|         except IndexError: |         except IndexError: | ||||||
|             # The index error is an internal detail. The KeyError is expected as a user. |             # The index error is an internal detail. The KeyError is expected as a user. | ||||||
|             raise KeyError |             raise KeyError | ||||||
| 
 | 
 | ||||||
|     def __len__(self): |     def __len__(self): | ||||||
|         return len(self._telegram_data) |         return len(self._item_names) | ||||||
| 
 | 
 | ||||||
|     def __iter__(self): |     def __iter__(self): | ||||||
|         for obis_reference, values in self._telegram_data.items(): |         for attr in self._item_names: | ||||||
|             reverse_obis_name = obis_name_mapping.EN[obis_reference] |             value = getattr(self, attr) | ||||||
|             value = values[0]  # TODO might be considered legacy behavior? |             yield attr, value | ||||||
| 
 |  | ||||||
|             yield reverse_obis_name, value |  | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         output = "" |         output = "" | ||||||
| @ -91,7 +96,13 @@ class Telegram(object): | |||||||
|         return output |         return output | ||||||
| 
 | 
 | ||||||
|     def to_json(self): |     def to_json(self): | ||||||
|         return json.dumps(dict([[attr, json.loads(value.to_json())] for attr, value in self])) |         telegram_data = {obis_name: json.loads(value.to_json()) for obis_name, value in self} | ||||||
|  |         telegram_data['MBUS_DEVICES'] = [ | ||||||
|  |             json.loads(mbus_device.to_json()) | ||||||
|  |             for mbus_device in self._mbus_channel_devices.values() | ||||||
|  |         ] | ||||||
|  | 
 | ||||||
|  |         return json.dumps(telegram_data) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class DSMRObject(object): | class DSMRObject(object): | ||||||
| @ -319,10 +330,31 @@ class MbusDevice: | |||||||
| 
 | 
 | ||||||
|     def __init__(self, channel_id): |     def __init__(self, channel_id): | ||||||
|         self.channel_id = channel_id |         self.channel_id = channel_id | ||||||
|         self._telegram_data = {} |         self._item_names = [] | ||||||
| 
 | 
 | ||||||
|     def add(self, obis_reference, dsmr_object): |     def add(self, obis_reference, dsmr_object): | ||||||
|         self._telegram_data[obis_reference] = dsmr_object |         # Update name mapping used to get value by attribute. Example: telegram.P1_MESSAGE_HEADER | ||||||
|  |         # Also keep track of the added names internally | ||||||
|  |         obis_name = obis_name_mapping.EN[obis_reference] | ||||||
|  |         setattr(self, obis_name, dsmr_object) | ||||||
|  |         self._item_names.append(obis_name) | ||||||
| 
 | 
 | ||||||
|         # Update name mapping used to get value by attribute. Example: device.HOURLY_GAS_METER_READING |     def __len__(self): | ||||||
|         setattr(self, obis_name_mapping.EN[obis_reference], dsmr_object) |         return len(self._item_names) | ||||||
|  | 
 | ||||||
|  |     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 {}\n".format(attr, str(value)) | ||||||
|  |         return output | ||||||
|  | 
 | ||||||
|  |     def to_json(self): | ||||||
|  |         data = {obis_name: json.loads(value.to_json()) for obis_name, value in self} | ||||||
|  |         data['CHANNEL_ID'] = self.channel_id | ||||||
|  | 
 | ||||||
|  |         return json.dumps(data) | ||||||
|  | |||||||
							
								
								
									
										0
									
								
								test/objects/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								test/objects/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										50
									
								
								test/objects/test_mbusdevice.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								test/objects/test_mbusdevice.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | |||||||
|  | from decimal import Decimal | ||||||
|  | 
 | ||||||
|  | import json | ||||||
|  | import unittest | ||||||
|  | 
 | ||||||
|  | from dsmr_parser import telegram_specifications, obis_references | ||||||
|  | from dsmr_parser.objects import MbusDevice | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class MbusDeviceTest(unittest.TestCase): | ||||||
|  | 
 | ||||||
|  |     def setUp(self): | ||||||
|  |         v5_objects = telegram_specifications.V5['objects'] | ||||||
|  | 
 | ||||||
|  |         device_type_parser = v5_objects[obis_references.DEVICE_TYPE] | ||||||
|  |         device_type = device_type_parser.parse('0-2:24.1.0(003)\r\n') | ||||||
|  | 
 | ||||||
|  |         equipment_parser = v5_objects[obis_references.EQUIPMENT_IDENTIFIER_GAS] | ||||||
|  |         equipment = equipment_parser.parse('0-2:96.1.0(4730303339303031393336393930363139)\r\n') | ||||||
|  | 
 | ||||||
|  |         gas_reading_parser = v5_objects[obis_references.HOURLY_GAS_METER_READING] | ||||||
|  |         gas_reading = gas_reading_parser.parse('0-2:24.2.1(200426223001S)(00246.138*m3)\r\n') | ||||||
|  | 
 | ||||||
|  |         mbus_device = MbusDevice(channel_id=1) | ||||||
|  |         mbus_device.add(obis_references.DEVICE_TYPE, device_type) | ||||||
|  |         mbus_device.add(obis_references.EQUIPMENT_IDENTIFIER_GAS, equipment) | ||||||
|  |         mbus_device.add(obis_references.HOURLY_GAS_METER_READING, gas_reading) | ||||||
|  | 
 | ||||||
|  |         self.mbus_device = mbus_device | ||||||
|  | 
 | ||||||
|  |     def test_attributes(self): | ||||||
|  |         self.assertEqual(self.mbus_device.DEVICE_TYPE.value, 3) | ||||||
|  |         self.assertEqual(self.mbus_device.DEVICE_TYPE.unit, None) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(self.mbus_device.EQUIPMENT_IDENTIFIER_GAS.value, | ||||||
|  |                          '4730303339303031393336393930363139') | ||||||
|  |         self.assertEqual(self.mbus_device.EQUIPMENT_IDENTIFIER_GAS.unit, None) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(self.mbus_device.HOURLY_GAS_METER_READING.value, Decimal('246.138')) | ||||||
|  |         self.assertEqual(self.mbus_device.HOURLY_GAS_METER_READING.unit, 'm3') | ||||||
|  | 
 | ||||||
|  |     def test_to_json(self): | ||||||
|  |         self.assertEqual( | ||||||
|  |             json.loads(self.mbus_device.to_json()), | ||||||
|  |             { | ||||||
|  |                 'CHANNEL_ID': 1, | ||||||
|  |                 'DEVICE_TYPE': {'value': 3, 'unit': None}, | ||||||
|  |                 'EQUIPMENT_IDENTIFIER_GAS': {'value': '4730303339303031393336393930363139', 'unit': None}, | ||||||
|  |                 'HOURLY_GAS_METER_READING': {'datetime': '2020-04-26T22:30:01+02:00', 'value': 246.138, 'unit': 'm3'}} | ||||||
|  |         ) | ||||||
| @ -1,3 +1,4 @@ | |||||||
|  | import json | ||||||
| import unittest | import unittest | ||||||
| import datetime | import datetime | ||||||
| import pytz | import pytz | ||||||
| @ -324,17 +325,17 @@ class TelegramTest(unittest.TestCase): | |||||||
|         parser = TelegramParser(telegram_specifications.V5) |         parser = TelegramParser(telegram_specifications.V5) | ||||||
|         telegram = parser.parse(TELEGRAM_V5_TWO_MBUS) |         telegram = parser.parse(TELEGRAM_V5_TWO_MBUS) | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(len(telegram), 35) |         self.assertEqual(len(telegram._item_names), 35) | ||||||
| 
 | 
 | ||||||
|     def test_iter(self): |     def test_iter(self): | ||||||
|         parser = TelegramParser(telegram_specifications.V5) |         parser = TelegramParser(telegram_specifications.V5) | ||||||
|         telegram = parser.parse(TELEGRAM_V5) |         telegram = parser.parse(TELEGRAM_V5) | ||||||
| 
 | 
 | ||||||
|         for obis_reference, dsmr_object in telegram: |         for obis_name, dsmr_object in telegram: | ||||||
|             break |             break | ||||||
| 
 | 
 | ||||||
|         # Verify that the iterator works for at least one value |         # Verify that the iterator works for at least one value | ||||||
|         self.assertEqual(obis_reference, obis_name_mapping.EN[obis_references.P1_MESSAGE_HEADER]) |         self.assertEqual(obis_name, obis_name_mapping.EN[obis_references.P1_MESSAGE_HEADER]) | ||||||
|         self.assertEqual(dsmr_object.value, '50') |         self.assertEqual(dsmr_object.value, '50') | ||||||
| 
 | 
 | ||||||
|     def test_get_mbus_devices(self): |     def test_get_mbus_devices(self): | ||||||
| @ -378,3 +379,68 @@ class TelegramTest(unittest.TestCase): | |||||||
|         # Because of a bug related to incorrect use of defaultdict, |         # Because of a bug related to incorrect use of defaultdict, | ||||||
|         # test again for unwanted side effects |         # test again for unwanted side effects | ||||||
|         self.assertEqual(telegram.get_mbus_devices(), []) |         self.assertEqual(telegram.get_mbus_devices(), []) | ||||||
|  | 
 | ||||||
|  |     def test_to_json(self): | ||||||
|  |         parser = TelegramParser(telegram_specifications.V5) | ||||||
|  |         telegram = parser.parse(TELEGRAM_V5) | ||||||
|  |         json_data = json.loads(telegram.to_json()) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual( | ||||||
|  |             json_data, | ||||||
|  |             {'CURRENT_ELECTRICITY_DELIVERY': {'unit': 'kW', 'value': 0.0}, | ||||||
|  |              'CURRENT_ELECTRICITY_USAGE': {'unit': 'kW', 'value': 0.244}, | ||||||
|  |              'DEVICE_TYPE': {'unit': None, 'value': 3}, | ||||||
|  |              'ELECTRICITY_ACTIVE_TARIFF': {'unit': None, 'value': '0002'}, | ||||||
|  |              'ELECTRICITY_DELIVERED_TARIFF_1': {'unit': 'kWh', 'value': 2.444}, | ||||||
|  |              'ELECTRICITY_DELIVERED_TARIFF_2': {'unit': 'kWh', 'value': 0.0}, | ||||||
|  |              'ELECTRICITY_USED_TARIFF_1': {'unit': 'kWh', 'value': 4.426}, | ||||||
|  |              'ELECTRICITY_USED_TARIFF_2': {'unit': 'kWh', 'value': 2.399}, | ||||||
|  |              'EQUIPMENT_IDENTIFIER': {'unit': None, | ||||||
|  |                                       'value': '4B384547303034303436333935353037'}, | ||||||
|  |              'EQUIPMENT_IDENTIFIER_GAS': {'unit': None, 'value': None}, | ||||||
|  |              'HOURLY_GAS_METER_READING': {'datetime': '2017-01-02T16:10:05+01:00', | ||||||
|  |                                           'unit': 'm3', | ||||||
|  |                                           'value': 0.107}, | ||||||
|  |              'INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE': {'unit': 'kW', 'value': 0.0}, | ||||||
|  |              'INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE': {'unit': 'kW', 'value': 0.07}, | ||||||
|  |              'INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE': {'unit': 'kW', 'value': 0.0}, | ||||||
|  |              'INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE': {'unit': 'kW', 'value': 0.032}, | ||||||
|  |              'INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE': {'unit': 'kW', 'value': 0.0}, | ||||||
|  |              'INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE': {'unit': 'kW', 'value': 0.142}, | ||||||
|  |              'INSTANTANEOUS_CURRENT_L1': {'unit': 'A', 'value': 0.48}, | ||||||
|  |              'INSTANTANEOUS_CURRENT_L2': {'unit': 'A', 'value': 0.44}, | ||||||
|  |              'INSTANTANEOUS_CURRENT_L3': {'unit': 'A', 'value': 0.86}, | ||||||
|  |              'INSTANTANEOUS_VOLTAGE_L1': {'unit': 'V', 'value': 230.0}, | ||||||
|  |              'INSTANTANEOUS_VOLTAGE_L2': {'unit': 'V', 'value': 230.0}, | ||||||
|  |              'INSTANTANEOUS_VOLTAGE_L3': {'unit': 'V', 'value': 229.0}, | ||||||
|  |              'LONG_POWER_FAILURE_COUNT': {'unit': None, 'value': 0}, | ||||||
|  |              'MBUS_DEVICES': [{'CHANNEL_ID': 1, | ||||||
|  |                                'DEVICE_TYPE': {'unit': None, 'value': 3}, | ||||||
|  |                                'EQUIPMENT_IDENTIFIER_GAS': {'unit': None, | ||||||
|  |                                                             'value': '3232323241424344313233343536373839'}, | ||||||
|  |                                'HOURLY_GAS_METER_READING': {'datetime': '2017-01-02T16:10:05+01:00', | ||||||
|  |                                                             'unit': 'm3', | ||||||
|  |                                                             'value': 0.107}}, | ||||||
|  |                               {'CHANNEL_ID': 2, | ||||||
|  |                                'DEVICE_TYPE': {'unit': None, 'value': 3}, | ||||||
|  |                                'EQUIPMENT_IDENTIFIER_GAS': {'unit': None, 'value': None}}], | ||||||
|  |              'P1_MESSAGE_HEADER': {'unit': None, 'value': '50'}, | ||||||
|  |              'P1_MESSAGE_TIMESTAMP': {'unit': None, 'value': '2017-01-02T19:20:02+01:00'}, | ||||||
|  |              'POWER_EVENT_FAILURE_LOG': {'buffer': [], | ||||||
|  |                                          'buffer_length': 0, | ||||||
|  |                                          'buffer_type': '0-0:96.7.19'}, | ||||||
|  |              'SHORT_POWER_FAILURE_COUNT': {'unit': None, 'value': 13}, | ||||||
|  |              'TEXT_MESSAGE': {'unit': None, 'value': None}, | ||||||
|  |              'VOLTAGE_SAG_L1_COUNT': {'unit': None, 'value': 0}, | ||||||
|  |              'VOLTAGE_SAG_L2_COUNT': {'unit': None, 'value': 0}, | ||||||
|  |              'VOLTAGE_SAG_L3_COUNT': {'unit': None, 'value': 0}, | ||||||
|  |              'VOLTAGE_SWELL_L1_COUNT': {'unit': None, 'value': 0}, | ||||||
|  |              'VOLTAGE_SWELL_L2_COUNT': {'unit': None, 'value': 0}, | ||||||
|  |              'VOLTAGE_SWELL_L3_COUNT': {'unit': None, 'value': 0}} | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def test_getitem(self): | ||||||
|  |         parser = TelegramParser(telegram_specifications.V5) | ||||||
|  |         telegram = parser.parse(TELEGRAM_V5) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(telegram[obis_references.P1_MESSAGE_HEADER].value, '50') | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user