commit
						d0cc429eda
					
				
							
								
								
									
										8
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							| @ -12,15 +12,15 @@ jobs: | |||||||
|     strategy: |     strategy: | ||||||
|       matrix: |       matrix: | ||||||
|         python-version: |         python-version: | ||||||
|           - '3.6' |  | ||||||
|           - '3.7' |           - '3.7' | ||||||
|           - '3.8' |           - '3.8' | ||||||
|           - '3.9' |           - '3.9' | ||||||
|           - '3.10' |           - '3.10' | ||||||
|  |           - '3.11' | ||||||
| 
 | 
 | ||||||
|     name: Python ${{ matrix.python-version }} |     name: Python ${{ matrix.python-version }} | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v2 |       - uses: actions/checkout@v3 | ||||||
| 
 | 
 | ||||||
|       - name: Setup Python ${{ matrix.python-version }} |       - name: Setup Python ${{ matrix.python-version }} | ||||||
|         uses: actions/setup-python@v2 |         uses: actions/setup-python@v2 | ||||||
| @ -28,7 +28,7 @@ jobs: | |||||||
|           python-version: ${{ matrix.python-version }} |           python-version: ${{ matrix.python-version }} | ||||||
| 
 | 
 | ||||||
|       - name: Cached PIP dependencies |       - name: Cached PIP dependencies | ||||||
|         uses: actions/cache@v2 |         uses: actions/cache@v3 | ||||||
|         with: |         with: | ||||||
|           path: | |           path: | | ||||||
|             ~/.cache/pip |             ~/.cache/pip | ||||||
| @ -43,4 +43,4 @@ jobs: | |||||||
|         run: tox |         run: tox | ||||||
| 
 | 
 | ||||||
|       - name: Code coverage upload |       - name: Code coverage upload | ||||||
|         uses: codecov/codecov-action@v1 |         uses: codecov/codecov-action@v3 | ||||||
|  | |||||||
| @ -50,9 +50,29 @@ EN = { | |||||||
|     obis.ACTUAL_TRESHOLD_ELECTRICITY: 'ACTUAL_TRESHOLD_ELECTRICITY', |     obis.ACTUAL_TRESHOLD_ELECTRICITY: 'ACTUAL_TRESHOLD_ELECTRICITY', | ||||||
|     obis.ACTUAL_SWITCH_POSITION: 'ACTUAL_SWITCH_POSITION', |     obis.ACTUAL_SWITCH_POSITION: 'ACTUAL_SWITCH_POSITION', | ||||||
|     obis.VALVE_POSITION_GAS: 'VALVE_POSITION_GAS', |     obis.VALVE_POSITION_GAS: 'VALVE_POSITION_GAS', | ||||||
|     obis.BELGIUM_5MIN_GAS_METER_READING: 'BELGIUM_5MIN_GAS_METER_READING', |     obis.BELGIUM_EQUIPMENT_IDENTIFIER: 'BELGIUM_EQUIPMENT_IDENTIFIER', | ||||||
|  |     obis.BELGIUM_CURRENT_AVERAGE_DEMAND: 'BELGIUM_CURRENT_AVERAGE_DEMAND', | ||||||
|  |     obis.BELGIUM_MAXIMUM_DEMAND_MONTH: 'BELGIUM_MAXIMUM_DEMAND_MONTH', | ||||||
|  |     obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS: 'BELGIUM_MAXIMUM_DEMAND_13_MONTHS', | ||||||
|     obis.BELGIUM_MAX_POWER_PER_PHASE: 'BELGIUM_MAX_POWER_PER_PHASE', |     obis.BELGIUM_MAX_POWER_PER_PHASE: 'BELGIUM_MAX_POWER_PER_PHASE', | ||||||
|     obis.BELGIUM_MAX_CURRENT_PER_PHASE: 'BELGIUM_MAX_CURRENT_PER_PHASE', |     obis.BELGIUM_MAX_CURRENT_PER_PHASE: 'BELGIUM_MAX_CURRENT_PER_PHASE', | ||||||
|  |     obis.BELGIUM_MBUS1_DEVICE_TYPE: 'BELGIUM_MBUS1_DEVICE_TYPE', | ||||||
|  |     obis.BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER: 'BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER', | ||||||
|  |     obis.BELGIUM_MBUS1_VALVE_POSITION: 'BELGIUM_MBUS1_VALVE_POSITION', | ||||||
|  |     obis.BELGIUM_MBUS1_METER_READING1: 'BELGIUM_MBUS1_METER_READING1', | ||||||
|  |     obis.BELGIUM_MBUS1_METER_READING2: 'BELGIUM_MBUS1_METER_READING2', | ||||||
|  |     obis.BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER: 'BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER', | ||||||
|  |     obis.BELGIUM_MBUS2_VALVE_POSITION: 'BELGIUM_MBUS2_VALVE_POSITION', | ||||||
|  |     obis.BELGIUM_MBUS2_METER_READING1: 'BELGIUM_MBUS2_METER_READING1', | ||||||
|  |     obis.BELGIUM_MBUS2_METER_READING2: 'BELGIUM_MBUS2_METER_READING2', | ||||||
|  |     obis.BELGIUM_MBUS3_EQUIPMENT_IDENTIFIER: 'BELGIUM_MBUS3_EQUIPMENT_IDENTIFIER', | ||||||
|  |     obis.BELGIUM_MBUS3_VALVE_POSITION: 'BELGIUM_MBUS3_VALVE_POSITION', | ||||||
|  |     obis.BELGIUM_MBUS3_METER_READING1: 'BELGIUM_MBUS3_METER_READING1', | ||||||
|  |     obis.BELGIUM_MBUS3_METER_READING2: 'BELGIUM_MBUS3_METER_READING2', | ||||||
|  |     obis.BELGIUM_MBUS4_EQUIPMENT_IDENTIFIER: 'BELGIUM_MBUS4_EQUIPMENT_IDENTIFIER', | ||||||
|  |     obis.BELGIUM_MBUS4_VALVE_POSITION: 'BELGIUM_MBUS4_VALVE_POSITION', | ||||||
|  |     obis.BELGIUM_MBUS4_METER_READING1: 'BELGIUM_MBUS4_METER_READING1', | ||||||
|  |     obis.BELGIUM_MBUS4_METER_READING2: 'BELGIUM_MBUS4_METER_READING2', | ||||||
|     obis.LUXEMBOURG_EQUIPMENT_IDENTIFIER: 'LUXEMBOURG_EQUIPMENT_IDENTIFIER', |     obis.LUXEMBOURG_EQUIPMENT_IDENTIFIER: 'LUXEMBOURG_EQUIPMENT_IDENTIFIER', | ||||||
|     obis.Q3D_EQUIPMENT_IDENTIFIER: 'Q3D_EQUIPMENT_IDENTIFIER', |     obis.Q3D_EQUIPMENT_IDENTIFIER: 'Q3D_EQUIPMENT_IDENTIFIER', | ||||||
|     obis.Q3D_EQUIPMENT_STATE: 'Q3D_EQUIPMENT_STATE', |     obis.Q3D_EQUIPMENT_STATE: 'Q3D_EQUIPMENT_STATE', | ||||||
|  | |||||||
| @ -73,10 +73,46 @@ ELECTRICITY_IMPORTED_TOTAL = r'\d-\d:1\.8\.0.+?\r\n'  # Total imported energy re | |||||||
| ELECTRICITY_EXPORTED_TOTAL = r'\d-\d:2\.8\.0.+?\r\n'  # Total exported energy register (P-) | ELECTRICITY_EXPORTED_TOTAL = r'\d-\d:2\.8\.0.+?\r\n'  # Total exported energy register (P-) | ||||||
| 
 | 
 | ||||||
| # International non generalized additions (country specific) / risk for necessary refactoring | # International non generalized additions (country specific) / risk for necessary refactoring | ||||||
| BELGIUM_5MIN_GAS_METER_READING = r'\d-\d:24\.2\.3.+?\r\n'  # Different code, same format. | BELGIUM_VERSION_INFORMATION = r'\d-\d:96\.1\.4.+?\r\n' | ||||||
|  | BELGIUM_EQUIPMENT_IDENTIFIER = r'\d-0:96\.1\.1.+?\r\n' | ||||||
|  | BELGIUM_CURRENT_AVERAGE_DEMAND = r'\d-\d:1\.4\.0.+?\r\n' | ||||||
|  | BELGIUM_MAXIMUM_DEMAND_MONTH = r'\d-\d:1\.6\.0.+?\r\n' | ||||||
|  | BELGIUM_MAXIMUM_DEMAND_13_MONTHS = r'\d-\d:98\.1\.0.+?\r\n' | ||||||
| BELGIUM_MAX_POWER_PER_PHASE = r'\d-\d:17\.0\.0.+?\r\n'  # Applicable when power limitation is active | BELGIUM_MAX_POWER_PER_PHASE = r'\d-\d:17\.0\.0.+?\r\n'  # Applicable when power limitation is active | ||||||
| BELGIUM_MAX_CURRENT_PER_PHASE = r'\d-\d:31\.4\.0.+?\r\n'  # Applicable when current limitation is active | BELGIUM_MAX_CURRENT_PER_PHASE = r'\d-\d:31\.4\.0.+?\r\n'  # Applicable when current limitation is active | ||||||
|  | 
 | ||||||
|  | # Multiple 'slaves' can be linked to the main device. | ||||||
|  | # Mostly MBUS1 = GAS METER with values on 24.2.3 | ||||||
|  | # While WATER METER reports it's values on 24.2.1 | ||||||
|  | # The GAS METER also reports its valve state on 24.4.0 | ||||||
|  | # Dev type for gas = 7 and water = 8 | ||||||
|  | BELGIUM_MBUS1_DEVICE_TYPE = r'\d-1:24\.1\.0.+?\r\n' | ||||||
|  | BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER = r'\d-1:96\.1\.1.+?\r\n' | ||||||
|  | BELGIUM_MBUS1_VALVE_POSITION = r'\d-1:24\.4\.0.+?\r\n' | ||||||
|  | BELGIUM_MBUS1_METER_READING1 = r'\d-1:24\.2\.1.+?\r\n' | ||||||
|  | BELGIUM_MBUS1_METER_READING2 = r'\d-1:24\.2\.3.+?\r\n' | ||||||
|  | 
 | ||||||
|  | BELGIUM_MBUS2_DEVICE_TYPE = r'\d-2:24\.1\.0.+?\r\n' | ||||||
|  | BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER = r'\d-2:96\.1\.1.+?\r\n' | ||||||
|  | BELGIUM_MBUS2_VALVE_POSITION = r'\d-2:24\.4\.0.+?\r\n' | ||||||
|  | BELGIUM_MBUS2_METER_READING1 = r'\d-2:24\.2\.1.+?\r\n' | ||||||
|  | BELGIUM_MBUS2_METER_READING2 = r'\d-2:24\.2\.3.+?\r\n' | ||||||
|  | 
 | ||||||
|  | BELGIUM_MBUS3_DEVICE_TYPE = r'\d-3:24\.1\.0.+?\r\n' | ||||||
|  | BELGIUM_MBUS3_EQUIPMENT_IDENTIFIER = r'\d-3:96\.1\.1.+?\r\n' | ||||||
|  | BELGIUM_MBUS3_VALVE_POSITION = r'\d-3:24\.4\.0.+?\r\n' | ||||||
|  | BELGIUM_MBUS3_METER_READING1 = r'\d-3:24\.2\.1.+?\r\n' | ||||||
|  | BELGIUM_MBUS3_METER_READING2 = r'\d-3:24\.2\.3.+?\r\n' | ||||||
|  | 
 | ||||||
|  | BELGIUM_MBUS4_DEVICE_TYPE = r'\d-4:24\.1\.0.+?\r\n' | ||||||
|  | BELGIUM_MBUS4_EQUIPMENT_IDENTIFIER = r'\d-4:96\.1\.1.+?\r\n' | ||||||
|  | BELGIUM_MBUS4_VALVE_POSITION = r'\d-4:24\.4\.0.+?\r\n' | ||||||
|  | BELGIUM_MBUS4_METER_READING1 = r'\d-4:24\.2\.1.+?\r\n' | ||||||
|  | BELGIUM_MBUS4_METER_READING2 = r'\d-4:24\.2\.3.+?\r\n' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| LUXEMBOURG_EQUIPMENT_IDENTIFIER = r'\d-\d:42\.0\.0.+?\r\n'  # Logical device name | LUXEMBOURG_EQUIPMENT_IDENTIFIER = r'\d-\d:42\.0\.0.+?\r\n'  # Logical device name | ||||||
|  | 
 | ||||||
| Q3D_EQUIPMENT_IDENTIFIER = r'\d-\d:0\.0\.0.+?\r\n'  # Logical device name | Q3D_EQUIPMENT_IDENTIFIER = r'\d-\d:0\.0\.0.+?\r\n'  # Logical device name | ||||||
| Q3D_EQUIPMENT_STATE = r'\d-\d:96\.5\.5.+?\r\n'  # Device state (hexadecimal) | Q3D_EQUIPMENT_STATE = r'\d-\d:96\.5\.5.+?\r\n'  # Device state (hexadecimal) | ||||||
| Q3D_EQUIPMENT_SERIALNUMBER = r'\d-\d:96\.1\.255.+?\r\n'  # Device Serialnumber | Q3D_EQUIPMENT_SERIALNUMBER = r'\d-\d:96\.1\.255.+?\r\n'  # Device Serialnumber | ||||||
|  | |||||||
| @ -113,6 +113,48 @@ class MBusObject(DSMRObject): | |||||||
|         } |         } | ||||||
|         return json.dumps(output) |         return json.dumps(output) | ||||||
| 
 | 
 | ||||||
|  | class MBusObjectPeak(DSMRObject): | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def datetime(self): | ||||||
|  |         return self.values[0]['value'] | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def occurred(self): | ||||||
|  |         return self.values[1]['value'] | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def value(self): | ||||||
|  |         return self.values[2]['value'] | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     def unit(self): | ||||||
|  |         return self.values[2]['unit'] | ||||||
|  | 
 | ||||||
|  |     def __str__(self): | ||||||
|  |         output = "{}\t[{}] at {} occurred {}".format(str(self.value), str(self.unit), str(self.datetime.astimezone().isoformat()), str(self.occurred.astimezone().isoformat())) | ||||||
|  |         return output | ||||||
|  | 
 | ||||||
|  |     def to_json(self): | ||||||
|  |         timestamp = self.datetime | ||||||
|  |         if isinstance(self.datetime, datetime.datetime): | ||||||
|  |             timestamp = self.datetime.astimezone().isoformat() | ||||||
|  |         timestamp_occurred = self.occurred | ||||||
|  |         if isinstance(self.occurred, datetime.datetime): | ||||||
|  |             timestamp_occurred = self.occurred.astimezone().isoformat() | ||||||
|  |         value = self.value | ||||||
|  |         if isinstance(self.value, datetime.datetime): | ||||||
|  |             value = self.value.astimezone().isoformat() | ||||||
|  |         if isinstance(self.value, Decimal): | ||||||
|  |             value = float(self.value) | ||||||
|  |         output = { | ||||||
|  |             'datetime': timestamp, | ||||||
|  |             'occurred': timestamp_occurred, | ||||||
|  |             'value': value, | ||||||
|  |             'unit': self.unit | ||||||
|  |         } | ||||||
|  |         return json.dumps(output) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class CosemObject(DSMRObject): | class CosemObject(DSMRObject): | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,12 +3,14 @@ import re | |||||||
| from binascii import unhexlify | from binascii import unhexlify | ||||||
| 
 | 
 | ||||||
| from ctypes import c_ushort | from ctypes import c_ushort | ||||||
|  | from decimal import Decimal | ||||||
| 
 | 
 | ||||||
| from dlms_cosem.connection import XDlmsApduFactory | from dlms_cosem.connection import XDlmsApduFactory | ||||||
| from dlms_cosem.protocol.xdlms import GeneralGlobalCipher | from dlms_cosem.protocol.xdlms import GeneralGlobalCipher | ||||||
| 
 | 
 | ||||||
| from dsmr_parser.objects import MBusObject, CosemObject, ProfileGenericObject | from dsmr_parser.objects import MBusObject, MBusObjectPeak, CosemObject, ProfileGenericObject | ||||||
| from dsmr_parser.exceptions import ParseError, InvalidChecksumError | from dsmr_parser.exceptions import ParseError, InvalidChecksumError | ||||||
|  | from dsmr_parser.value_types import timestamp | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
| @ -214,6 +216,43 @@ class MBusParser(DSMRObjectParser): | |||||||
|         return MBusObject(self._parse(line)) |         return MBusObject(self._parse(line)) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class MaxDemandParser(DSMRObjectParser): | ||||||
|  |     """ | ||||||
|  |     Max demand history parser. | ||||||
|  | 
 | ||||||
|  |     These are lines with multiple values. Each containing 2 timestamps and a value | ||||||
|  | 
 | ||||||
|  |     Line format: | ||||||
|  |     'ID (Count) (ID) (ID) (TST) (TST) (Mv1*U1)' | ||||||
|  | 
 | ||||||
|  |      1  2  3  4  5  6  7 | ||||||
|  | 
 | ||||||
|  |     1) OBIS Reduced ID-code | ||||||
|  |     2) Amount of values in the response | ||||||
|  |     3) ID of the source | ||||||
|  |     4) ^^ | ||||||
|  |     5) Time Stamp (TST) of the month | ||||||
|  |     6) Time Stamp (TST) when the max demand occured | ||||||
|  |     6) Measurement value 1 (most recent entry of buffer attribute without unit) | ||||||
|  |     7) Unit of measurement values (Unit of capture objects attribute) | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def parse(self, line): | ||||||
|  |         pattern = re.compile(r'((?<=\()[0-9a-zA-Z\.\*\-\:]{0,}(?=\)))') | ||||||
|  |         values = re.findall(pattern, line) | ||||||
|  | 
 | ||||||
|  |         objects = [] | ||||||
|  | 
 | ||||||
|  |         count = int(values[0]) | ||||||
|  |         for i in range(1, count+1): | ||||||
|  |             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])) | ||||||
|  | 
 | ||||||
|  |         return objects | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class CosemParser(DSMRObjectParser): | class CosemParser(DSMRObjectParser): | ||||||
|     """ |     """ | ||||||
|     Cosem object parser. |     Cosem object parser. | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ from decimal import Decimal | |||||||
| from copy import deepcopy | from copy import deepcopy | ||||||
| 
 | 
 | ||||||
| from dsmr_parser import obis_references as obis | from dsmr_parser import obis_references as obis | ||||||
| from dsmr_parser.parsers import CosemParser, ValueParser, MBusParser, ProfileGenericParser | from dsmr_parser.parsers import CosemParser, ValueParser, MBusParser, ProfileGenericParser, MaxDemandParser | ||||||
| from dsmr_parser.value_types import timestamp | from dsmr_parser.value_types import timestamp | ||||||
| from dsmr_parser.profile_generic_specifications import BUFFER_TYPES, PG_HEAD_PARSERS, PG_UNIDENTIFIED_BUFFERTYPE_PARSERS | from dsmr_parser.profile_generic_specifications import BUFFER_TYPES, PG_HEAD_PARSERS, PG_UNIDENTIFIED_BUFFERTYPE_PARSERS | ||||||
| 
 | 
 | ||||||
| @ -141,18 +141,88 @@ V5 = { | |||||||
| 
 | 
 | ||||||
| ALL = (V2_2, V3, V4, V5) | ALL = (V2_2, V3, V4, V5) | ||||||
| 
 | 
 | ||||||
| 
 | BELGIUM_FLUVIUS = { | ||||||
| BELGIUM_FLUVIUS = deepcopy(V5) |     'checksum_support': True, | ||||||
| BELGIUM_FLUVIUS['objects'].update({ |     'objects': { | ||||||
|     obis.BELGIUM_5MIN_GAS_METER_READING: MBusParser( |         obis.BELGIUM_VERSION_INFORMATION: CosemParser(ValueParser(str)), | ||||||
|         ValueParser(timestamp), |         obis.EQUIPMENT_IDENTIFIER: CosemParser(ValueParser(str)), | ||||||
|         ValueParser(Decimal) |         obis.P1_MESSAGE_TIMESTAMP: CosemParser(ValueParser(timestamp)), | ||||||
|     ), |         obis.ELECTRICITY_USED_TARIFF_1: CosemParser(ValueParser(Decimal)), | ||||||
|     obis.BELGIUM_MAX_POWER_PER_PHASE: CosemParser(ValueParser(Decimal)), |         obis.ELECTRICITY_USED_TARIFF_2: CosemParser(ValueParser(Decimal)), | ||||||
|     obis.BELGIUM_MAX_CURRENT_PER_PHASE: CosemParser(ValueParser(Decimal)), |         obis.ELECTRICITY_DELIVERED_TARIFF_1: CosemParser(ValueParser(Decimal)), | ||||||
|     obis.ACTUAL_SWITCH_POSITION: CosemParser(ValueParser(str)), |         obis.ELECTRICITY_DELIVERED_TARIFF_2: CosemParser(ValueParser(Decimal)), | ||||||
|     obis.VALVE_POSITION_GAS: CosemParser(ValueParser(str)), |         obis.ELECTRICITY_ACTIVE_TARIFF: CosemParser(ValueParser(str)), | ||||||
| }) |         obis.BELGIUM_CURRENT_AVERAGE_DEMAND: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.BELGIUM_MAXIMUM_DEMAND_MONTH: MBusParser( | ||||||
|  |             ValueParser(timestamp), | ||||||
|  |             ValueParser(Decimal) | ||||||
|  |         ), | ||||||
|  |         obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS: MaxDemandParser(), | ||||||
|  |         obis.CURRENT_ELECTRICITY_USAGE: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.CURRENT_ELECTRICITY_DELIVERY: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_VOLTAGE_L1: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_VOLTAGE_L2: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_VOLTAGE_L3: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_CURRENT_L1: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_CURRENT_L2: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.INSTANTANEOUS_CURRENT_L3: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.ACTUAL_SWITCH_POSITION: CosemParser(ValueParser(int)), | ||||||
|  |         obis.ACTUAL_TRESHOLD_ELECTRICITY: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.BELGIUM_MAX_POWER_PER_PHASE: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.BELGIUM_MAX_CURRENT_PER_PHASE: CosemParser(ValueParser(Decimal)), | ||||||
|  |         obis.TEXT_MESSAGE: CosemParser(ValueParser(str)), | ||||||
|  |         obis.BELGIUM_MBUS1_DEVICE_TYPE: CosemParser(ValueParser(int)), | ||||||
|  |         obis.BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER: CosemParser(ValueParser(str)), | ||||||
|  |         obis.BELGIUM_MBUS1_VALVE_POSITION: CosemParser(ValueParser(int)), | ||||||
|  |         obis.BELGIUM_MBUS1_METER_READING1: MBusParser( | ||||||
|  |             ValueParser(timestamp), | ||||||
|  |             ValueParser(Decimal) | ||||||
|  |         ), | ||||||
|  |         obis.BELGIUM_MBUS1_METER_READING2: MBusParser( | ||||||
|  |             ValueParser(timestamp), | ||||||
|  |             ValueParser(Decimal) | ||||||
|  |         ), | ||||||
|  |         obis.BELGIUM_MBUS2_DEVICE_TYPE: CosemParser(ValueParser(int)), | ||||||
|  |         obis.BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER: CosemParser(ValueParser(str)), | ||||||
|  |         obis.BELGIUM_MBUS2_VALVE_POSITION: CosemParser(ValueParser(int)), | ||||||
|  |         obis.BELGIUM_MBUS2_METER_READING1: MBusParser( | ||||||
|  |             ValueParser(timestamp), | ||||||
|  |             ValueParser(Decimal) | ||||||
|  |         ), | ||||||
|  |         obis.BELGIUM_MBUS2_METER_READING2: MBusParser( | ||||||
|  |             ValueParser(timestamp), | ||||||
|  |             ValueParser(Decimal) | ||||||
|  |         ), | ||||||
|  |         obis.BELGIUM_MBUS3_DEVICE_TYPE: CosemParser(ValueParser(int)), | ||||||
|  |         obis.BELGIUM_MBUS3_EQUIPMENT_IDENTIFIER: CosemParser(ValueParser(str)), | ||||||
|  |         obis.BELGIUM_MBUS3_VALVE_POSITION: CosemParser(ValueParser(int)), | ||||||
|  |         obis.BELGIUM_MBUS3_METER_READING1: MBusParser( | ||||||
|  |             ValueParser(timestamp), | ||||||
|  |             ValueParser(Decimal) | ||||||
|  |         ), | ||||||
|  |         obis.BELGIUM_MBUS3_METER_READING2: MBusParser( | ||||||
|  |             ValueParser(timestamp), | ||||||
|  |             ValueParser(Decimal) | ||||||
|  |         ), | ||||||
|  |         obis.BELGIUM_MBUS4_DEVICE_TYPE: CosemParser(ValueParser(int)), | ||||||
|  |         obis.BELGIUM_MBUS4_EQUIPMENT_IDENTIFIER: CosemParser(ValueParser(str)), | ||||||
|  |         obis.BELGIUM_MBUS4_VALVE_POSITION: CosemParser(ValueParser(int)), | ||||||
|  |         obis.BELGIUM_MBUS4_METER_READING1: MBusParser( | ||||||
|  |             ValueParser(timestamp), | ||||||
|  |             ValueParser(Decimal) | ||||||
|  |         ), | ||||||
|  |         obis.BELGIUM_MBUS4_METER_READING2: MBusParser( | ||||||
|  |             ValueParser(timestamp), | ||||||
|  |             ValueParser(Decimal) | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| LUXEMBOURG_SMARTY = deepcopy(V5) | LUXEMBOURG_SMARTY = deepcopy(V5) | ||||||
| LUXEMBOURG_SMARTY['objects'].update({ | LUXEMBOURG_SMARTY['objects'].update({ | ||||||
|  | |||||||
| @ -129,6 +129,48 @@ TELEGRAM_V5 = ( | |||||||
|     '!6EEE\r\n' |     '!6EEE\r\n' | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | TELEGRAM_FLUVIUS_V171 = ( | ||||||
|  |     '/FLU5\253769484_A\r\n' | ||||||
|  |     '\r\n' | ||||||
|  |     '0-0:96.1.4(50217)\r\n' | ||||||
|  |     '0-0:96.1.1(3153414733313031303231363035)\r\n' | ||||||
|  |     '0-0:1.0.0(200512135409S)\r\n' | ||||||
|  |     '1-0:1.8.1(000000.034*kWh)\r\n' | ||||||
|  |     '1-0:1.8.2(000015.758*kWh)\r\n' | ||||||
|  |     '1-0:2.8.1(000000.000*kWh)\r\n' | ||||||
|  |     '1-0:2.8.2(000000.011*kWh)\r\n' | ||||||
|  |     '1-0:1.4.0(02.351*kW)\r\n' | ||||||
|  |     '1-0:1.6.0(200509134558S)(02.589*kW)\r\n' | ||||||
|  |     '0-0:98.1.0(3)(1-0:1.6.0)(1-0:1.6.0)(200501000000S)(200423192538S)(03.695*kW)(200401000000S)(200305122139S)(05.980*kW)(200301000000S)(200210035421W)(04.318*kW)\r\n' | ||||||
|  |     '0-0:96.14.0(0001)\r\n' | ||||||
|  |     '1-0:1.7.0(00.000*kW)\r\n' | ||||||
|  |     '1-0:2.7.0(00.000*kW)\r\n' | ||||||
|  |     '1-0:21.7.0(00.000*kW)\r\n' | ||||||
|  |     '1-0:41.7.0(00.000*kW)\r\n' | ||||||
|  |     '1-0:61.7.0(00.000*kW)\r\n' | ||||||
|  |     '1-0:22.7.0(00.000*kW)\r\n' | ||||||
|  |     '1-0:42.7.0(00.000*kW)\r\n' | ||||||
|  |     '1-0:62.7.0(00.000*kW)\r\n' | ||||||
|  |     '1-0:32.7.0(234.7*V)\r\n' | ||||||
|  |     '1-0:52.7.0(234.7*V)\r\n' | ||||||
|  |     '1-0:72.7.0(234.7*V)\r\n' | ||||||
|  |     '1-0:31.7.0(000.00*A)\r\n' | ||||||
|  |     '1-0:51.7.0(000.00*A)\r\n' | ||||||
|  |     '1-0:71.7.0(000.00*A)\r\n' | ||||||
|  |     '0-0:96.3.10(1)\r\n' | ||||||
|  |     '0-0:17.0.0(999.9*kW)\r\n' | ||||||
|  |     '1-0:31.4.0(999*A)\r\n' | ||||||
|  |     '0-0:96.13.0()\r\n' | ||||||
|  |     '0-1:24.1.0(003)\r\n' | ||||||
|  |     '0-1:96.1.1(37464C4F32313139303333373333)\r\n' | ||||||
|  |     '0-1:24.4.0(1)\r\n' | ||||||
|  |     '0-1:24.2.3(200512134558S)(00112.384*m3)\r\n' | ||||||
|  |     '0-2:24.1.0(007)\r\n' | ||||||
|  |     '0-2:96.1.1(3853414731323334353637383930)\r\n' | ||||||
|  |     '0-2:24.2.1(200512134558S)(00872.234*m3)\r\n' | ||||||
|  |     '!911C\r\n' | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| # EasyMeter via COM-1 Ethernet Gateway | # EasyMeter via COM-1 Ethernet Gateway | ||||||
| # Q3D Manual (german) https://www.easymeter.com/downloads/products/zaehler/Q3D/Easymeter_Q3D_DE_2016-06-15.pdf | # Q3D Manual (german) https://www.easymeter.com/downloads/products/zaehler/Q3D/Easymeter_Q3D_DE_2016-06-15.pdf | ||||||
| #  - type code on page 8 | #  - type code on page 8 | ||||||
|  | |||||||
							
								
								
									
										269
									
								
								test/test_parse_fluvius.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								test/test_parse_fluvius.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,269 @@ | |||||||
|  | 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, MBusObjectPeak | ||||||
|  | from dsmr_parser.parsers import TelegramParser | ||||||
|  | from test.example_telegrams import TELEGRAM_FLUVIUS_V171 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TelegramParserFluviusTest(unittest.TestCase): | ||||||
|  |     """ Test parsing of a DSMR Fluvius telegram. """ | ||||||
|  | 
 | ||||||
|  |     def test_parse(self): | ||||||
|  |         parser = TelegramParser(telegram_specifications.BELGIUM_FLUVIUS) | ||||||
|  |         result = parser.parse(TELEGRAM_FLUVIUS_V171) | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_VERSION_INFORMATION (0-0:96.1.4) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_VERSION_INFORMATION], CosemObject) | ||||||
|  |         assert result[obis.BELGIUM_VERSION_INFORMATION].unit is None | ||||||
|  |         assert isinstance(result[obis.BELGIUM_VERSION_INFORMATION].value, str) | ||||||
|  |         assert result[obis.BELGIUM_VERSION_INFORMATION].value == '50217' | ||||||
|  | 
 | ||||||
|  |         # EQUIPMENT_IDENTIFIER (0-0:96.1.1) | ||||||
|  |         assert isinstance(result[obis.EQUIPMENT_IDENTIFIER], CosemObject) | ||||||
|  |         assert result[obis.EQUIPMENT_IDENTIFIER].unit is None | ||||||
|  |         assert isinstance(result[obis.EQUIPMENT_IDENTIFIER].value, str) | ||||||
|  |         assert result[obis.EQUIPMENT_IDENTIFIER].value == '3153414733313031303231363035' | ||||||
|  | 
 | ||||||
|  |         # P1_MESSAGE_TIMESTAMP (0-0:1.0.0) | ||||||
|  |         assert isinstance(result[obis.P1_MESSAGE_TIMESTAMP], CosemObject) | ||||||
|  |         assert result[obis.P1_MESSAGE_TIMESTAMP].unit is None | ||||||
|  |         assert isinstance(result[obis.P1_MESSAGE_TIMESTAMP].value, datetime.datetime) | ||||||
|  |         assert result[obis.P1_MESSAGE_TIMESTAMP].value == \ | ||||||
|  |             datetime.datetime(2020, 5, 12, 11, 54, 9, tzinfo=pytz.UTC) | ||||||
|  | 
 | ||||||
|  |         # ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1) | ||||||
|  |         assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1], CosemObject) | ||||||
|  |         assert result[obis.ELECTRICITY_USED_TARIFF_1].unit == 'kWh' | ||||||
|  |         assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_1].value, Decimal) | ||||||
|  |         assert result[obis.ELECTRICITY_USED_TARIFF_1].value == Decimal('0.034') | ||||||
|  | 
 | ||||||
|  |         # ELECTRICITY_USED_TARIFF_2 (1-0:1.8.2) | ||||||
|  |         assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2], CosemObject) | ||||||
|  |         assert result[obis.ELECTRICITY_USED_TARIFF_2].unit == 'kWh' | ||||||
|  |         assert isinstance(result[obis.ELECTRICITY_USED_TARIFF_2].value, Decimal) | ||||||
|  |         assert result[obis.ELECTRICITY_USED_TARIFF_2].value == Decimal('15.758') | ||||||
|  | 
 | ||||||
|  |         # ELECTRICITY_DELIVERED_TARIFF_1 (1-0:2.8.1) | ||||||
|  |         assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1], CosemObject) | ||||||
|  |         assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].unit == 'kWh' | ||||||
|  |         assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value, Decimal) | ||||||
|  |         assert result[obis.ELECTRICITY_DELIVERED_TARIFF_1].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # ELECTRICITY_DELIVERED_TARIFF_2 (1-0:2.8.2) | ||||||
|  |         assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2], CosemObject) | ||||||
|  |         assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].unit == 'kWh' | ||||||
|  |         assert isinstance(result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value, Decimal) | ||||||
|  |         assert result[obis.ELECTRICITY_DELIVERED_TARIFF_2].value == Decimal('0.011') | ||||||
|  | 
 | ||||||
|  |         # ELECTRICITY_ACTIVE_TARIFF (0-0:96.14.0) | ||||||
|  |         assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF], CosemObject) | ||||||
|  |         assert result[obis.ELECTRICITY_ACTIVE_TARIFF].unit is None | ||||||
|  |         assert isinstance(result[obis.ELECTRICITY_ACTIVE_TARIFF].value, str) | ||||||
|  |         assert result[obis.ELECTRICITY_ACTIVE_TARIFF].value == '0001' | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_CURRENT_AVERAGE_DEMAND (1-0:1.4.0) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_CURRENT_AVERAGE_DEMAND], CosemObject) | ||||||
|  |         assert result[obis.BELGIUM_CURRENT_AVERAGE_DEMAND].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.BELGIUM_CURRENT_AVERAGE_DEMAND].value, Decimal) | ||||||
|  |         assert result[obis.BELGIUM_CURRENT_AVERAGE_DEMAND].value == Decimal('2.351') | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_MAXIMUM_DEMAND_MONTH (1-0:1.6.0) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH], MBusObject) | ||||||
|  |         assert result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH].value, Decimal) | ||||||
|  |         assert result[obis.BELGIUM_MAXIMUM_DEMAND_MONTH].value == Decimal('2.589') | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_MAXIMUM_DEMAND_13_MONTHS (0-0:98.1.0) Value 0 | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0], MBusObjectPeak) | ||||||
|  |         assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].value, Decimal) | ||||||
|  |         assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][0].value == Decimal('3.695') | ||||||
|  |         # BELGIUM_MAXIMUM_DEMAND_13_MONTHS (0-0:98.1.0) Value 1 | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1], MBusObjectPeak) | ||||||
|  |         assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].value, Decimal) | ||||||
|  |         assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][1].value == Decimal('5.980') | ||||||
|  |         # BELGIUM_MAXIMUM_DEMAND_13_MONTHS (0-0:98.1.0) Value 2 | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2], MBusObjectPeak) | ||||||
|  |         assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].value, Decimal) | ||||||
|  |         assert result[obis.BELGIUM_MAXIMUM_DEMAND_13_MONTHS][2].value == Decimal('4.318') | ||||||
|  | 
 | ||||||
|  |         # CURRENT_ELECTRICITY_USAGE (1-0:1.7.0) | ||||||
|  |         assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE], CosemObject) | ||||||
|  |         assert result[obis.CURRENT_ELECTRICITY_USAGE].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.CURRENT_ELECTRICITY_USAGE].value, Decimal) | ||||||
|  |         assert result[obis.CURRENT_ELECTRICITY_USAGE].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # CURRENT_ELECTRICITY_DELIVERY (1-0:2.7.0) | ||||||
|  |         assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY], CosemObject) | ||||||
|  |         assert result[obis.CURRENT_ELECTRICITY_DELIVERY].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.CURRENT_ELECTRICITY_DELIVERY].value, Decimal) | ||||||
|  |         assert result[obis.CURRENT_ELECTRICITY_DELIVERY].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE (1-0:21.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE (1-0:41.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE (1-0:61.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE (1-0:22.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE (1-0:42.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE (1-0:62.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_VOLTAGE_L1 (1-0:32.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L1], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_VOLTAGE_L1].unit == 'V' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L1].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_VOLTAGE_L1].value == Decimal('234.7') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_VOLTAGE_L2 (1-0:52.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L2], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_VOLTAGE_L2].unit == 'V' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L2].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_VOLTAGE_L2].value == Decimal('234.7') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_VOLTAGE_L3 (1-0:72.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L3], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_VOLTAGE_L3].unit == 'V' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_VOLTAGE_L3].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_VOLTAGE_L3].value == Decimal('234.7') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_CURRENT_L1 (1-0:31.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L1], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_CURRENT_L1].unit == 'A' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L1].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_CURRENT_L1].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_CURRENT_L2 (1-0:51.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L2], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_CURRENT_L2].unit == 'A' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L2].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_CURRENT_L2].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # INSTANTANEOUS_CURRENT_L3 (1-0:71.7.0) | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L3], CosemObject) | ||||||
|  |         assert result[obis.INSTANTANEOUS_CURRENT_L3].unit == 'A' | ||||||
|  |         assert isinstance(result[obis.INSTANTANEOUS_CURRENT_L3].value, Decimal) | ||||||
|  |         assert result[obis.INSTANTANEOUS_CURRENT_L3].value == Decimal('0.000') | ||||||
|  | 
 | ||||||
|  |         # ACTUAL_SWITCH_POSITION (0-0:96.3.10) | ||||||
|  |         assert isinstance(result[obis.ACTUAL_SWITCH_POSITION], CosemObject) | ||||||
|  |         assert result[obis.ACTUAL_SWITCH_POSITION].unit is None | ||||||
|  |         assert isinstance(result[obis.ACTUAL_SWITCH_POSITION].value, int) | ||||||
|  |         assert result[obis.ACTUAL_SWITCH_POSITION].value == 1 | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_MAX_POWER_PER_PHASE (0-0:17.0.0) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAX_POWER_PER_PHASE], CosemObject) | ||||||
|  |         assert result[obis.BELGIUM_MAX_POWER_PER_PHASE].unit == 'kW' | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAX_POWER_PER_PHASE].value, Decimal) | ||||||
|  |         assert result[obis.BELGIUM_MAX_POWER_PER_PHASE].value == Decimal('999.9') | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_MAX_POWER_PER_PHASE (1-0:31.4.0) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAX_CURRENT_PER_PHASE], CosemObject) | ||||||
|  |         assert result[obis.BELGIUM_MAX_CURRENT_PER_PHASE].unit == 'A' | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MAX_CURRENT_PER_PHASE].value, Decimal) | ||||||
|  |         assert result[obis.BELGIUM_MAX_CURRENT_PER_PHASE].value == Decimal('999') | ||||||
|  | 
 | ||||||
|  |         # TEXT_MESSAGE (0-0:96.13.0) | ||||||
|  |         assert isinstance(result[obis.TEXT_MESSAGE], CosemObject) | ||||||
|  |         assert result[obis.TEXT_MESSAGE].unit is None | ||||||
|  |         assert result[obis.TEXT_MESSAGE].value is None | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_MBUS1_DEVICE_TYPE (0-1:24.1.0) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS1_DEVICE_TYPE], CosemObject) | ||||||
|  |         assert result[obis.BELGIUM_MBUS1_DEVICE_TYPE].unit is None | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS1_DEVICE_TYPE].value, int) | ||||||
|  |         assert result[obis.BELGIUM_MBUS1_DEVICE_TYPE].value == 3 | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER (0-1:96.1.1) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER], CosemObject) | ||||||
|  |         assert result[obis.BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER].unit is None | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER].value, str) | ||||||
|  |         assert result[obis.BELGIUM_MBUS1_EQUIPMENT_IDENTIFIER].value == '37464C4F32313139303333373333' | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_MBUS1_VALVE_POSITION (0-1:24.4.0) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS1_VALVE_POSITION], CosemObject) | ||||||
|  |         assert result[obis.BELGIUM_MBUS1_VALVE_POSITION].unit is None | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS1_VALVE_POSITION].value, int) | ||||||
|  |         assert result[obis.BELGIUM_MBUS1_VALVE_POSITION].value == 1 | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_MBUS1_METER_READING2 (0-1:24.2.3) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS1_METER_READING2], MBusObject) | ||||||
|  |         assert result[obis.BELGIUM_MBUS1_METER_READING2].unit == 'm3' | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS1_METER_READING2].value, Decimal) | ||||||
|  |         assert result[obis.BELGIUM_MBUS1_METER_READING2].value == Decimal('112.384') | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_MBUS2_DEVICE_TYPE (0-2:24.1.0) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS2_DEVICE_TYPE], CosemObject) | ||||||
|  |         assert result[obis.BELGIUM_MBUS2_DEVICE_TYPE].unit is None | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS2_DEVICE_TYPE].value, int) | ||||||
|  |         assert result[obis.BELGIUM_MBUS2_DEVICE_TYPE].value == 7 | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER (0-2:96.1.1) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER], CosemObject) | ||||||
|  |         assert result[obis.BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER].unit is None | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER].value, str) | ||||||
|  |         assert result[obis.BELGIUM_MBUS2_EQUIPMENT_IDENTIFIER].value == '3853414731323334353637383930' | ||||||
|  | 
 | ||||||
|  |         # BELGIUM_MBUS2_METER_READING1 (0-1:24.2.1) | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS2_METER_READING1], MBusObject) | ||||||
|  |         assert result[obis.BELGIUM_MBUS2_METER_READING1].unit == 'm3' | ||||||
|  |         assert isinstance(result[obis.BELGIUM_MBUS2_METER_READING1].value, Decimal) | ||||||
|  |         assert result[obis.BELGIUM_MBUS2_METER_READING1].value == Decimal('872.234') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def test_checksum_valid(self): | ||||||
|  |         # No exception is raised. | ||||||
|  |         TelegramParser.validate_checksum(TELEGRAM_FLUVIUS_V171) | ||||||
|  | 
 | ||||||
|  |     def test_checksum_invalid(self): | ||||||
|  |         # Remove the electricty used data value. This causes the checksum to | ||||||
|  |         # not match anymore. | ||||||
|  |         corrupted_telegram = TELEGRAM_FLUVIUS_V171.replace( | ||||||
|  |             '1-0:1.8.1(000000.034*kWh)\r\n', | ||||||
|  |             '' | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         with self.assertRaises(InvalidChecksumError): | ||||||
|  |             TelegramParser.validate_checksum(corrupted_telegram) | ||||||
|  | 
 | ||||||
|  |     def test_checksum_missing(self): | ||||||
|  |         # Remove the checksum value causing a ParseError. | ||||||
|  |         corrupted_telegram = TELEGRAM_FLUVIUS_V171.replace('!911C\r\n', '') | ||||||
|  |         with self.assertRaises(ParseError): | ||||||
|  |             TelegramParser.validate_checksum(corrupted_telegram) | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user