Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ophyd async v0.8 #23

Merged
merged 4 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ version = "0.0.1"
description = "An Interface between bluesky and SECoP, using ophyd and frappy-client"

dependencies = [
'ophyd-async == 0.7.0',
'ophyd-async == 0.8.0',
'frappy-core@git+https://github.com/SampleEnvironment/frappy@v0.19.2'

]
Expand Down Expand Up @@ -93,6 +93,7 @@ exclude = [".tox", "venv","frappy"]
[tool.mypy]
ignore_missing_imports = true # Ignore missing stubs in imported modules
plugins = ["numpy.typing.mypy_plugin"]
check_untyped_defs = true


[tool.black]
Expand Down
131 changes: 77 additions & 54 deletions src/secop_ophyd/SECoPDevices.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,14 @@
)
from ophyd_async.core import (
AsyncStatus,
ConfigSignal,
HintedSignal,
SignalR,
SignalRW,
SignalX,
StandardReadable,
T,
StandardReadableFormat,
observe_value,
)
from ophyd_async.core._utils import Callback
from typing_extensions import Self

from secop_ophyd.AsyncFrappyClient import AsyncFrappyClient
from secop_ophyd.GenNodeCode import GenNodeCode, Method
Expand Down Expand Up @@ -125,7 +122,7 @@ def __init__(self, secclient: AsyncFrappyClient) -> None:

self._secclient: AsyncFrappyClient = secclient

self.status: SignalR = None
self.status: SignalR

self.impl: str | None = None

Expand Down Expand Up @@ -248,46 +245,54 @@ def __init__(self, path: Path, secclient: AsyncFrappyClient):

self.wait_idle: bool = False

# Argument Signals (config Signals, can also be read)
arg_path = path.append("argument")
if self.arg_dtype is None:
self.argument = None
else:
arg_backend = LocalBackend(
path=arg_path,
secop_dtype_obj=self.arg_dtype,
sig_datainfo=datainfo["argument"],
)
self.argument = SignalRW(arg_backend)
config.append(self.argument)

# Result Signals (read Signals)
res_path = path.append("result")

if self.res_dtype is None:
self.result = None
else:
res_backend = LocalBackend(
path=res_path,
secop_dtype_obj=self.res_dtype,
sig_datainfo=datainfo["result"],
with self.add_children_as_readables(
format=StandardReadableFormat.CONFIG_SIGNAL
):
# Argument Signals (config Signals, can also be read)
arg_path = path.append("argument")
if self.arg_dtype is None:
self.argument = None
else:
arg_backend = LocalBackend(
path=arg_path,
secop_dtype_obj=self.arg_dtype,
sig_datainfo=datainfo["argument"],
)
self.argument = SignalRW(arg_backend)
config.append(self.argument)

# Result Signals (read Signals)
res_path = path.append("result")

if self.res_dtype is None:
self.result = None
else:
res_backend = LocalBackend(
path=res_path,
secop_dtype_obj=self.res_dtype,
sig_datainfo=datainfo["result"],
)
self.result = SignalRW(res_backend)
read.append(self.argument)

argument = None
result = None
if isinstance(self.argument, SignalR):
argument = self.argument._connector.backend

if isinstance(self.result, SignalR):
result = self.result._connector.backend

# SignalX (signal that triggers execution of the Command)
exec_backend = SECoPXBackend(
path=path,
secclient=secclient,
argument=argument, # type: ignore
result=result, # type: ignore
)
self.result = SignalRW(res_backend)
read.append(self.argument)

# SignalX (signal that triggers execution of the Command)
exec_backend = SECoPXBackend(
path=path,
secclient=secclient,
argument=None if self.argument is None else self.argument._backend,
result=None if self.result is None else self.result._backend,
)

self.commandx = SignalX(exec_backend)

self.add_readables(read, wrapper=HintedSignal)
self.add_readables(config, wrapper=ConfigSignal)

super().__init__(name=dev_name)

def trigger(self) -> AsyncStatus:
Expand Down Expand Up @@ -352,10 +357,12 @@ def __init__(self, secclient: AsyncFrappyClient, module_name: str):
module_desc = secclient.modules[module_name]
self.plans: list[Method] = []
self.mod_prop_devices: Dict[str, SignalR] = {}
self.param_devices: Dict[str, T] = {}
self.param_devices: Dict[str, Any] = {}

# Add configuration Signal
with self.add_children_as_readables(ConfigSignal):
with self.add_children_as_readables(
format=StandardReadableFormat.CONFIG_SIGNAL
):
# generate Signals from Module Properties
for property in module_desc["properties"]:
propb = PropertyBackend(property, module_desc["properties"], secclient)
Expand Down Expand Up @@ -387,7 +394,9 @@ def __init__(self, secclient: AsyncFrappyClient, module_name: str):
self.param_devices[parameter] = getattr(self, parameter)

# Add readables Signals
with self.add_children_as_readables(HintedSignal):
with self.add_children_as_readables(
format=StandardReadableFormat.HINTED_SIGNAL
):
for parameter in READABLE_PARAMS:
if parameter not in module_desc["parameters"].keys():
continue
Expand Down Expand Up @@ -465,8 +474,13 @@ def wait_for_idle_factory():

yield from bps.wait_for([wait_for_idle_factory])

if return_type is not None and cmd_dev.result is not None:
return cmd_dev.result._backend.reading.get_value()
if (
return_type is not None
and isinstance(cmd_dev.result, SignalR)
and isinstance(cmd_dev.result._connector.backend, LocalBackend)
):

return cmd_dev.result._connector.backend.reading.get_value()

def command_plan(self, arg, wait_for_idle: bool = False):
# TODO Type checking
Expand All @@ -485,8 +499,13 @@ def wait_for_idle_factory():

yield from bps.wait_for([wait_for_idle_factory])

if return_type is not None and cmd_dev.result is not None:
return cmd_dev.result._backend.reading.get_value()
if (
return_type is not None
and isinstance(cmd_dev.result, SignalR)
and isinstance(cmd_dev.result._connector.backend, LocalBackend)
):

return cmd_dev.result._connector.backend.reading.get_value()

cmd_meth = command_plan_no_arg if argument_type is None else command_plan

Expand All @@ -511,7 +530,7 @@ def wait_for_idle_factory():

return cmd_meth

def trigger(self) -> bps.Status:
def trigger(self) -> AsyncStatus:
return AsyncStatus(awaitable=self.value.read(cached=False))

def subscribe(self, function: Callback[dict[str, Reading]]) -> None:
Expand Down Expand Up @@ -715,14 +734,16 @@ def __init__(self, secclient: AsyncFrappyClient):

config = []

with self.add_children_as_readables(ConfigSignal):
with self.add_children_as_readables(
format=StandardReadableFormat.CONFIG_SIGNAL
):
for property in self._secclient.properties:
propb = PropertyBackend(property, self._secclient.properties, secclient)
setattr(self, property, SignalR(backend=propb))
config.append(getattr(self, property))
self.node_prop_devices[property] = getattr(self, property)

with self.add_children_as_readables():
with self.add_children_as_readables(format=StandardReadableFormat.CHILD):
for module, module_desc in self._secclient.modules.items():
secop_dev_class = class_from_interface(module_desc["properties"])

Expand All @@ -738,7 +759,7 @@ def __init__(self, secclient: AsyncFrappyClient):
super().__init__(name=name)

@classmethod
def create(cls, host: str, port: str, loop, log=Logger) -> Self:
def create(cls, host: str, port: str, loop, log=Logger) -> "SECoPNodeDevice":

secclient: AsyncFrappyClient

Expand All @@ -762,7 +783,9 @@ def create(cls, host: str, port: str, loop, log=Logger) -> Self:
return SECoPNodeDevice(secclient=secclient)

@classmethod
async def create_async(cls, host: str, port: str, loop, log=Logger) -> Self:
async def create_async(
cls, host: str, port: str, loop, log=Logger
) -> "SECoPNodeDevice":

secclient: AsyncFrappyClient

Expand Down Expand Up @@ -930,7 +953,7 @@ def descriptiveDataChange(self, module, description): # noqa: N802
setattr(self, property, SignalR(backend=propb))
config.append(getattr(self, property))

self.add_readables(config, wrapper=ConfigSignal)
self.add_readables(config, format=StandardReadableFormat.CONFIG_SIGNAL)
else:
# Refresh changed modules
module_desc = self._secclient.modules[module]
Expand Down
Loading