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
+1 -1
View File
@@ -8,7 +8,7 @@ so later rebinding would only ever be seen by the module that did it.
import configparser import configparser
import os import os
VERSION = "0.0.0.089" VERSION = "0.0.0.092"
PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties") PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties")
DEFAULT_GRID_SIZE = 10 DEFAULT_GRID_SIZE = 10
DEFAULT_ADD_TIMESTAMP = True DEFAULT_ADD_TIMESTAMP = True
+24 -10
View File
@@ -13,12 +13,22 @@ import schema
from sox import SoxClient, SoxComponent, TREE, CONFIG, RUNTIME, LINKS, ALL from sox import SoxClient, SoxComponent, TREE, CONFIG, RUNTIME, LINKS, ALL
def _fmt_float(val): def _fmt_float(val, precision=2):
"""Format a 32-bit float for display: 6 significant digits, always with a decimal point.""" """Format a float for display with *precision* decimal places (default 2)."""
s = f"{val:.6g}" return f"{val:.{precision}f}"
if "." not in s and "e" not in s and "E" not in s:
s += ".0"
return s 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: class DeviceSession:
@@ -100,7 +110,7 @@ class DeviceSession:
for type_elem in manifest.iter("type"): for type_elem in manifest.iter("type"):
if type_elem.get("name") == "Component": if type_elem.get("name") == "Component":
slots = [] slots = []
for slot_elem in type_elem.iter("slot"): for slot_elem in type_elem.findall("slot"):
slot_name = slot_elem.get("name", "") slot_name = slot_elem.get("name", "")
slot_id = int(slot_elem.get("id", "-1")) slot_id = int(slot_elem.get("id", "-1"))
slot_type = slot_elem.get("type", "int") slot_type = slot_elem.get("type", "int")
@@ -127,7 +137,7 @@ class DeviceSession:
if type_id_val < 0: if type_id_val < 0:
continue continue
slots = [] slots = []
for slot_elem in type_elem.iter("slot"): for slot_elem in type_elem.findall("slot"):
slot_name = slot_elem.get("name", "") slot_name = slot_elem.get("name", "")
slot_id = int(slot_elem.get("id", "-1")) slot_id = int(slot_elem.get("id", "-1"))
slot_type = slot_elem.get("type", "int") slot_type = slot_elem.get("type", "int")
@@ -276,7 +286,7 @@ class DeviceSession:
if name in sox_comp.values: if name in sox_comp.values:
val = sox_comp.values[name] val = sox_comp.values[name]
if isinstance(val, float): if isinstance(val, float):
val_str = _fmt_float(val) val_str = _fmt_float(val, _slot_precision(type_qname, name))
else: else:
val_str = str(val) val_str = str(val)
ET.SubElement(comp_elem, "prop", ET.SubElement(comp_elem, "prop",
@@ -364,6 +374,7 @@ class DeviceSession:
if comp_elem is None: if comp_elem is None:
return None return None
type_name = sox_comp.type_name
slots = self.sox_client.slot_registry.get( slots = self.sox_client.slot_registry.get(
(sox_comp.kit_id, sox_comp.type_id)) (sox_comp.kit_id, sox_comp.type_id))
if slots: if slots:
@@ -374,7 +385,10 @@ class DeviceSession:
name = slot["name"] name = slot["name"]
if name in sox_comp.values: if name in sox_comp.values:
raw = sox_comp.values[name] 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: if name in existing_props:
existing_props[name].set("val", val) existing_props[name].set("val", val)
else: else:
+1 -1
View File
@@ -374,7 +374,7 @@ def display_text(slot, raw):
precision = slot["facets"].get("precision") precision = slot["facets"].get("precision")
if isinstance(precision, int) and 0 <= precision <= 12: if isinstance(precision, int) and 0 <= precision <= 12:
return f"{number:.{precision}f}" return f"{number:.{precision}f}"
return str(number) return f"{number:.2f}"
if slot_type in INTEGER_TYPES: if slot_type in INTEGER_TYPES:
try: try:
+2 -3
View File
@@ -831,9 +831,8 @@ class SoxClient:
continue continue
if operator_only and not slot.get("is_operator"): if operator_only and not slot.get("is_operator"):
continue continue
is_config = slot.get("is_config", True) is_config = slot.get("is_config", False)
is_runtime = slot.get("is_runtime", False) if what_char == 'c' and not is_config:
if what_char == 'c' and is_runtime:
continue continue
if what_char == 'r' and is_config: if what_char == 'r' and is_config:
continue continue