Add HIOKI channel range controls and live range display
- GUI: voltage/current range selectors for Ch5 and Ch6 with AUTO option - Worker: queries current V/I ranges each poll cycle, pushes to GUI - Setting a fixed range automatically disables auto-range for that channel - Live display shows current range values below each channel's readout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -381,6 +381,11 @@ class TestbenchGUI(tk.Tk):
|
||||
self._meter_fmt_combo.pack(side=tk.LEFT, padx=2)
|
||||
self._meter_fmt_combo.bind("<<ComboboxSelected>>", self._on_meter_fmt_change)
|
||||
|
||||
# Voltage ranges: 6,15,30,60,150,300,600,1000
|
||||
v_ranges = ["AUTO", "6", "15", "30", "60", "150", "300", "600", "1000"]
|
||||
# Current ranges depend on clamp sensor; common values
|
||||
i_ranges = ["AUTO", "0.5", "1", "2", "5", "10", "20", "50", "100", "200", "500", "1000"]
|
||||
|
||||
# Input side
|
||||
input_frame = ttk.LabelFrame(frame, text="Input (Ch5 - Solar)", padding=4)
|
||||
input_frame.pack(fill=tk.X, pady=2)
|
||||
@@ -390,6 +395,23 @@ class TestbenchGUI(tk.Tk):
|
||||
self._m_i5.pack(anchor=tk.W)
|
||||
self._m_p5 = ttk.Label(input_frame, text="P5: ---", font=("Consolas", 11))
|
||||
self._m_p5.pack(anchor=tk.W)
|
||||
# Ch5 ranges
|
||||
rng5 = ttk.Frame(input_frame)
|
||||
rng5.pack(fill=tk.X, pady=(4, 0))
|
||||
ttk.Label(rng5, text="V range:").pack(side=tk.LEFT)
|
||||
self._ch5_v_range = ttk.Combobox(rng5, values=v_ranges, width=6, state="readonly")
|
||||
self._ch5_v_range.set("AUTO")
|
||||
self._ch5_v_range.pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(rng5, text="Set", width=3,
|
||||
command=lambda: self._set_range(5, "V", self._ch5_v_range)).pack(side=tk.LEFT)
|
||||
ttk.Label(rng5, text=" I range:").pack(side=tk.LEFT)
|
||||
self._ch5_i_range = ttk.Combobox(rng5, values=i_ranges, width=6, state="readonly")
|
||||
self._ch5_i_range.set("AUTO")
|
||||
self._ch5_i_range.pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(rng5, text="Set", width=3,
|
||||
command=lambda: self._set_range(5, "I", self._ch5_i_range)).pack(side=tk.LEFT)
|
||||
self._ch5_range_label = ttk.Label(input_frame, text="V: --- / I: ---", font=("Consolas", 9))
|
||||
self._ch5_range_label.pack(anchor=tk.W)
|
||||
|
||||
# Output side
|
||||
output_frame = ttk.LabelFrame(frame, text="Output (Ch6 - MPPT)", padding=4)
|
||||
@@ -400,6 +422,23 @@ class TestbenchGUI(tk.Tk):
|
||||
self._m_i6.pack(anchor=tk.W)
|
||||
self._m_p6 = ttk.Label(output_frame, text="P6: ---", font=("Consolas", 11))
|
||||
self._m_p6.pack(anchor=tk.W)
|
||||
# Ch6 ranges
|
||||
rng6 = ttk.Frame(output_frame)
|
||||
rng6.pack(fill=tk.X, pady=(4, 0))
|
||||
ttk.Label(rng6, text="V range:").pack(side=tk.LEFT)
|
||||
self._ch6_v_range = ttk.Combobox(rng6, values=v_ranges, width=6, state="readonly")
|
||||
self._ch6_v_range.set("AUTO")
|
||||
self._ch6_v_range.pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(rng6, text="Set", width=3,
|
||||
command=lambda: self._set_range(6, "V", self._ch6_v_range)).pack(side=tk.LEFT)
|
||||
ttk.Label(rng6, text=" I range:").pack(side=tk.LEFT)
|
||||
self._ch6_i_range = ttk.Combobox(rng6, values=i_ranges, width=6, state="readonly")
|
||||
self._ch6_i_range.set("AUTO")
|
||||
self._ch6_i_range.pack(side=tk.LEFT, padx=2)
|
||||
ttk.Button(rng6, text="Set", width=3,
|
||||
command=lambda: self._set_range(6, "I", self._ch6_i_range)).pack(side=tk.LEFT)
|
||||
self._ch6_range_label = ttk.Label(output_frame, text="V: --- / I: ---", font=("Consolas", 9))
|
||||
self._ch6_range_label.pack(anchor=tk.W)
|
||||
|
||||
# Efficiency - big and bold
|
||||
eff_frame = ttk.Frame(frame)
|
||||
@@ -803,6 +842,18 @@ class TestbenchGUI(tk.Tk):
|
||||
else:
|
||||
self._load_state_label.config(text="LOAD: ---", fg="#888888")
|
||||
|
||||
# Meter channel ranges
|
||||
vr5 = data.get("v_range_5")
|
||||
ir5 = data.get("i_range_5")
|
||||
self._ch5_range_label.config(
|
||||
text=f"V: {vr5 or '---'} / I: {ir5 or '---'}"
|
||||
)
|
||||
vr6 = data.get("v_range_6")
|
||||
ir6 = data.get("i_range_6")
|
||||
self._ch6_range_label.config(
|
||||
text=f"V: {vr6 or '---'} / I: {ir6 or '---'}"
|
||||
)
|
||||
|
||||
def _update_graphs(self, data: dict) -> None:
|
||||
"""Append data to series and redraw graphs."""
|
||||
now = time.time() - self._t0
|
||||
@@ -839,6 +890,20 @@ class TestbenchGUI(tk.Tk):
|
||||
return _fmt_eng(val)
|
||||
return _fmt(val, decimals=4)
|
||||
|
||||
def _set_range(self, channel: int, vi: str, combo: ttk.Combobox) -> None:
|
||||
"""Set voltage or current range for a HIOKI channel."""
|
||||
val = combo.get()
|
||||
if val == "AUTO":
|
||||
if vi == "V":
|
||||
self._send(Cmd.SET_VOLTAGE_AUTO, channel, True)
|
||||
else:
|
||||
self._send(Cmd.SET_CURRENT_AUTO, channel, True)
|
||||
else:
|
||||
if vi == "V":
|
||||
self._send(Cmd.SET_VOLTAGE_RANGE, channel, int(val))
|
||||
else:
|
||||
self._send(Cmd.SET_CURRENT_RANGE, channel, float(val))
|
||||
|
||||
# ── Command Helpers ───────────────────────────────────────────────
|
||||
|
||||
def _send(self, cmd: Cmd, *args) -> None:
|
||||
|
||||
@@ -39,6 +39,10 @@ class Cmd(Enum):
|
||||
SET_COUPLING = auto()
|
||||
SET_RESPONSE_SPEED = auto()
|
||||
SET_AVERAGING = auto()
|
||||
SET_VOLTAGE_RANGE = auto()
|
||||
SET_CURRENT_RANGE = auto()
|
||||
SET_VOLTAGE_AUTO = auto()
|
||||
SET_CURRENT_AUTO = auto()
|
||||
|
||||
# System
|
||||
SET_INTERVAL = auto()
|
||||
@@ -108,6 +112,16 @@ class InstrumentWorker(threading.Thread):
|
||||
data["load_on"] = self.bench.load.get_load_state()
|
||||
except Exception:
|
||||
data["load_on"] = None
|
||||
# Query meter channel ranges
|
||||
for ch in (5, 6):
|
||||
try:
|
||||
data[f"v_range_{ch}"] = self.bench.meter.get_voltage_range(ch).strip()
|
||||
except Exception:
|
||||
data[f"v_range_{ch}"] = None
|
||||
try:
|
||||
data[f"i_range_{ch}"] = self.bench.meter.get_current_range(ch).strip()
|
||||
except Exception:
|
||||
data[f"i_range_{ch}"] = None
|
||||
except Exception as e:
|
||||
data = {"_error": str(e), "_timestamp": time.time()}
|
||||
|
||||
@@ -181,6 +195,16 @@ class InstrumentWorker(threading.Thread):
|
||||
bench.meter.set_response_speed(args[0])
|
||||
case Cmd.SET_AVERAGING:
|
||||
bench.meter.set_averaging(args[0], args[1] if len(args) > 1 else None)
|
||||
case Cmd.SET_VOLTAGE_RANGE:
|
||||
bench.meter.set_voltage_auto(args[0], False)
|
||||
bench.meter.set_voltage_range(args[0], args[1])
|
||||
case Cmd.SET_CURRENT_RANGE:
|
||||
bench.meter.set_current_auto(args[0], False)
|
||||
bench.meter.set_current_range(args[0], args[1])
|
||||
case Cmd.SET_VOLTAGE_AUTO:
|
||||
bench.meter.set_voltage_auto(args[0], args[1])
|
||||
case Cmd.SET_CURRENT_AUTO:
|
||||
bench.meter.set_current_auto(args[0], args[1])
|
||||
|
||||
# System
|
||||
case Cmd.SET_INTERVAL:
|
||||
|
||||
Reference in New Issue
Block a user