{
"extension": ".py",
"source": "from decimal import Decimal\n\nimport datetime\nimport unittest\n\nimport pytz\n\nfrom dsmr_parser import telegram_specifications\nfrom dsmr_parser.exceptions import InvalidChecksumError, ParseError\nfrom dsmr_parser.objects import CosemObject\nfrom dsmr_parser.parsers import TelegramParser\nfrom test.example_telegrams import TELEGRAM_V5_EON_HU\n\n\nclass TelegramParserV5EONHUTest(unittest.TestCase):\n \"\"\" Test parsing of a DSMR v5 EON Hungary telegram. \"\"\"\n\n def test_parse(self):\n parser = TelegramParser(telegram_specifications.EON_HUNGARY)\n try:\n telegram = parser.parse(TELEGRAM_V5_EON_HU, throw_ex=True)\n except Exception as ex:\n assert False, f\"parse trigged an exception {ex}\"\n\n # P1_MESSAGE_TIMESTAMP (0-0:1.0.0)\n assert isinstance(telegram.P1_MESSAGE_TIMESTAMP, CosemObject)\n assert telegram.P1_MESSAGE_TIMESTAMP.unit is None\n assert isinstance(telegram.P1_MESSAGE_TIMESTAMP.value, datetime.datetime)\n assert telegram.P1_MESSAGE_TIMESTAMP.value == \\\n pytz.timezone(\"Europe/Budapest\").localize(datetime.datetime(2023, 7, 24, 15, 7, 30))\n\n # EON_HU_COSEM_LOGICAL_DEVICE_NAME (0-0:42.0.0)\n assert isinstance(telegram.COSEM_LOGICAL_DEVICE_NAME, CosemObject)\n assert telegram.COSEM_LOGICAL_DEVICE_NAME.unit is None\n assert isinstance(telegram.COSEM_LOGICAL_DEVICE_NAME.value, str)\n assert telegram.COSEM_LOGICAL_DEVICE_NAME.value == '53414733303832323030303032313630'\n\n # EON_HU_EQUIPMENT_SERIAL_NUMBER (0-0:96.1.0)\n assert isinstance(telegram.EQUIPMENT_SERIAL_NUMBER, CosemObject)\n assert telegram.EQUIPMENT_SERIAL_NUMBER.unit is None\n assert isinstance(telegram.EQUIPMENT_SERIAL_NUMBER.value, str)\n assert telegram.EQUIPMENT_SERIAL_NUMBER.value == '383930303832323030303032313630'\n\n # ELECTRICITY_ACTIVE_TARIFF (0-0:96.14.0)\n assert isinstance(telegram.ELECTRICITY_ACTIVE_TARIFF, CosemObject)\n assert telegram.ELECTRICITY_ACTIVE_TARIFF.unit is None\n assert isinstance(telegram.ELECTRICITY_ACTIVE_TARIFF.value, str)\n assert telegram.ELECTRICITY_ACTIVE_TARIFF.value == '0001'\n\n # ACTUAL_SWITCH_POSITION (0-0:96.3.10)\n assert isinstance(telegram.ACTUAL_SWITCH_POSITION, CosemObject)\n assert telegram.ACTUAL_SWITCH_POSITION.unit is None\n assert isinstance(telegram.ACTUAL_SWITCH_POSITION.value, str)\n assert telegram.ACTUAL_SWITCH_POSITION.value == '1'\n\n # ACTUAL_TRESHOLD_ELECTRICITY (0-0:17.0.0)\n assert isinstance(telegram.ACTUAL_TRESHOLD_ELECTRICITY, CosemObject)\n assert telegram.ACTUAL_TRESHOLD_ELECTRICITY.unit == 'kW'\n assert isinstance(telegram.ACTUAL_TRESHOLD_ELECTRICITY.value, Decimal)\n assert telegram.ACTUAL_TRESHOLD_ELECTRICITY.value == Decimal('90.000')\n\n # ELECTRICITY_IMPORTED_TOTAL (1-0:1.8.0)\n assert isinstance(telegram.ELECTRICITY_IMPORTED_TOTAL, CosemObject)\n assert telegram.ELECTRICITY_IMPORTED_TOTAL.unit == 'kWh'\n assert isinstance(telegram.ELECTRICITY_IMPORTED_TOTAL.value, Decimal)\n assert telegram.ELECTRICITY_IMPORTED_TOTAL.value == Decimal('000173.640')\n\n # ELECTRICITY_USED_TARIFF_1 (1-0:1.8.1)\n assert isinstance(telegram.ELECTRICITY_USED_TARIFF_1, CosemObject)\n assert telegram.ELECTRICITY_USED_TARIFF_1.unit == 'kWh'\n assert isinstance(telegram.ELECTRICITY_USED_TARIFF_1.value, Decimal)\n assert telegram.ELECTRICITY_USED_TARIFF_1.value == Decimal('000047.719')\n\n # ELECTRICITY_USED_TARIFF_2 (1-0:1.8.2)\n assert isinstance(telegram.ELECTRICITY_USED_TARIFF_2, CosemObject)\n assert telegram.ELECTRICITY_USED_TARIFF_2.unit == 'kWh'\n assert isinstance(telegram.ELECTRICITY_USED_TARIFF_2.value, Decimal)\n assert telegram.ELECTRICITY_USED_TARIFF_2.value == Decimal('000125.921')\n\n # EON_HU_ELECTRICITY_USED_TARIFF_3 (1-0:1.8.3)\n assert isinstance(telegram.ELECTRICITY_USED_TARIFF_3, CosemObject)\n assert telegram.ELECTRICITY_USED_TARIFF_3.unit == 'kWh'\n assert isinstance(telegram.ELECTRICITY_USED_TARIFF_3.value, Decimal)\n assert telegram.ELECTRICITY_USED_TARIFF_3.value == Decimal('000000.000')\n\n # EON_HU_ELECTRICITY_USED_TARIFF_4 (1-0:1.8.4)\n assert isinstance(telegram.ELECTRICITY_USED_TARIFF_4, CosemObject)\n assert telegram.ELECTRICITY_USED_TARIFF_4.unit == 'kWh'\n assert isinstance(telegram.ELECTRICITY_USED_TARIFF_4.value, Decimal)\n assert telegram.ELECTRICITY_USED_TARIFF_4.value == Decimal('000000.000')\n\n # ELECTRICITY_EXPORTED_TOTAL (1-0:2.8.0)\n assert isinstance(telegram.ELECTRICITY_EXPORTED_TOTAL, CosemObject)\n assert telegram.ELECTRICITY_EXPORTED_TOTAL.unit == 'kWh'\n assert isinstance(telegram.ELECTRICITY_EXPORTED_TOTAL.value, Decimal)\n assert telegram.ELECTRICITY_EXPORTED_TOTAL.value == Decimal('000627.177')\n\n # ELECTRICITY_DELIVERED_TARIFF_1 (1-0:2.8.1)\n assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_1, CosemObject)\n assert telegram.ELECTRICITY_DELIVERED_TARIFF_1.unit == 'kWh'\n assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_1.value, Decimal)\n assert telegram.ELECTRICITY_DELIVERED_TARIFF_1.value == Decimal('000401.829')\n\n # ELECTRICITY_DELIVERED_TARIFF_2 (1-0:2.8.2)\n assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_2, CosemObject)\n assert telegram.ELECTRICITY_DELIVERED_TARIFF_2.unit == 'kWh'\n assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_2.value, Decimal)\n assert telegram.ELECTRICITY_DELIVERED_TARIFF_2.value == Decimal('000225.348')\n\n # EON_HU_ELECTRICITY_DELIVERED_TARIFF_3 (1-0:2.8.3)\n assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_3, CosemObject)\n assert telegram.ELECTRICITY_DELIVERED_TARIFF_3.unit == 'kWh'\n assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_3.value, Decimal)\n assert telegram.ELECTRICITY_DELIVERED_TARIFF_3.value == Decimal('000000.000')\n\n # EON_HU_ELECTRICITY_DELIVERED_TARIFF_4 (1-0:2.8.4)\n assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_4, CosemObject)\n assert telegram.ELECTRICITY_DELIVERED_TARIFF_4.unit == 'kWh'\n assert isinstance(telegram.ELECTRICITY_DELIVERED_TARIFF_4.value, Decimal)\n assert telegram.ELECTRICITY_DELIVERED_TARIFF_4.value == Decimal('000000.000')\n\n # ELECTRICITY_REACTIVE_IMPORTED_TOTAL (1-0:3.8.0)\n assert isinstance(telegram.ELECTRICITY_REACTIVE_IMPORTED_TOTAL, CosemObject)\n assert telegram.ELECTRICITY_REACTIVE_IMPORTED_TOTAL.unit == 'kvarh'\n assert isinstance(telegram.ELECTRICITY_REACTIVE_IMPORTED_TOTAL.value, Decimal)\n assert telegram.ELECTRICITY_REACTIVE_IMPORTED_TOTAL.value == Decimal('000000.123')\n\n # ELECTRICITY_REACTIVE_EXPORTED_TOTAL (1-0:4.8.0)\n assert isinstance(telegram.ELECTRICITY_REACTIVE_EXPORTED_TOTAL, CosemObject)\n assert telegram.ELECTRICITY_REACTIVE_EXPORTED_TOTAL.unit == 'kvarh'\n assert isinstance(telegram.ELECTRICITY_REACTIVE_EXPORTED_TOTAL.value, Decimal)\n assert telegram.ELECTRICITY_REACTIVE_EXPORTED_TOTAL.value == Decimal('000303.131')\n\n # EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q1 (1-0:5.8.0)\n assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q1, CosemObject)\n assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q1.unit == 'kvarh'\n assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q1.value, Decimal)\n assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q1.value == Decimal('000000.668')\n\n # EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q2 (1-0:6.8.0)\n assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q2, CosemObject)\n assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q2.unit == 'kvarh'\n assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q2.value, Decimal)\n assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q2.value == Decimal('000000.071')\n\n # EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q3 (1-0:7.8.0)\n assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q3, CosemObject)\n assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q3.unit == 'kvarh'\n assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q3.value, Decimal)\n assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q3.value == Decimal('000160.487')\n\n # EON_HU_ELECTRICITY_REACTIVE_TOTAL_Q4 (1-0:8.8.0)\n assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q4, CosemObject)\n assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q4.unit == 'kvarh'\n assert isinstance(telegram.ELECTRICITY_REACTIVE_TOTAL_Q4.value, Decimal)\n assert telegram.ELECTRICITY_REACTIVE_TOTAL_Q4.value == Decimal('000143.346')\n\n # EON_HU_ELECTRICITY_COMBINED (1-0:15.8.0)\n assert isinstance(telegram.ELECTRICITY_COMBINED, CosemObject)\n assert telegram.ELECTRICITY_COMBINED.unit == 'kWh'\n assert isinstance(telegram.ELECTRICITY_COMBINED.value, Decimal)\n assert telegram.ELECTRICITY_COMBINED.value == Decimal('000800.817')\n\n # INSTANTANEOUS_VOLTAGE_L2 (1-0:32.7.0)\n assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L1, CosemObject)\n assert telegram.INSTANTANEOUS_VOLTAGE_L1.unit == 'V'\n assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L1.value, Decimal)\n assert telegram.INSTANTANEOUS_VOLTAGE_L1.value == Decimal('240.4')\n\n # INSTANTANEOUS_VOLTAGE_L2 (1-0:52.7.0)\n assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L2, CosemObject)\n assert telegram.INSTANTANEOUS_VOLTAGE_L2.unit == 'V'\n assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L2.value, Decimal)\n assert telegram.INSTANTANEOUS_VOLTAGE_L2.value == Decimal('239.1')\n\n # INSTANTANEOUS_VOLTAGE_L3 (1-0:72.7.0)\n assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L3, CosemObject)\n assert telegram.INSTANTANEOUS_VOLTAGE_L3.unit == 'V'\n assert isinstance(telegram.INSTANTANEOUS_VOLTAGE_L3.value, Decimal)\n assert telegram.INSTANTANEOUS_VOLTAGE_L3.value == Decimal('241.2')\n\n # INSTANTANEOUS_CURRENT_L1 (1-0:31.7.0)\n assert isinstance(telegram.INSTANTANEOUS_CURRENT_L1, CosemObject)\n assert telegram.INSTANTANEOUS_CURRENT_L1.unit == 'A'\n assert isinstance(telegram.INSTANTANEOUS_CURRENT_L1.value, Decimal)\n assert telegram.INSTANTANEOUS_CURRENT_L1.value == Decimal('003')\n\n # INSTANTANEOUS_CURRENT_L2 (1-0:51.7.0)\n assert isinstance(telegram.INSTANTANEOUS_CURRENT_L2, CosemObject)\n assert telegram.INSTANTANEOUS_CURRENT_L2.unit == 'A'\n assert isinstance(telegram.INSTANTANEOUS_CURRENT_L2.value, Decimal)\n assert telegram.INSTANTANEOUS_CURRENT_L2.value == Decimal('004')\n\n # INSTANTANEOUS_CURRENT_L3 (1-0:71.7.0)\n assert isinstance(telegram.INSTANTANEOUS_CURRENT_L3, CosemObject)\n assert telegram.INSTANTANEOUS_CURRENT_L3.unit == 'A'\n assert isinstance(telegram.INSTANTANEOUS_CURRENT_L3.value, Decimal)\n assert telegram.INSTANTANEOUS_CURRENT_L3.value == Decimal('003')\n\n # EON_HU_INSTANTANEOUS_POWER_FACTOR_TOTAL (1-0:13.7.0)\n assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_TOTAL, CosemObject)\n assert telegram.INSTANTANEOUS_POWER_FACTOR_TOTAL.unit is None\n assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_TOTAL.value, Decimal)\n assert telegram.INSTANTANEOUS_POWER_FACTOR_TOTAL.value == Decimal('4.556')\n\n # EON_HU_INSTANTANEOUS_POWER_FACTOR_L1 (1-0:33.7.0)\n assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L1, CosemObject)\n assert telegram.INSTANTANEOUS_POWER_FACTOR_L1.unit is None\n assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L1.value, Decimal)\n assert telegram.INSTANTANEOUS_POWER_FACTOR_L1.value == Decimal('4.591')\n\n # EON_HU_INSTANTANEOUS_POWER_FACTOR_L2 (1-0:53.7.0)\n assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L2, CosemObject)\n assert telegram.INSTANTANEOUS_POWER_FACTOR_L2.unit is None\n assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L2.value, Decimal)\n assert telegram.INSTANTANEOUS_POWER_FACTOR_L2.value == Decimal('4.542')\n\n # EON_HU_INSTANTANEOUS_POWER_FACTOR_L3 (1-0:73.7.0)\n assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L3, CosemObject)\n assert telegram.INSTANTANEOUS_POWER_FACTOR_L3.unit is None\n assert isinstance(telegram.INSTANTANEOUS_POWER_FACTOR_L3.value, Decimal)\n assert telegram.INSTANTANEOUS_POWER_FACTOR_L3.value == Decimal('4.552')\n\n # EON_HU_FREQUENCY (1-0:14.7.0)\n assert isinstance(telegram.FREQUENCY, CosemObject)\n assert telegram.FREQUENCY.unit == \"Hz\"\n assert isinstance(telegram.FREQUENCY.value, Decimal)\n assert telegram.FREQUENCY.value == Decimal('50.00')\n\n # CURRENT_ELECTRICITY_USAGE (1-0:1.7.0)\n assert isinstance(telegram.CURRENT_ELECTRICITY_USAGE, CosemObject)\n assert telegram.CURRENT_ELECTRICITY_USAGE.unit == 'kW'\n assert isinstance(telegram.CURRENT_ELECTRICITY_USAGE.value, Decimal)\n assert telegram.CURRENT_ELECTRICITY_USAGE.value == Decimal('00.000')\n\n # CURRENT_ELECTRICITY_DELIVERY (1-0:2.7.0)\n assert isinstance(telegram.CURRENT_ELECTRICITY_DELIVERY, CosemObject)\n assert telegram.CURRENT_ELECTRICITY_DELIVERY.unit == 'kW'\n assert isinstance(telegram.CURRENT_ELECTRICITY_DELIVERY.value, Decimal)\n assert telegram.CURRENT_ELECTRICITY_DELIVERY.value == Decimal('02.601')\n\n # EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q1 (1-0:5.7.0)\n assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q1, CosemObject)\n assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q1.unit == 'kvar'\n assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q1.value, Decimal)\n assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q1.value == Decimal('00.000')\n\n # EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q2 (1-0:6.7.0)\n assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q2, CosemObject)\n assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q2.unit == 'kvar'\n assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q2.value, Decimal)\n assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q2.value == Decimal('00.000')\n\n # EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q3 (1-0:7.7.0)\n assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q3, CosemObject)\n assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q3.unit == 'kvar'\n assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q3.value, Decimal)\n assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q3.value == Decimal('00.504')\n\n # EON_HU_INSTANTANEOUS_REACTIVE_POWER_Q4 (1-0:8.7.0)\n assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q4, CosemObject)\n assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q4.unit == 'kvar'\n assert isinstance(telegram.INSTANTANEOUS_REACTIVE_POWER_Q4.value, Decimal)\n assert telegram.INSTANTANEOUS_REACTIVE_POWER_Q4.value == Decimal('00.000')\n\n # FUSE_THRESHOLD_L1 (1-0:31.4.0)\n assert isinstance(telegram.FUSE_THRESHOLD_L1, CosemObject)\n assert telegram.FUSE_THRESHOLD_L1.unit == 'A'\n assert isinstance(telegram.FUSE_THRESHOLD_L1.value, Decimal)\n assert telegram.FUSE_THRESHOLD_L1.value == Decimal('200.00')\n\n # FUSE_THRESHOLD_L2 (1-0:31.4.0)\n assert isinstance(telegram.FUSE_THRESHOLD_L2, CosemObject)\n assert telegram.FUSE_THRESHOLD_L2.unit == 'A'\n assert isinstance(telegram.FUSE_THRESHOLD_L2.value, Decimal)\n assert telegram.FUSE_THRESHOLD_L2.value == Decimal('200.00')\n\n # FUSE_THRESHOLD_L3 (1-0:31.4.0)\n assert isinstance(telegram.FUSE_THRESHOLD_L3, CosemObject)\n assert telegram.FUSE_THRESHOLD_L3.unit == 'A'\n assert isinstance(telegram.FUSE_THRESHOLD_L3.value, Decimal)\n assert telegram.FUSE_THRESHOLD_L3.value == Decimal('200.00')\n\n # TEXT_MESSAGE (0-0:96.13.0)\n assert isinstance(telegram.TEXT_MESSAGE, CosemObject)\n assert telegram.TEXT_MESSAGE.unit is None\n assert telegram.TEXT_MESSAGE.value is None\n\n def test_checksum_valid(self):\n # No exception is raised.\n TelegramParser.validate_checksum(TELEGRAM_V5_EON_HU)\n\n def test_checksum_invalid(self):\n # Remove the electricty used data value. This causes the checksum to\n # not match anymore.\n corrupted_telegram = TELEGRAM_V5_EON_HU.replace(\n '1-0:1.8.1(000047.719*kWh)\\r\\n',\n ''\n )\n\n with self.assertRaises(InvalidChecksumError):\n TelegramParser.validate_checksum(corrupted_telegram)\n\n def test_checksum_missing(self):\n # Remove the checksum value causing a ParseError.\n corrupted_telegram = TELEGRAM_V5_EON_HU.replace('!99DA\\r\\n', '')\n with self.assertRaises(ParseError):\n TelegramParser.validate_checksum(corrupted_telegram)\n",
"review": "# 8\n\n## Bugs\n- No prominent bugs were identified, but exception handling in `test_parse` could miss specific issues due to a generic exception catch.\n\n## Optimizations\n- Use `self.assertIsInstance` instead of `assert isinstance` for consistency with unittest methods.\n- Refactor the test to separate setup, execution, and assertions for better readability and maintenance.\n- Consider using parameterized tests to avoid repetition and improve maintainability.\n- The generic exception handling in the `test_parse` method could be more specific to catch only expected exceptions.\n\n## Good points\n- Comprehensive test coverage for various fields extracted from the telegram.\n- Uses the `unittest` framework appropriately to perform unit testing.\n- Coverage includes validation for both valid and invalid checksums.\n- Correct use of `Decimal` for precise representation of numeric values.\n\n## Summary\nThe code provides thorough unittest coverage for parsing DSMR v5 EON Hungary telegrams. It ensures that each field in the telegram is correctly parsed and validated, covering cases such as valid, invalid, and missing checksums. The test structure is mostly solid, though improvements could be made by using `unittest` assertions to enhance readability and error reporting. Parameterizing repetitive assertions would also help in maintaining the code more efficiently.\n\n## Open source alternatives\n- **pytz**: This library is being used in the code for timezone localization and is a robust package for working with time zones.\n- **Decouple**: If managing environment-specific configurations becomes complex, you may consider using Decouple for configuration management.",
"filename": "test_parse_v5_eon_hungary.py",
"path": "test/test_parse_v5_eon_hungary.py",
"directory": "test",
"grade": 8,
"size": 16935,
"line_count": 309
}