From ad48aaee566dd1d2d9ad69c73757526bc9b2d460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20P=C3=A9rez?= Date: Fri, 5 Jun 2026 00:30:54 -0400 Subject: [PATCH] fix(config): accept numeric MMDVM option fields in YAML Validate RX_FREQ, SLOTS, lat/long, etc. as int/float instead of requiring strings. Fixes parrot startup when YAML uses unquoted numbers. --- adn-parrot.example.yaml | 4 +- .../infrastructure/config_validator.py | 42 +++++++++++++++---- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/adn-parrot.example.yaml b/adn-parrot.example.yaml index aa86981..5b08c7a 100644 --- a/adn-parrot.example.yaml +++ b/adn-parrot.example.yaml @@ -66,8 +66,8 @@ SYSTEMS: TX_POWER: 25 COLORCODE: 1 SLOTS: 2 - LATITUDE: "00.0000" - LONGITUDE: "000.0000" + LATITUDE: 0 + LONGITUDE: 0 HEIGHT: 0 LOCATION: "9990 Parrot" DESCRIPTION: ECHO diff --git a/src/adn_server/infrastructure/config_validator.py b/src/adn_server/infrastructure/config_validator.py index 455630b..3d14560 100644 --- a/src/adn_server/infrastructure/config_validator.py +++ b/src/adn_server/infrastructure/config_validator.py @@ -62,16 +62,8 @@ SYSTEM_STRING_KEYS = frozenset( "PASSPHRASE", "MASTER_IP", "CALLSIGN", - "RX_FREQ", - "TX_FREQ", - "TX_POWER", - "COLORCODE", - "LATITUDE", - "LONGITUDE", - "HEIGHT", "LOCATION", "DESCRIPTION", - "SLOTS", "URL", "SOFTWARE_ID", "PACKAGE_ID", @@ -120,6 +112,17 @@ def _expect_int(path: str, value: Any, errors: list[str]) -> None: errors.append(f"{path}: expected integer, got {type(value).__name__} ({value!r}).") +def _expect_number(path: str, value: Any, errors: list[str]) -> None: + if _is_empty(value): + return + if isinstance(value, bool): + errors.append(f"{path}: expected number, got boolean ({value!r}).") + return + if isinstance(value, (int, float)): + return + errors.append(f"{path}: expected number, got {type(value).__name__} ({value!r}).") + + def _section_string_keys(section_name: str, section: dict[str, Any], keys: frozenset[str], errors: list[str]) -> None: for key in keys: if key in section: @@ -181,9 +184,30 @@ def _validate_system(name: str, sys_cfg: dict[str, Any], errors: list[str]) -> N for key in ("ENABLED", "REPEAT", "USE_ACL", "SINGLE_MODE", "VOICE_IDENT", "ALLOW_UNREG_ID", "PROXY_CONTROL", "EXPORT_AMBE", "LOOSE", "RELAX_CHECKS", "ENHANCED_OBP", "BOTH_SLOTS"): if key in sys_cfg: _expect_bool(f"{prefix}.{key}", sys_cfg[key], errors) - for key in ("PORT", "MASTER_PORT", "MAX_PEERS", "GROUP_HANGTIME", "DEFAULT_UA_TIMER", "DEFAULT_REFLECTOR", "GENERATOR", "NETWORK_ID", "TARGET_PORT", "PROTO_VER", "RADIO_ID"): + for key in ( + "PORT", + "MASTER_PORT", + "MAX_PEERS", + "GROUP_HANGTIME", + "DEFAULT_UA_TIMER", + "DEFAULT_REFLECTOR", + "GENERATOR", + "NETWORK_ID", + "TARGET_PORT", + "PROTO_VER", + "RADIO_ID", + "RX_FREQ", + "TX_FREQ", + "TX_POWER", + "COLORCODE", + "SLOTS", + "HEIGHT", + ): if key in sys_cfg: _expect_int(f"{prefix}.{key}", sys_cfg[key], errors) + for key in ("LATITUDE", "LONGITUDE"): + if key in sys_cfg: + _expect_number(f"{prefix}.{key}", sys_cfg[key], errors) def validate_config(config: dict[str, Any], *, config_path: str | None = None) -> None: