mirror of
https://github.com/NickoScope/nickol-knx-mcp.git
synced 2026-09-29 19:31:12 +02:00
fix(handover): read domain names from GroupRanges, not mislabeled GARecord.main_name
Main/middle range names now resolve correctly (e.g. [1] Освещение 1 этаж, [5] Климат) instead of a middle-group name leaking into the main. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a621ced701
commit
2f2b8b1f91
@@ -26,6 +26,12 @@ Zennio project (a 3646-GA multi-vendor villa, 5× larger, no ETS Functions).
|
||||
`Все шторы - Стоп`) surface as INFO `central_macro_no_status` instead of a
|
||||
`missing_status_address` warning, since a fan-out broadcast has no single state to read back.
|
||||
|
||||
### Fixed
|
||||
- **Handover domain names** — the group-address map now reads main/middle range names straight
|
||||
from the project's `GroupRanges` instead of `GARecord.main_name`, which the parser could
|
||||
mislabel (a middle range's name leaking into the main). Domains now render correctly
|
||||
(e.g. `[1] Освещение 1 этаж`, `[5] Климат`) instead of a middle-group name.
|
||||
|
||||
## [0.2.0] — 2026-06-30
|
||||
|
||||
**Colour/climate entity assembly and GA-intent noise reduction.** Two feature tracks
|
||||
|
||||
@@ -25,23 +25,41 @@ from .intent import INTENT_FUNCTIONAL
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Structure helpers
|
||||
# --------------------------------------------------------------------------- #
|
||||
def _range_names(project: LoadedProject) -> tuple[dict[int, str], dict[tuple[int, int], str]]:
|
||||
"""Authoritative main/middle names from the project's GroupRanges.
|
||||
|
||||
``GARecord.main_name`` from the parser can mislabel (it may carry a middle
|
||||
range's name), so the domain map reads names straight from ``group_ranges``.
|
||||
"""
|
||||
main_names: dict[int, str] = {}
|
||||
mid_names: dict[tuple[int, int], str] = {}
|
||||
for mkey, mrange in (project.raw.get("group_ranges") or {}).items():
|
||||
head = str(mkey).split("/")[0]
|
||||
if not head.isdigit():
|
||||
continue
|
||||
mi = int(head)
|
||||
main_names[mi] = mrange.get("name") or ""
|
||||
for skey, srange in (mrange.get("group_ranges") or {}).items():
|
||||
parts = str(skey).split("/")
|
||||
if len(parts) >= 2 and parts[1].isdigit():
|
||||
mid_names[(mi, int(parts[1]))] = srange.get("name") or ""
|
||||
return main_names, mid_names
|
||||
|
||||
|
||||
def _domain_map(project: LoadedProject) -> dict[int, dict[str, Any]]:
|
||||
"""main -> {name, count, middles: {middle -> {name, count}}}, sorted-ready."""
|
||||
main_names, mid_names = _range_names(project)
|
||||
mains: dict[int, dict[str, Any]] = {}
|
||||
for ga in project.gas.values():
|
||||
if ga.main is None:
|
||||
continue
|
||||
m = mains.setdefault(ga.main, {"name": ga.main_name or "", "count": 0, "middles": {}})
|
||||
m = mains.setdefault(
|
||||
ga.main, {"name": main_names.get(ga.main, ""), "count": 0, "middles": {}})
|
||||
m["count"] += 1
|
||||
if not m["name"] and ga.main_name:
|
||||
m["name"] = ga.main_name
|
||||
midkey = ga.middle if ga.middle is not None else -1
|
||||
mid = m["middles"].setdefault(
|
||||
ga.middle if ga.middle is not None else -1,
|
||||
{"name": ga.middle_name or "", "count": 0},
|
||||
)
|
||||
midkey, {"name": mid_names.get((ga.main, midkey), ""), "count": 0})
|
||||
mid["count"] += 1
|
||||
if not mid["name"] and ga.middle_name:
|
||||
mid["name"] = ga.middle_name
|
||||
return mains
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user