diff --git a/testbench/gui.py b/testbench/gui.py index 2972fec..d57e1e2 100644 --- a/testbench/gui.py +++ b/testbench/gui.py @@ -381,6 +381,11 @@ class TestbenchGUI(tk.Tk): self._meter_fmt_combo.pack(side=tk.LEFT, padx=2) self._meter_fmt_combo.bind("<>", 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: diff --git a/testbench/gui_workers.py b/testbench/gui_workers.py index 4f38fe4..b869994 100644 --- a/testbench/gui_workers.py +++ b/testbench/gui_workers.py @@ -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: