From 1296773346af79987dc7cec6746675b1ee4b15fe Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 1 Sep 2026 21:32:56 +0300 Subject: [PATCH] feat(protocan): decode KONOR runtime settings --- python/protocan/protocan.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/python/protocan/protocan.py b/python/protocan/protocan.py index 94a7264..8a2789e 100644 --- a/python/protocan/protocan.py +++ b/python/protocan/protocan.py @@ -66,6 +66,7 @@ class SettingsResult(IntEnum): EEPROM_ERROR = 0x05 INVALID_LOCATION = 0x06 BUSY = 0x07 + INVALID_VALUE = 0x08 class BroadcastType(IntEnum): @@ -145,6 +146,7 @@ SETTINGS_RESULT_RU = { SettingsResult.EEPROM_ERROR: "ошибка EEPROM", SettingsResult.INVALID_LOCATION: "неверная локация", SettingsResult.BUSY: "устройство занято", + SettingsResult.INVALID_VALUE: "значение настройки вне диапазона", } BROADCAST_RU = { @@ -680,6 +682,30 @@ def _decode_settings(res: Decoded) -> None: (" SETTINGS.Position Y", "%d (0x%02X)" % (position, position)), ] + # Зарезервированная локация прибора KONOR: runtime-настройки не являются + # ROM датчика, хотя используют тот же однокадровый SETTINGS-транспорт. + if assembly == 0xFF and position == 0x01: + if res.dlc == 0 and res.id.pm == Route.FROM_PM: + res.summary = "SETTINGS RUNTIME GET" + return + if res.dlc == 8: + pulse_seconds = res.data[0] + led_hz = int.from_bytes(res.data[1:3], "little") + res.fields += [ + (" SETTINGS.Pulse period", + "%d s" % pulse_seconds if pulse_seconds else "выключен"), + (" SETTINGS.LED frequency", "%d Hz" % led_hz), + ] + if led_hz > 500: + res.warnings.append("Частота LED должна быть 0..500 Гц") + if any(res.data[3:]): + res.warnings.append("Резерв SETTINGS Data[3:8] должен быть нулевым") + direction = "WRITE" if res.id.pm == Route.FROM_PM else "RESPONSE" + period_text = "%d s" % pulse_seconds if pulse_seconds else "выключен" + res.summary = ("SETTINGS RUNTIME %s: PULSE %s, LED %d Hz" + % (direction, period_text, led_hz)) + return + if res.id.pm == Route.FROM_PM: if res.dlc == 0: operation = "GET"