From f8abd4e40eecf393096c61771783855b3e626376 Mon Sep 17 00:00:00 2001 From: Dennis Siemensma Date: Mon, 23 Jan 2023 22:46:25 +0100 Subject: [PATCH] Added new datalogger configuration option for selecting extra device channel for specific vendor(s) #1794 --- docs/reference/changelog.rst | 1 + dsmr_datalogger/admin.py | 6 +- .../0032_dsmr_extra_device_channel.py | 46 +++++++ dsmr_datalogger/models/settings.py | 27 +++- dsmr_datalogger/services/datalogger.py | 21 ++- .../test_fluvius_multiple_gas_devices.py | 124 ++++++++++++++++++ dsmrreader/locales/nl/LC_MESSAGES/django.mo | Bin 109655 -> 110501 bytes dsmrreader/locales/nl/LC_MESSAGES/django.po | 34 ++++- 8 files changed, 246 insertions(+), 13 deletions(-) create mode 100644 dsmr_datalogger/migrations/0032_dsmr_extra_device_channel.py create mode 100644 dsmr_datalogger/tests/datalogger/test_fluvius_multiple_gas_devices.py diff --git a/docs/reference/changelog.rst b/docs/reference/changelog.rst index 49be969db..e5be7caaa 100644 --- a/docs/reference/changelog.rst +++ b/docs/reference/changelog.rst @@ -35,6 +35,7 @@ v5.10.0 - January 2023 - ``Added`` [`#1770 `_] Now tracking meter position timestamps in day statistics. Added them to Archive (day view) and Export. - ``Added`` [`#1770 `_] Automatic migrations retroactively reassessing meter positions and timestamps. Additionally checks/fixes gas consumption mismatch. +- ``Added`` [`#1794 `_] Added new datalogger configuration option for selecting extra device channel for specific vendor(s) - ``Added`` Old Dashboard notifications can now be viewed and permanently deleted in the Frontend admin section. - ``Changed`` [`#1725 `_] The value of ``DSMRREADER_REMOTE_DATALOGGER_INPUT_METHOD`` is now restricted to: ``DEBUG``, ``WARNING`` or ``ERROR`` diff --git a/dsmr_datalogger/admin.py b/dsmr_datalogger/admin.py index 572b9d76d..053eb59b7 100644 --- a/dsmr_datalogger/admin.py +++ b/dsmr_datalogger/admin.py @@ -44,7 +44,11 @@ class DataloggerSettingsAdmin(SingletonModelAdmin): ( _("Advanced"), { - "fields": ["process_sleep", "override_telegram_timestamp"], + "fields": [ + "dsmr_extra_device_channel", + "process_sleep", + "override_telegram_timestamp", + ], }, ), ( diff --git a/dsmr_datalogger/migrations/0032_dsmr_extra_device_channel.py b/dsmr_datalogger/migrations/0032_dsmr_extra_device_channel.py new file mode 100644 index 000000000..38f8c688f --- /dev/null +++ b/dsmr_datalogger/migrations/0032_dsmr_extra_device_channel.py @@ -0,0 +1,46 @@ +# Generated by Django 3.2.16 on 2023-01-23 21:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("dsmr_datalogger", "0031_meter_statistics_meta"), + ] + + operations = [ + migrations.AddField( + model_name="dataloggersettings", + name="dsmr_extra_device_channel", + field=models.IntegerField( + blank=True, + choices=[ + (None, "Auto (default)"), + (1, "Belgium - Fluvius (channel 1)"), + (2, "Belgium - Fluvius (channel 2)"), + (3, "Belgium - Fluvius (channel 3)"), + (4, "Belgium - Fluvius (channel 4)"), + ], + default=None, + help_text="Only use when your extra device is read incorrectly (e.g. gas). Also, only works with specific vendor(s).", + null=True, + verbose_name="Extra device channel", + ), + ), + migrations.AlterField( + model_name="dataloggersettings", + name="dsmr_version", + field=models.IntegerField( + choices=[ + (4, "Netherlands - DSMR version 4/5 (default)"), + (3, "Netherlands - DSMR version 2/3"), + (101, "Belgium - Fluvius (gas meter fix)"), + (102, "Luxembourg - Smarty (single tariff fix)"), + ], + default=4, + help_text="The DSMR version your meter supports or the vendor related to it. Version should be printed on meter.", + verbose_name="DSMR version/vendor", + ), + ), + ] diff --git a/dsmr_datalogger/models/settings.py b/dsmr_datalogger/models/settings.py index f9d772cc3..b0895949d 100644 --- a/dsmr_datalogger/models/settings.py +++ b/dsmr_datalogger/models/settings.py @@ -28,6 +28,19 @@ class DataloggerSettings(ModelUpdateMixin, SingletonModel): (DSMR_LUXEMBOURG_SMARTY, _("Luxembourg - Smarty (single tariff fix)")), ) + DSMR_EXTRA_DEVICE_CHANNEL_AUTO = None + DSMR_EXTRA_DEVICE_CHANNEL_1 = 1 + DSMR_EXTRA_DEVICE_CHANNEL_2 = 2 + DSMR_EXTRA_DEVICE_CHANNEL_3 = 3 + DSMR_EXTRA_DEVICE_CHANNEL_4 = 4 + DSMR_EXTRA_DEVICE_CHANNEL_CHOICES = ( + (DSMR_EXTRA_DEVICE_CHANNEL_AUTO, _("Auto (default)")), + (DSMR_EXTRA_DEVICE_CHANNEL_1, _("Belgium - Fluvius (channel 1)")), + (DSMR_EXTRA_DEVICE_CHANNEL_2, _("Belgium - Fluvius (channel 2)")), + (DSMR_EXTRA_DEVICE_CHANNEL_3, _("Belgium - Fluvius (channel 3)")), + (DSMR_EXTRA_DEVICE_CHANNEL_4, _("Belgium - Fluvius (channel 4)")), + ) + input_method = models.CharField( max_length=16, default=INPUT_METHOD_SERIAL, @@ -38,9 +51,19 @@ class DataloggerSettings(ModelUpdateMixin, SingletonModel): dsmr_version = models.IntegerField( default=DSMR_VERSION_4_PLUS, choices=DSMR_VERSION_CHOICES, - verbose_name=_("DSMR version"), + verbose_name=_("DSMR version/vendor"), + help_text=_( + "The DSMR version your meter supports or the vendor related to it. Version should be printed on meter." + ), + ) + dsmr_extra_device_channel = models.IntegerField( + default=None, + blank=True, + null=True, + choices=DSMR_EXTRA_DEVICE_CHANNEL_CHOICES, + verbose_name=_("Extra device channel"), help_text=_( - "The DSMR version your meter supports. Version should be printed on meter." + "Only use when your extra device is read incorrectly (e.g. gas). Also, only works with specific vendor(s)." ), ) serial_port = models.CharField( diff --git a/dsmr_datalogger/services/datalogger.py b/dsmr_datalogger/services/datalogger.py index da2c44aae..d1b071d49 100644 --- a/dsmr_datalogger/services/datalogger.py +++ b/dsmr_datalogger/services/datalogger.py @@ -108,7 +108,7 @@ def _map_telegram_to_model(parsed_telegram: Dict, data: str): datalogger_settings = DataloggerSettings.get_solo() model_fields = {k: None for k in READING_FIELDS + STATISTICS_FIELDS} - mapping = _get_dsmrreader_mapping(datalogger_settings.dsmr_version) + mapping = _get_dsmrreader_mapping(datalogger_settings) for obis_ref, obis_data in parsed_telegram.items(): try: @@ -188,7 +188,7 @@ def _map_telegram_to_model(parsed_telegram: Dict, data: str): return new_instance -def _get_dsmrreader_mapping(version: int) -> Dict: +def _get_dsmrreader_mapping(datalogger_settings: DataloggerSettings) -> Dict: """Returns the mapping for OBIS to DSMR-reader (model fields).""" SPLIT_GAS_FIELD = { "value": "extra_device_delivered", @@ -232,14 +232,25 @@ def _get_dsmrreader_mapping(version: int) -> Dict: obis_references.VOLTAGE_SWELL_L3_COUNT: "voltage_swell_count_l3", } - if version == DataloggerSettings.DSMR_BELGIUM_FLUVIUS: + if datalogger_settings.dsmr_version == DataloggerSettings.DSMR_BELGIUM_FLUVIUS: + # Cheap hack for forcing channel selection. + try: + mbus_reference = { + DataloggerSettings.DSMR_EXTRA_DEVICE_CHANNEL_1: obis_references.BELGIUM_MBUS1_METER_READING2, + DataloggerSettings.DSMR_EXTRA_DEVICE_CHANNEL_2: obis_references.BELGIUM_MBUS2_METER_READING2, + DataloggerSettings.DSMR_EXTRA_DEVICE_CHANNEL_3: obis_references.BELGIUM_MBUS3_METER_READING2, + DataloggerSettings.DSMR_EXTRA_DEVICE_CHANNEL_4: obis_references.BELGIUM_MBUS4_METER_READING2, + }[datalogger_settings.dsmr_extra_device_channel] + except KeyError: + mbus_reference = obis_references.BELGIUM_MBUS_WILDCARD_METER_READING2 + mapping.update( { - obis_references.BELGIUM_MBUS_WILDCARD_METER_READING2: SPLIT_GAS_FIELD, + mbus_reference: SPLIT_GAS_FIELD, } ) - if version == DataloggerSettings.DSMR_LUXEMBOURG_SMARTY: + if datalogger_settings.dsmr_version == DataloggerSettings.DSMR_LUXEMBOURG_SMARTY: mapping.update( { obis_references.ELECTRICITY_IMPORTED_TOTAL: "electricity_delivered_1", diff --git a/dsmr_datalogger/tests/datalogger/test_fluvius_multiple_gas_devices.py b/dsmr_datalogger/tests/datalogger/test_fluvius_multiple_gas_devices.py new file mode 100644 index 000000000..3b9dedea6 --- /dev/null +++ b/dsmr_datalogger/tests/datalogger/test_fluvius_multiple_gas_devices.py @@ -0,0 +1,124 @@ +from unittest import mock +from datetime import datetime +from decimal import Decimal + +from django.test import TestCase +from django.utils import timezone +import pytz + +from dsmr_backend.tests.mixins import InterceptCommandStdoutMixin +from dsmr_datalogger.models.reading import DsmrReading +from dsmr_datalogger.models.statistics import MeterStatistics +from dsmr_datalogger.models.settings import DataloggerSettings +from dsmr_datalogger.tests.datalogger.mixins import FakeDsmrReadingMixin + + +class TestDatalogger(FakeDsmrReadingMixin, InterceptCommandStdoutMixin, TestCase): + """Belgium Fluvius meter (polyphase) with two gas devices (one inactive).""" + + def setUp(self): + DataloggerSettings.get_solo() + DataloggerSettings.objects.all().update( + dsmr_version=DataloggerSettings.DSMR_BELGIUM_FLUVIUS, + dsmr_extra_device_channel=DataloggerSettings.DSMR_EXTRA_DEVICE_CHANNEL_1, + ) + + def _dsmr_dummy_data(self): + return [ + "/FLU5\253769484_A\r\n", + "\r\n", + "0-0:96.1.4(012345678901234567890123456789)\r\n", + "0-0:96.1.1(012345678901234567890123456789)\r\n", + "0-0:1.0.0(230119124638W)\r\n", + "1-0:1.8.1(004423.770*kWh)\r\n", + "1-0:1.8.2(002607.237*kWh)\r\n", + "1-0:2.8.1(001194.693*kWh)\r\n", + "1-0:2.8.2(000755.554*kWh)\r\n", + "0-0:96.14.0(0001)\r\n", + "1-0:1.4.0(00.000*kW)\r\n", + "1-0:1.6.0(230116090000W)(11.173*kW)\r\n", + "0-0:98.1.0(1)(1-0:1.6.0)(1-0:1.6.0)(230101000000W)(221230114500W)(13.603*kW)\r\n", + "1-0:1.7.0(00.000*kW)\r\n", + "1-0:2.7.0(00.204*kW)\r\n", + "1-0:21.7.0(00.000*kW)\r\n", + "1-0:41.7.0(00.177*kW)\r\n", + "1-0:61.7.0(00.109*kW)\r\n", + "1-0:22.7.0(00.491*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.3*V)\r\n", + "1-0:52.7.0(234.2*V)\r\n", + "1-0:72.7.0(234.3*V)\r\n", + "1-0:31.7.0(002.18*A)\r\n", + "1-0:51.7.0(000.93*A)\r\n", + "1-0:71.7.0(000.60*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", + # Active gas device + "0-1:24.1.0(003)\r\n", + "0-1:96.1.1(012345678901234567890123456789)\r\n", + "0-1:24.4.0(1)\r\n", + "0-1:24.2.3(230119124616W)(00734.607*m3)\r\n", + # Inactive/stale gas device + "0-2:24.1.0(003)\r\n", + "0-2:96.1.1(012345678901234567890123456789)\r\n", + "0-2:24.4.0(1)\r\n", + "0-2:24.2.3(230119124005W)(00000.000*m3)\r\n", + "!B315", + ] + + def test_reading_creation(self): + self.assertFalse(DsmrReading.objects.exists()) + self._fake_dsmr_reading() + self.assertTrue(DsmrReading.objects.exists()) + + @mock.patch("django.utils.timezone.now") + def test_reading_values(self, now_mock): + now_mock.return_value = timezone.make_aware(timezone.datetime(2023, 1, 20)) + self._fake_dsmr_reading() + self.assertTrue(DsmrReading.objects.exists()) + reading = DsmrReading.objects.get() + self.assertEqual( + reading.timestamp, datetime(2023, 1, 19, 11, 46, 38, tzinfo=pytz.UTC) + ) + self.assertEqual(reading.electricity_delivered_1, Decimal("4423.770")) + self.assertEqual(reading.electricity_returned_1, Decimal("1194.693")) + self.assertEqual(reading.electricity_delivered_2, Decimal("2607.237")) + self.assertEqual(reading.electricity_returned_2, Decimal("755.554")) + self.assertEqual(reading.electricity_currently_delivered, Decimal("0")) + self.assertEqual(reading.electricity_currently_returned, Decimal("0.204")) + self.assertEqual( + reading.extra_device_timestamp, + datetime(2023, 1, 19, 11, 46, 16, tzinfo=pytz.UTC), + ) + self.assertEqual(reading.extra_device_delivered, Decimal("734.607")) + self.assertEqual(reading.phase_voltage_l1, Decimal("234.3")) + self.assertEqual(reading.phase_voltage_l2, Decimal("234.2")) + self.assertEqual(reading.phase_voltage_l3, Decimal("234.3")) + self.assertEqual(reading.phase_power_current_l1, 2) + self.assertEqual(reading.phase_power_current_l2, 0) + self.assertEqual(reading.phase_power_current_l3, 0) + + meter_statistics = MeterStatistics.get_solo() + self.assertIsNone(meter_statistics.dsmr_version) + self.assertEqual(meter_statistics.electricity_tariff, 1) + self.assertEqual(meter_statistics.power_failure_count, None) + self.assertEqual(meter_statistics.long_power_failure_count, None) + self.assertEqual(meter_statistics.voltage_sag_count_l1, None) + self.assertEqual(meter_statistics.voltage_sag_count_l2, None) + self.assertEqual(meter_statistics.voltage_sag_count_l3, None) + self.assertEqual(meter_statistics.voltage_swell_count_l1, None) + self.assertEqual(meter_statistics.voltage_swell_count_l2, None) + self.assertEqual(meter_statistics.voltage_swell_count_l3, None) + + # @mock.patch("django.utils.timezone.now") + # def test_telegram_override_timestamp(self, now_mock): + # reading = self._reading_with_override_telegram_timestamp_active(now_mock) + # + # self.assertEqual( + # # CET > UTC. Minute marker rounded to hours. Because Fluvius may or may not communicate DSMR v5 in telegrams + # reading.extra_device_timestamp, + # datetime(2021, 1, 15, 11, 0, 0, 0, tzinfo=pytz.UTC), + # ) diff --git a/dsmrreader/locales/nl/LC_MESSAGES/django.mo b/dsmrreader/locales/nl/LC_MESSAGES/django.mo index 175e1cc9cc6c181326598c1b4c710b3647053c0f..70dfdde654e40d1380554074eb9ed39a24dc3858 100644 GIT binary patch delta 20453 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 LD{HbVvhn`|$5%(J delta 19691 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 z%0D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\n" "Language-Team: Dennis Siemensma \n" @@ -711,17 +711,38 @@ msgstr "België - Fluvius (fix voor gasmeter)" msgid "Luxembourg - Smarty (single tariff fix)" msgstr "Luxemburg - Smarty (fix voor enkel tarief)" +msgid "Auto (default)" +msgstr "Automatisch (standaard)" + +msgid "Belgium - Fluvius (channel 1)" +msgstr "België - Fluvius (kanaal 1)" + +msgid "Belgium - Fluvius (channel 2)" +msgstr "België - Fluvius (kanaal 2)" + +msgid "Belgium - Fluvius (channel 3)" +msgstr "België - Fluvius (kanaal 3)" + +msgid "Belgium - Fluvius (channel 4)" +msgstr "België - Fluvius (kanaal 4)" + msgid "Input method" msgstr "Uitleesmethode" msgid "Whether to read telegrams from a serial port or network socket." msgstr "Geeft aan of telegrammen uitgelezen worden via een seriële poort of netwerk socket." -msgid "DSMR version" -msgstr "DSMR-versie" +msgid "DSMR version/vendor" +msgstr "DSMR-versie/fabrikant" + +msgid "The DSMR version your meter supports or the vendor related to it. Version should be printed on meter." +msgstr "De DSMR-versie ondersteund door je meter, of de fabrikant. Versie staat meestal aangegeven op de meter." + +msgid "Extra device channel" +msgstr "Kanaal extra gekoppeld apparaat" -msgid "The DSMR version your meter supports. Version should be printed on meter." -msgstr "De DSMR-versie ondersteund door je meter. Versie staat meestal aangegeven op de meter." +msgid "Only use when your extra device is read incorrectly (e.g. gas). Also, only works with specific vendor(s)." +msgstr "Alleen gebruiken wanneer een extra gekoppeld apparaat (zoals een gasmeter) niet goed uitgelezen wordt. Werkt daarnaast alleen voor specifieke fabrikant(en)." msgid "For serial input: Serial port connected to smartmeter. E.g.: /dev/ttyUSB0" msgstr "Voor uitlezen via een seriële poort: De seriële poort verbonden met de slimme meter. Bijvoorbeeld: /dev/ttyUSB0" @@ -786,6 +807,9 @@ msgstr "Retentieconfiguratie" msgid "Timestamp indicating when the reading was taken" msgstr "Moment waarop de meting is gedaan" +msgid "DSMR version" +msgstr "DSMR-versie" + msgid "Tariff indicator electricity. The tariff indicator can be used to switch tariff dependent loads e.g boilers. This is responsibility of the P1 user." msgstr "Tariefindicatie. Dit kan gebruikt worden om te wisselen met tariefafhankelijke vraag, zoals bijvoorbeeld een boiler. Verantwoording is voor de gebruiker van de P1-poort."