From 12bf0c643572db6c3636c1689be2b1c581a33e02 Mon Sep 17 00:00:00 2001 From: Luis Segalla Date: Fri, 23 Jan 2026 11:28:28 +0000 Subject: [PATCH 1/6] Add commands to xspress_api and remove them from config tree --- python/src/xspress_detector/control/detector.py | 8 ++++++-- python/src/xspress_detector/control/xspress_api.py | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/python/src/xspress_detector/control/detector.py b/python/src/xspress_detector/control/detector.py index 2d8576a..3b2546d 100644 --- a/python/src/xspress_detector/control/detector.py +++ b/python/src/xspress_detector/control/detector.py @@ -379,6 +379,10 @@ def __init__( self.param["module"] = self._name + self.param[XspressApi.command_uri] = self.add_parameters( + MessageType.CMD, XspressApi.command_items, ParamAccess.WriteOnly, XspressApi.command_uri + ) + async def _get_value(self,path): return self._cache.get(path,None) @@ -531,8 +535,8 @@ async def reconfigure(self, *unused): resp = await self._async_client.send_recv(self.configuration.get_daq()) return resp - async def connect(self, *unused): - msg = _build_message(MessageType.CMD, {XspressDetectorStr.CMD_CONNECT: 1}) + async def connect(self, value: bool = True, *unused): + msg = _build_message(MessageType.CMD, {XspressDetectorStr.CMD_CONNECT: value}) return await self._async_client.send_recv(msg, timeout=20) async def acquire(self, value, *unused): diff --git a/python/src/xspress_detector/control/xspress_api.py b/python/src/xspress_detector/control/xspress_api.py index 85a4d81..e95931a 100644 --- a/python/src/xspress_detector/control/xspress_api.py +++ b/python/src/xspress_detector/control/xspress_api.py @@ -5,6 +5,7 @@ class XspressApi: adapter_uri = "adapter" process_uri = "process" version_uri = "version" + command_uri = "command" daq_uri = "daq" app_uri = "app" @@ -104,5 +105,4 @@ class XspressApi: "patch": 0, "short": "", } - } - + } \ No newline at end of file From 8bd7d9cc3ae40f80214625829651af5502b82a86 Mon Sep 17 00:00:00 2001 From: Luis Segalla Date: Wed, 28 Jan 2026 10:38:50 +0000 Subject: [PATCH 2/6] Add new commands --- python/pyproject.toml | 2 +- .../src/xspress_detector/control/adapter.py | 5 ++- .../src/xspress_detector/control/detector.py | 36 +++++++++++-------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/python/pyproject.toml b/python/pyproject.toml index 3141568..c767f91 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -2,5 +2,5 @@ # To get a reproducible wheel, wheel must be pinned to the same version as in # dls-python3, and setuptools must produce the same dist-info. Cap setuptools # to the last version that didn't add License-File to METADATA -requires = ["setuptools<57", "wheel==0.33.1", "versioneer-518"] +requires = ["setuptools>=64", "wheel==0.33.1", "versioneer-518"] build-backend = "setuptools.build_meta" diff --git a/python/src/xspress_detector/control/adapter.py b/python/src/xspress_detector/control/adapter.py index e7a8718..50b3593 100644 --- a/python/src/xspress_detector/control/adapter.py +++ b/python/src/xspress_detector/control/adapter.py @@ -85,7 +85,10 @@ async def get(self, path, request): try: response = await self.detector.get(path) if not isinstance(response, dict): - response = {"value": response} + if "command" in path: + response = {path.split("/")[-1]: response} + else: + response = {"value": response} respose = "{}".format(response) status_code = 200 diff --git a/python/src/xspress_detector/control/detector.py b/python/src/xspress_detector/control/detector.py index 3b2546d..59994d5 100644 --- a/python/src/xspress_detector/control/detector.py +++ b/python/src/xspress_detector/control/detector.py @@ -379,9 +379,21 @@ def __init__( self.param["module"] = self._name - self.param[XspressApi.command_uri] = self.add_parameters( - MessageType.CMD, XspressApi.command_items, ParamAccess.WriteOnly, XspressApi.command_uri - ) + self.param["command"] = {"allowed": ["reconfigure","start_acquisition","stop_acquisition"], + "execute": ("", lambda name: self.run_command(name)) + } + + + async def run_command(self, name): + match name: + case "reconfigure": + await self.reconfigure(1) + case "start_acquisition": + await self.acquire(1) + case "stop_acquisition": + await self.acquire(0) + case _: + logging.error(f"Unsupported command {name}") async def _get_value(self,path): return self._cache.get(path,None) @@ -521,7 +533,7 @@ async def reconfigure(self, *unused): resp = await self._async_client.send_recv(self.configuration.get()) # resp = await self._put(MessageType.CONFIG, XspressDetectorStr.CONFIG_CONFIG_PATH, self.settings_paths[mode]) - resp = await self._put(MessageType.CMD, "config/disconnect", 1) # Here disconnect is inside config + resp = await self._put(MessageType.CMD, "command/disconnect", 1) # Here disconnect is inside config chans = self.mca_channels if mode == XSPRESS_MODE_MCA else self.mca_channels + 1 await self._put( MessageType.CONFIG, "config/max_channels", chans @@ -539,7 +551,7 @@ async def connect(self, value: bool = True, *unused): msg = _build_message(MessageType.CMD, {XspressDetectorStr.CMD_CONNECT: value}) return await self._async_client.send_recv(msg, timeout=20) - async def acquire(self, value, *unused): + async def acquire(self, value): if value: reply = await self._put(MessageType.CMD, XspressDetectorStr.CMD_START, 1) self.acquisition_complete = False @@ -566,7 +578,7 @@ async def do_updates(self, value: int): def _set(self, attr_name, value): setattr(self, attr_name, value) - async def _put(self, message_type: MessageType, config_str: str, value: any): + async def _put(self, message_type: MessageType, path: str, value: any): if not self._param_tree_waited: self.parameter_tree = await AsyncParameterTree(self.param) self._param_tree_waited = True @@ -577,11 +589,7 @@ async def _put(self, message_type: MessageType, config_str: str, value: any): "Control server is not connected! Check if it is running and tcp endpoint is configured correctly" ) - field, item = config_str.split("/") - - # For when commands are available - if field == "command": - return self.COMMANDS[item](self,value) + # field, item = path.split("/") if isinstance(value,list): index = 0 @@ -589,12 +597,12 @@ async def _put(self, message_type: MessageType, config_str: str, value: any): if value[i] != -1: index = i break - self._cache[config_str][index] = value[index] - msg = _build_message(message_type, {item: self._cache[config_str]}) + self._cache[path][index] = value[index] + msg = _build_message(message_type, {path: self._cache[path]}) resp = await self._async_client.send_recv(msg) return resp - msg = _build_message(message_type, {item: value}) + msg = _build_message(message_type, {path: value}) resp = await self._async_client.send_recv(msg) return resp From 9113181af00a188e4476467d0dfe1f4faa1f18a9 Mon Sep 17 00:00:00 2001 From: Luis Segalla Date: Wed, 28 Jan 2026 17:19:13 +0000 Subject: [PATCH 3/6] Update acquire method and _put --- python/src/xspress_detector/control/detector.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/src/xspress_detector/control/detector.py b/python/src/xspress_detector/control/detector.py index 59994d5..86e93b4 100644 --- a/python/src/xspress_detector/control/detector.py +++ b/python/src/xspress_detector/control/detector.py @@ -553,11 +553,11 @@ async def connect(self, value: bool = True, *unused): async def acquire(self, value): if value: - reply = await self._put(MessageType.CMD, XspressDetectorStr.CMD_START, 1) + reply = await self._put(MessageType.CMD, "command/start", 1) self.acquisition_complete = False return reply else: - return await self._put(MessageType.CMD, XspressDetectorStr.CMD_STOP, 1) + return await self._put(MessageType.CMD, "command/stop", 1) async def set_mode(self, value): if value == 0: @@ -589,7 +589,7 @@ async def _put(self, message_type: MessageType, path: str, value: any): "Control server is not connected! Check if it is running and tcp endpoint is configured correctly" ) - # field, item = path.split("/") + _, item = path.split("/") if isinstance(value,list): index = 0 @@ -598,11 +598,11 @@ async def _put(self, message_type: MessageType, path: str, value: any): index = i break self._cache[path][index] = value[index] - msg = _build_message(message_type, {path: self._cache[path]}) + msg = _build_message(message_type, {item: self._cache[path]}) resp = await self._async_client.send_recv(msg) return resp - msg = _build_message(message_type, {path: value}) + msg = _build_message(message_type, {item: value}) resp = await self._async_client.send_recv(msg) return resp From 33b6b6e7c1f33783d1cd6ac7f9678d7844517b0d Mon Sep 17 00:00:00 2001 From: Luis Segalla Date: Thu, 29 Jan 2026 11:46:05 +0000 Subject: [PATCH 4/6] Add trigger command --- python/src/xspress_detector/control/detector.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/src/xspress_detector/control/detector.py b/python/src/xspress_detector/control/detector.py index 86e93b4..a6e4beb 100644 --- a/python/src/xspress_detector/control/detector.py +++ b/python/src/xspress_detector/control/detector.py @@ -379,7 +379,7 @@ def __init__( self.param["module"] = self._name - self.param["command"] = {"allowed": ["reconfigure","start_acquisition","stop_acquisition"], + self.param["command"] = {"allowed": ["reconfigure","start_acquisition","stop_acquisition", "trigger"], "execute": ("", lambda name: self.run_command(name)) } @@ -392,6 +392,8 @@ async def run_command(self, name): await self.acquire(1) case "stop_acquisition": await self.acquire(0) + case "trigger": + await self.trigger() case _: logging.error(f"Unsupported command {name}") @@ -559,6 +561,9 @@ async def acquire(self, value): else: return await self._put(MessageType.CMD, "command/stop", 1) + async def trigger(self): + return await self._put(MessageType.CMD, "command/trigger", 1) + async def set_mode(self, value): if value == 0: return await self._put( From 1f3709d7da28008d902bf31098dbdbf4bacbea3d Mon Sep 17 00:00:00 2001 From: Luis Segalla Date: Thu, 29 Jan 2026 15:24:56 +0000 Subject: [PATCH 5/6] Changed module parameter and made all responses return parameter name as key --- python/src/xspress_detector/control/adapter.py | 6 +----- python/src/xspress_detector/control/detector.py | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/python/src/xspress_detector/control/adapter.py b/python/src/xspress_detector/control/adapter.py index 50b3593..7d357e2 100644 --- a/python/src/xspress_detector/control/adapter.py +++ b/python/src/xspress_detector/control/adapter.py @@ -85,12 +85,8 @@ async def get(self, path, request): try: response = await self.detector.get(path) if not isinstance(response, dict): - if "command" in path: - response = {path.split("/")[-1]: response} - else: - response = {"value": response} + response = {path.split("/")[-1]: response} - respose = "{}".format(response) status_code = 200 except LookupError as e: response = {'invalid path': str(e)} diff --git a/python/src/xspress_detector/control/detector.py b/python/src/xspress_detector/control/detector.py index a6e4beb..50f5dea 100644 --- a/python/src/xspress_detector/control/detector.py +++ b/python/src/xspress_detector/control/detector.py @@ -377,7 +377,7 @@ def __init__( ) - self.param["module"] = self._name + self.param["module"] = {"value": self._name} self.param["command"] = {"allowed": ["reconfigure","start_acquisition","stop_acquisition", "trigger"], "execute": ("", lambda name: self.run_command(name)) From 4669796f0ce0f71d791e688ccf7b7ab4dac40e9a Mon Sep 17 00:00:00 2001 From: Luis Segalla Date: Fri, 30 Jan 2026 09:38:01 +0000 Subject: [PATCH 6/6] Remove pyptoject.toml to try and fix CI --- python/pyproject.toml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 python/pyproject.toml diff --git a/python/pyproject.toml b/python/pyproject.toml deleted file mode 100644 index c767f91..0000000 --- a/python/pyproject.toml +++ /dev/null @@ -1,6 +0,0 @@ -[build-system] -# To get a reproducible wheel, wheel must be pinned to the same version as in -# dls-python3, and setuptools must produce the same dist-info. Cap setuptools -# to the last version that didn't add License-File to METADATA -requires = ["setuptools>=64", "wheel==0.33.1", "versioneer-518"] -build-backend = "setuptools.build_meta"