Skip to content

Commit

Permalink
Merge pull request #9 from DiamondLightSource/ui-groups
Browse files Browse the repository at this point in the history
Add demo of grouping Attributes
  • Loading branch information
GDYendell authored Aug 12, 2024
2 parents 77e4cc5 + ef13f4e commit 50077e5
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 50 deletions.
19 changes: 18 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"version": "0.2.0",
"configurations": [
{
"name": "Debug temp controller",
"name": "TempController Sim",
"type": "python",
"request": "launch",
"module": "tickit",
Expand All @@ -25,6 +25,23 @@
"PYTEST_ADDOPTS": "--no-cov"
},
},
{
"name": "TempController IOC",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/src/demo_fast_cs/demo.py",
"justMyCode": false,
"purpose": [
"debug-test"
],
"console": "integratedTerminal",
"env": {
// The default config in pyproject.toml's "[tool.pytest.ini_options]" adds coverage.
// Cannot have coverage and debugging at the same time.
// https://github.com/microsoft/vscode-python/issues/693
"PYTEST_ADDOPTS": "--no-cov"
},
},
{
"name": "Debug Unit Test",
"type": "python",
Expand Down
16 changes: 10 additions & 6 deletions src/demo_fast_cs/controllers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import asyncio
from dataclasses import dataclass
from typing import Any

Expand Down Expand Up @@ -41,14 +42,15 @@ async def update(
response = await controller.conn.send_query(
f"{self.name}{controller.suffix}?\r\n"
)

if attr.dtype is bool:
await attr.set(int(response))
else:
await attr.set(response)


class TempController(Controller):
ramp_rate = AttrRW(Float(), handler=TempControllerHandler("R"))
ramp_rate = AttrRW(Float(), handler=TempControllerHandler("R"), group="Config")

def __init__(self, settings: TempControllerSettings) -> None:
super().__init__()
Expand All @@ -63,10 +65,12 @@ def __init__(self, settings: TempControllerSettings) -> None:
self._ramp_controllers.append(controller)
self.register_sub_controller(controller)

@command
@command()
async def cancel_all(self) -> None:
for rc in self._ramp_controllers:
await rc.enabled.process(False)
# TODO: The requests all get concatenated if they are sent too quickly?
await asyncio.sleep(0.1)

async def connect(self) -> None:
await self.conn.connect(self._settings.ip_settings)
Expand All @@ -76,12 +80,12 @@ async def close(self) -> None:


class TempRampController(SubController):
start = AttrRW(Int(), handler=TempControllerHandler("S"))
end = AttrRW(Int(), handler=TempControllerHandler("E"))
current = AttrR(Float(prec=3), handler=TempControllerHandler("T"))
start = AttrRW(Int(), handler=TempControllerHandler("S"), group="Config")
end = AttrRW(Int(), handler=TempControllerHandler("E"), group="Config")
current = AttrR(Float(prec=3), handler=TempControllerHandler("T"), group="Status")
enabled = AttrRW(Bool(znam="Off", onam="On"), handler=TempControllerHandler("N"))

def __init__(self, index: int, conn: IPConnection) -> None:
self.suffix = f"{index:02d}"
super().__init__(f"ramp{self.suffix}")
super().__init__(f"Ramp{self.suffix}")
self.conn = conn
4 changes: 4 additions & 0 deletions src/demo_fast_cs/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,7 @@ def main() -> None:
# test_asyncio_backend()
create_gui()
test_ioc()


if __name__ == "__main__":
main()
59 changes: 31 additions & 28 deletions src/demo_fast_cs/simulation/device.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import logging
import traceback
from dataclasses import dataclass
from os import _exit

import numpy as np
import numpy.typing as npt
from tickit.adapters.composed import ComposedAdapter
from tickit.adapters.interpreters.command import CommandInterpreter
from tickit.adapters.interpreters.command.regex_command import RegexCommand
from tickit.adapters.interpreters.wrappers import SplittingInterpreter
from tickit.adapters.servers.tcp import ByteFormat, TcpServer
import pydantic.v1.dataclasses
from tickit.adapters.io import TcpIo
from tickit.adapters.specifications.regex_command import RegexCommand
from tickit.adapters.tcp import CommandAdapter
from tickit.core.adapter import AdapterContainer
from tickit.core.components.component import Component, ComponentConfig
from tickit.core.components.device_simulation import DeviceSimulation
from tickit.core.components.device_component import DeviceComponent
from tickit.core.device import Device, DeviceUpdate
from tickit.core.typedefs import SimTime
from tickit.utils.byte_format import ByteFormat
from typing_extensions import TypedDict


Expand All @@ -35,8 +35,11 @@ def wrapped_func(*args, **kwargs):


class TempControllerDevice(Device):
Inputs: type = TypedDict("Inputs", {"flux": float})
Outputs: type = TypedDict("Outputs", {"flux": float})
class Inputs(TypedDict):
flux: float

class Outputs(TypedDict):
flux: float

def __init__(
self,
Expand Down Expand Up @@ -105,19 +108,13 @@ def update(self, time: SimTime, inputs: Inputs) -> DeviceUpdate[Outputs]:
return DeviceUpdate(TempControllerDevice.Outputs(flux=inputs["flux"]), call_at)


class TempControllerAdapter(ComposedAdapter):
class TempControllerAdapter(CommandAdapter):
device: TempControllerDevice
_byte_format: ByteFormat = ByteFormat(b"%b\r\n")

def __init__(
self,
host: str = "localhost",
port: int = 25565,
) -> None:
super().__init__(
TcpServer(host, port, ByteFormat(b"%b\r\n")),
SplittingInterpreter(CommandInterpreter(), message_delimiter=b"\n"),
# CommandInterpreter(),
)
def __init__(self, device: TempControllerDevice) -> None:
super().__init__()
self.device = device

def _validate_index(self, index: str) -> int:
int_index = int(index) - 1
Expand Down Expand Up @@ -172,7 +169,7 @@ async def ignore_whitespace(self) -> None:
pass


@dataclass
@pydantic.v1.dataclasses.dataclass
class TempController(ComponentConfig):
num_ramp_controllers: int
default_start: float = 0
Expand All @@ -181,12 +178,18 @@ class TempController(ComponentConfig):
port: int = 25565

def __call__(self) -> Component:
return DeviceSimulation(
device = TempControllerDevice(
num_ramp_controllers=self.num_ramp_controllers,
default_start=self.default_start,
default_end=self.default_end,
)
return DeviceComponent(
name=self.name,
device=TempControllerDevice(
num_ramp_controllers=self.num_ramp_controllers,
default_start=self.default_start,
default_end=self.default_end,
),
adapters=[TempControllerAdapter(host=self.host, port=self.port)],
device=device,
adapters=[
AdapterContainer(
TempControllerAdapter(device),
TcpIo(self.host, self.port),
)
],
)
36 changes: 21 additions & 15 deletions src/demo_fast_cs/simulation/temp_controller.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
- tickit.devices.source.Source:
name: source
inputs: {}
value: 42.0
- demo_fast_cs.simulation.device.TempController:
name: tempcont
inputs:
flux: source:value
num_ramp_controllers: 4
default_start: 10
default_end: 50
- tickit.devices.sink.Sink:
name: sink
inputs:
flux: tempcont:flux
- type: tickit.devices.source.Source
name: source
inputs: {}
value: 42.0

- type: demo_fast_cs.simulation.device.TempController
name: tempcont
inputs:
flux:
component: source
port: value
num_ramp_controllers: 4
default_start: 10
default_end: 50

- type: tickit.devices.sink.Sink
name: sink
inputs:
flux:
component: tempcont
port: flux

0 comments on commit 50077e5

Please sign in to comment.