diff --git a/environment.yml b/environment.yml
index 325f1dc2..ab545c1d 100644
--- a/environment.yml
+++ b/environment.yml
@@ -41,7 +41,7 @@ dependencies:
- aioca
- aiokafka
- asynctest
- - apsbss
+ - apsbss < 2.0
- time-machine
- rich
- autoapi
diff --git a/src/firefly/tests/test_voltmeters.py b/src/firefly/tests/test_voltmeters.py
index a1b2fc57..afd68b30 100644
--- a/src/firefly/tests/test_voltmeters.py
+++ b/src/firefly/tests/test_voltmeters.py
@@ -1,5 +1,8 @@
+import asyncio
+
import pytest
from bluesky_queueserver_api import BPlan
+from ophyd_async.core import Device
from pydm import widgets as PyDMWidgets
from pydm.widgets.analog_indicator import PyDMAnalogIndicator
from qtpy import QtWidgets
@@ -28,6 +31,19 @@ async def ion_chambers(sim_registry):
return devices
+@pytest.fixture()
+async def shutters(sim_registry):
+ front_end_shutter = Device(name="front_end_shutter")
+ front_end_shutter.allow_close = False
+ endstation_shutter = Device(name="endstation_shutter")
+ shutters = [front_end_shutter, endstation_shutter]
+ await asyncio.gather(*[d.connect(mock=True) for d in shutters])
+ for shutter in shutters:
+ shutter._ophyd_labels_ = {"shutters"}
+ sim_registry.register(shutter)
+ return shutters
+
+
@pytest.fixture()
async def voltmeters_display(qtbot, ion_chambers, sim_registry):
vms_display = VoltmetersDisplay()
@@ -151,14 +167,66 @@ def check_item(item):
display.ui.auto_gain_button.click()
+async def test_shutters_checkbox_no_shutters(voltmeters_display, sim_registry):
+ display = voltmeters_display
+ combobox = display.ui.shutter_combobox
+ checkbox = display.ui.shutter_checkbox
+ checkbox.setChecked(True)
+ # Update the state of the UI with no shutters
+ await display.update_devices(sim_registry)
+ # Ensure checkbox has been disabled
+ assert not checkbox.isEnabled()
+ assert not checkbox.checkState()
+ assert not display.ui.shutter_checkbox.setChecked(True)
+ combobox_items = [combobox.itemText(idx) for idx in range(combobox.count())]
+ assert len(combobox_items) == 0
+
+
+async def test_shutters_checkbox_with_shutters(
+ voltmeters_display,
+ sim_registry,
+ shutters,
+):
+ display = voltmeters_display
+ checkbox = display.ui.shutter_checkbox
+ combobox = display.ui.shutter_combobox
+ # Update the state of the UI with no shutters
+ await display.update_devices(sim_registry)
+ # Ensure checkbox has been enabled
+ assert checkbox.isEnabled()
+ # Check that shutters were added to the combobox
+ combobox_items = [combobox.itemText(idx) for idx in range(combobox.count())]
+ assert "front_end_shutter" not in combobox_items
+ assert "endstation_shutter" in combobox_items
+
+
@pytest.mark.asyncio
async def test_read_dark_current_plan(voltmeters_display, qtbot):
+ display = voltmeters_display
+ display.ui.shutter_checkbox.setChecked(False)
+ # Check that the correct plan was sent
+ expected_item = BPlan("record_dark_current", ["I0", "It"])
+
+ def check_item(item):
+ return item.to_dict() == expected_item.to_dict()
+
+ # Click the run button and see if the plan is queued
+ with qtbot.waitSignal(
+ display.queue_item_submitted, timeout=1000, check_params_cb=check_item
+ ):
+ # Simulate clicking on the dark_current button
+ # display.ui.dark_current_button.click()
+ display.ui.record_dark_current()
+
+
+@pytest.mark.asyncio
+async def test_read_dark_current_plan_with_shutters(voltmeters_display, qtbot):
display = voltmeters_display
display.ui.shutter_checkbox.setChecked(True)
+ display.ui.shutter_combobox.setCurrentIndex(1)
# Check that the correct plan was sent
- expected_item = BPlan(
- "record_dark_current", ["I0", "It"], shutters=["experiment_shutter"]
- )
+ shutter_name = display.ui.shutter_combobox.itemText(1)
+ expected_item = BPlan("record_dark_current", ["I0", "It"], shutters=[shutter_name])
def check_item(item):
return item.to_dict() == expected_item.to_dict()
diff --git a/src/firefly/voltmeters.py b/src/firefly/voltmeters.py
index 15772899..e0e56fba 100644
--- a/src/firefly/voltmeters.py
+++ b/src/firefly/voltmeters.py
@@ -71,6 +71,28 @@ async def update_devices(self, registry):
# Connect the details button signal
details_slot = partial(self.details_window_requested.emit, ic.name)
row.details_button.clicked.connect(details_slot)
+ # Remove old shutters from the combobox
+ for idx in range(self.ui.shutter_combobox.count()):
+ self.ui.shutter_combobox.removeItem(idx)
+
+ # Decide which shutters we should show (only those that can be opened/closed)
+ def is_controllable(shtr):
+ can_open = getattr(shtr, "allow_open", True)
+ can_close = getattr(shtr, "allow_close", True)
+ return can_open and can_close
+
+ shutters = registry.findall("shutters", allow_none=True)
+ shutters = [shtr for shtr in shutters if is_controllable(shtr)]
+ has_shutters = bool(len(shutters))
+ # Add the shutters to the shutter combobox
+ if has_shutters:
+ self.ui.shutter_checkbox.setEnabled(True)
+ for shutter in shutters:
+ self.ui.shutter_combobox.addItem(shutter.name)
+ else:
+ log.warning("No shutters found, disabling checkbox.")
+ self.ui.shutter_checkbox.setEnabled(False)
+ self.ui.shutter_checkbox.setCheckState(False)
def update_queue_status(self, status):
super().update_queue_status(status)
@@ -104,12 +126,13 @@ def record_dark_current(self):
"""
# Determine which shutters to close
- shutters = []
+ kwargs = {}
if self.ui.shutter_checkbox.isChecked():
- shutters.append("experiment_shutter")
+ shutter_name = self.ui.shutter_combobox.currentText()
+ kwargs["shutters"] = [shutter_name]
# Construct the plan
ic_names = [ic.name for ic in self.ion_chambers]
- item = BPlan("record_dark_current", ic_names, shutters=shutters)
+ item = BPlan("record_dark_current", ic_names, **kwargs)
# Send it to the queue server
self.queue_item_submitted.emit(item)
diff --git a/src/firefly/voltmeters.ui b/src/firefly/voltmeters.ui
index c391a414..89b786a4 100644
--- a/src/firefly/voltmeters.ui
+++ b/src/firefly/voltmeters.ui
@@ -87,7 +87,7 @@
-
- false
+ true
<html><head/><body><p>Close the experimental experimental hutch shutter prior to recording dark current. </p><p><br/></p><p><span style=" font-weight:600;">This feature is disabled pending availability of shutter controls.</span></p></body></html>
@@ -103,6 +103,13 @@
+ -
+
+
+ false
+
+
+
-
@@ -224,5 +231,22 @@
-
+
+
+ shutter_checkbox
+ toggled(bool)
+ shutter_combobox
+ setEnabled(bool)
+
+
+ 157
+ 53
+
+
+ 249
+ 53
+
+
+
+