Fix live wiresheet config/runtime slot alignment and cap float display to 2 decimals

Slots with no flags (sensor, controlSignal, out_*) were not skipped
during config property reads, consuming bytes that the device never
sent and misaligning every subsequent config value (setpoint,
proportionalBand, etc.) into tiny denormalized floats like 2.36875e-41.

Changed the filter in _apply_props from "skip if runtime" to "skip if
not config" so only explicitly config-flagged slots are read from config
messages. Also switched iter("slot") to findall("slot") in the slot
registry builder to avoid picking up nested descendants.

Float display now defaults to 2 decimal places everywhere (wiresheet
and properties panel), honouring the precision facet when one exists.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-09-12 15:46:44 +03:00
co-authored by Claude Opus 4.6
parent 48671585dd
commit 6cd030c7ea
4 changed files with 28 additions and 15 deletions
+24 -10
View File
@@ -13,12 +13,22 @@ import schema
from sox import SoxClient, SoxComponent, TREE, CONFIG, RUNTIME, LINKS, ALL
def _fmt_float(val):
"""Format a 32-bit float for display: 6 significant digits, always with a decimal point."""
s = f"{val:.6g}"
if "." not in s and "e" not in s and "E" not in s:
s += ".0"
return s
def _fmt_float(val, precision=2):
"""Format a float for display with *precision* decimal places (default 2)."""
return f"{val:.{precision}f}"
def _slot_precision(type_name, slot_name):
"""Looks up the precision facet for a slot, returning 2 as the default."""
reg = app_state.final_components_registry.get(type_name)
if reg:
for s in reg:
if s["name"] == slot_name:
p = s.get("facets", {}).get("precision")
if isinstance(p, int) and 0 <= p <= 12:
return p
break
return 2
class DeviceSession:
@@ -100,7 +110,7 @@ class DeviceSession:
for type_elem in manifest.iter("type"):
if type_elem.get("name") == "Component":
slots = []
for slot_elem in type_elem.iter("slot"):
for slot_elem in type_elem.findall("slot"):
slot_name = slot_elem.get("name", "")
slot_id = int(slot_elem.get("id", "-1"))
slot_type = slot_elem.get("type", "int")
@@ -127,7 +137,7 @@ class DeviceSession:
if type_id_val < 0:
continue
slots = []
for slot_elem in type_elem.iter("slot"):
for slot_elem in type_elem.findall("slot"):
slot_name = slot_elem.get("name", "")
slot_id = int(slot_elem.get("id", "-1"))
slot_type = slot_elem.get("type", "int")
@@ -276,7 +286,7 @@ class DeviceSession:
if name in sox_comp.values:
val = sox_comp.values[name]
if isinstance(val, float):
val_str = _fmt_float(val)
val_str = _fmt_float(val, _slot_precision(type_qname, name))
else:
val_str = str(val)
ET.SubElement(comp_elem, "prop",
@@ -364,6 +374,7 @@ class DeviceSession:
if comp_elem is None:
return None
type_name = sox_comp.type_name
slots = self.sox_client.slot_registry.get(
(sox_comp.kit_id, sox_comp.type_id))
if slots:
@@ -374,7 +385,10 @@ class DeviceSession:
name = slot["name"]
if name in sox_comp.values:
raw = sox_comp.values[name]
val = _fmt_float(raw) if isinstance(raw, float) else str(raw)
if isinstance(raw, float):
val = _fmt_float(raw, _slot_precision(type_name, name))
else:
val = str(raw)
if name in existing_props:
existing_props[name].set("val", val)
else: