From c1e613ca81002ad8e101bcebf8c586ba55c34cda Mon Sep 17 00:00:00 2001 From: Gary Yendell Date: Thu, 27 Nov 2025 11:35:57 +0000 Subject: [PATCH] Add monitor waveform --- pyproject.toml | 1 + src/fastcs_eiger/__main__.py | 8 +++++-- .../controllers/eiger_monitor_controller.py | 23 ++++++++++++++----- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9c9969e..3841b42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ description = "Eiger control system integration with FastCS" dependencies = [ "aiohttp", "fastcs-odin~=0.9.0", + "fastcs[epicspva]", "numpy", "pillow", "typer", diff --git a/src/fastcs_eiger/__main__.py b/src/fastcs_eiger/__main__.py index e2dc962..fec3a14 100644 --- a/src/fastcs_eiger/__main__.py +++ b/src/fastcs_eiger/__main__.py @@ -8,6 +8,7 @@ from fastcs.logging import LogLevel, configure_logging, intercept_std_logger from fastcs.transports.epics import EpicsGUIOptions, EpicsIOCOptions from fastcs.transports.epics.ca.transport import EpicsCATransport +from fastcs.transports.epics.pva.transport import EpicsPVATransport from fastcs_eiger import __version__ from fastcs_eiger.controllers.eiger_controller import EigerController @@ -72,12 +73,15 @@ def ioc( ) transports = [ - EpicsCATransport( - epicsca=EpicsIOCOptions(pv_prefix=pv_prefix), + EpicsPVATransport( + epicspva=EpicsIOCOptions(pv_prefix=pv_prefix), gui=EpicsGUIOptions( output_path=ui_path / "eiger.bob", title=f"Eiger - {pv_prefix}" ), ), + EpicsCATransport( + epicsca=EpicsIOCOptions(pv_prefix=pv_prefix), + ), ] launcher = FastCS(controller, transports) launcher.run() diff --git a/src/fastcs_eiger/controllers/eiger_monitor_controller.py b/src/fastcs_eiger/controllers/eiger_monitor_controller.py index 2c5b671..3434f33 100644 --- a/src/fastcs_eiger/controllers/eiger_monitor_controller.py +++ b/src/fastcs_eiger/controllers/eiger_monitor_controller.py @@ -1,25 +1,36 @@ from io import BytesIO import numpy as np +from fastcs.attributes import AttrR +from fastcs.datatypes import Waveform from fastcs.methods import scan from PIL import Image from fastcs_eiger.controllers.eiger_subsystem_controller import EigerSubsystemController +DEFAULT_IMAGE_SHAPE = (5000, 5000) +DEFAULT_IMAGE = np.array(range(np.prod(DEFAULT_IMAGE_SHAPE)), dtype=np.uint32).reshape( + *DEFAULT_IMAGE_SHAPE +) + class EigerMonitorController(EigerSubsystemController): _subsystem = "monitor" + image = AttrR( + Waveform(np.uint32, shape=DEFAULT_IMAGE_SHAPE), initial_value=DEFAULT_IMAGE + ) + @scan(1) async def handle_monitor(self): """Poll monitor images to display.""" + if (image := await self._read_monitor_image()) is not None: + await self.image.update(image) + + async def _read_monitor_image(self) -> np.ndarray | None: response, image_bytes = await self.connection.get_bytes( f"monitor/api/{self._api_version}/images/next" ) - if response.status != 200: - return - else: - image = Image.open(BytesIO(image_bytes)) - # TODO: Populate waveform PV to display as image, once supported in PVI - print(np.array(image)) + if response.status == 200: + return np.array(Image.open(BytesIO(image_bytes)).getdata())