mccode-plumber 0.13.4__py3-none-any.whl → 0.14.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mccode_plumber/epics_watcher.py +125 -0
- {mccode_plumber-0.13.4.dist-info → mccode_plumber-0.14.0.dist-info}/METADATA +3 -3
- {mccode_plumber-0.13.4.dist-info → mccode_plumber-0.14.0.dist-info}/RECORD +6 -5
- {mccode_plumber-0.13.4.dist-info → mccode_plumber-0.14.0.dist-info}/entry_points.txt +1 -0
- {mccode_plumber-0.13.4.dist-info → mccode_plumber-0.14.0.dist-info}/WHEEL +0 -0
- {mccode_plumber-0.13.4.dist-info → mccode_plumber-0.14.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
from textual.app import App, ComposeResult
|
|
2
|
+
from textual.containers import VerticalScroll
|
|
3
|
+
from textual.widgets import Static
|
|
4
|
+
from textual.reactive import reactive
|
|
5
|
+
from textual import events
|
|
6
|
+
|
|
7
|
+
from p4p.client.thread import Context
|
|
8
|
+
from p4p.client.thread import Disconnected
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
import threading
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PVWidget(Static):
|
|
15
|
+
value: reactive[str] = reactive("Connecting...")
|
|
16
|
+
|
|
17
|
+
def __init__(self, pvname: str):
|
|
18
|
+
super().__init__()
|
|
19
|
+
self.pvname = pvname
|
|
20
|
+
self.sid = pvname.replace(':', '')
|
|
21
|
+
self.set_class(True, "pv-widget")
|
|
22
|
+
self.value_widget = None # Store reference directly
|
|
23
|
+
|
|
24
|
+
def compose(self) -> ComposeResult:
|
|
25
|
+
yield Static(f"[b]{self.pvname}[/b]", id=f"label-{self.sid}")
|
|
26
|
+
self.value_widget = Static(self.value, id=f"value-{self.sid}")
|
|
27
|
+
yield self.value_widget
|
|
28
|
+
|
|
29
|
+
def watch_value(self, value: str):
|
|
30
|
+
if self.value_widget:
|
|
31
|
+
self.value_widget.update(value)
|
|
32
|
+
|
|
33
|
+
def update_value(self, new_value: str):
|
|
34
|
+
self.value = new_value
|
|
35
|
+
|
|
36
|
+
class PVMonitorApp(App):
|
|
37
|
+
CSS = """
|
|
38
|
+
.pv-widget {
|
|
39
|
+
padding: 1 1;
|
|
40
|
+
border: round $primary;
|
|
41
|
+
margin: 1;
|
|
42
|
+
}
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, prefix: str, names: list[str]):
|
|
46
|
+
super().__init__()
|
|
47
|
+
self.pv_widgets = {}
|
|
48
|
+
self.ctx = Context("pva") # Or 'ca' if using Channel Access
|
|
49
|
+
self.prefix = prefix
|
|
50
|
+
self.names = names
|
|
51
|
+
self.grid = None
|
|
52
|
+
|
|
53
|
+
def compose(self) -> ComposeResult:
|
|
54
|
+
from textual.containers import Grid
|
|
55
|
+
self.grid = Grid(id="pv-grid")
|
|
56
|
+
yield self.grid
|
|
57
|
+
|
|
58
|
+
def on_mount(self) -> None:
|
|
59
|
+
self.grid.styles.grid_columns = ["1fr", "1fr", "1fr"] # 3 columns
|
|
60
|
+
self.grid.styles.grid_gap = (1, 1)
|
|
61
|
+
for name in self.names:
|
|
62
|
+
pv = f'{self.prefix}{name}'
|
|
63
|
+
widget = PVWidget(pv)
|
|
64
|
+
self.pv_widgets[pv] = widget
|
|
65
|
+
self.grid.mount(widget)
|
|
66
|
+
threading.Thread(target=self.monitor_pv, args=(pv,), daemon=True).start()
|
|
67
|
+
|
|
68
|
+
def monitor_pv(self, pvname: str):
|
|
69
|
+
def callback(value):
|
|
70
|
+
if isinstance(value, Disconnected):
|
|
71
|
+
new_value = "Disconnected"
|
|
72
|
+
else:
|
|
73
|
+
new_value = str(value)
|
|
74
|
+
# Schedule update on the main thread
|
|
75
|
+
asyncio.run_coroutine_threadsafe(
|
|
76
|
+
self.update_widget_value(pvname, new_value),
|
|
77
|
+
self._loop,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
self.ctx.monitor(pvname, callback)
|
|
81
|
+
|
|
82
|
+
async def update_widget_value(self, pvname: str, new_value: str):
|
|
83
|
+
widget = self.pv_widgets.get(pvname)
|
|
84
|
+
if widget:
|
|
85
|
+
widget.update_value(new_value)
|
|
86
|
+
|
|
87
|
+
async def on_shutdown(self) -> None:
|
|
88
|
+
self.ctx.close()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def get_names_parser():
|
|
93
|
+
from argparse import ArgumentParser
|
|
94
|
+
from mccode_plumber import __version__
|
|
95
|
+
p = ArgumentParser()
|
|
96
|
+
p.add_argument('name', type=str, nargs='+', help='The NTScalar names to watch')
|
|
97
|
+
p.add_argument('-p', '--prefix', type=str, help='The EPICS PV prefix to use', default='mcstas:')
|
|
98
|
+
p.add_argument('-v', '--version', action='version', version=__version__)
|
|
99
|
+
return p
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def run_strings():
|
|
103
|
+
args = get_names_parser().parse_args()
|
|
104
|
+
PVMonitorApp(args.prefix, args.name).run()
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def get_instr_parser():
|
|
108
|
+
from argparse import ArgumentParser
|
|
109
|
+
from mccode_plumber import __version__
|
|
110
|
+
p = ArgumentParser()
|
|
111
|
+
p.add_argument('instr', type=str, help='The instrument which defines names to watch')
|
|
112
|
+
p.add_argument('-p', '--prefix', type=str, help='The EPICS PV prefix to use', default='mcstas:')
|
|
113
|
+
p.add_argument('-v', '--version', action='version', version=__version__)
|
|
114
|
+
return p
|
|
115
|
+
|
|
116
|
+
def run_instr():
|
|
117
|
+
from mccode_plumber.manage.orchestrate import get_instr_name_and_parameters
|
|
118
|
+
args = get_instr_parser().parse_args()
|
|
119
|
+
_, parameters = get_instr_name_and_parameters(args.instr)
|
|
120
|
+
names = [p.name for p in parameters]
|
|
121
|
+
PVMonitorApp(args.prefix, names).run()
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
if __name__ == '__main__':
|
|
125
|
+
run_instr()
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mccode-plumber
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Author-email: Gregory Tucker <gregory.tucker@ess.eu>
|
|
5
5
|
Classifier: License :: OSI Approved :: BSD License
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
7
7
|
Requires-Dist: p4p
|
|
8
8
|
Requires-Dist: kafka-python>=2.2.11
|
|
9
9
|
Requires-Dist: ess-streaming-data-types>=0.14.0
|
|
10
|
-
Requires-Dist: restage>=0.
|
|
10
|
+
Requires-Dist: restage>=0.9.0
|
|
11
11
|
Requires-Dist: mccode-to-kafka>=0.2.2
|
|
12
|
-
Requires-Dist: moreniius>=0.
|
|
12
|
+
Requires-Dist: moreniius>=0.6.0
|
|
13
13
|
Requires-Dist: icecream
|
|
14
14
|
Requires-Dist: ephemeral-port-reserve
|
|
15
15
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
mccode_plumber/__init__.py,sha256=ZQMwyPQ6GyoEkKXj7aWETPqhXfwUbDOD5EpvlXj1c18,148
|
|
2
2
|
mccode_plumber/conductor.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
mccode_plumber/epics.py,sha256=SvZQN_vmI0NCGaIykIOQLO3tbgv79AMm60zGCmFQ56s,6167
|
|
4
|
+
mccode_plumber/epics_watcher.py,sha256=Jiz761A5NfoUzJ6ZzBGg8_BewFTmHDo5qYgh_DZHx_4,3973
|
|
4
5
|
mccode_plumber/forwarder.py,sha256=yzjb--r8M6vNSsWvvOi5IjXqpRn8MvT13cv89ezNEeU,3994
|
|
5
6
|
mccode_plumber/kafka.py,sha256=Q3oAuk7c-PS7b7zWSDhOR3dOO8R6Q8Y3HPI7K-Kt-RU,2499
|
|
6
7
|
mccode_plumber/mccode.py,sha256=vc4Gb5WhdOfuDRjEejU3Flps0C2A60sfFbMrxmKLhn0,2189
|
|
@@ -28,8 +29,8 @@ mccode_plumber/manage/forwarder.py,sha256=YYvHaOJ4djBXM7PFF2NBbnNDO6nnrwNOfSHaVO
|
|
|
28
29
|
mccode_plumber/manage/manager.py,sha256=zzrduroUL-jwQ9BrPTdAm1IW4dGv5bi8-ieIQ6qiQ6M,4141
|
|
29
30
|
mccode_plumber/manage/orchestrate.py,sha256=bumvHN6jPEOqd8V96f7gEmc5IpWOZ6mSo7_bosi3jY8,17662
|
|
30
31
|
mccode_plumber/manage/writer.py,sha256=SEv1U14L01Y9-BcaJKPei4Ah2LFfwexDy9FTjpvtSEs,2245
|
|
31
|
-
mccode_plumber-0.
|
|
32
|
-
mccode_plumber-0.
|
|
33
|
-
mccode_plumber-0.
|
|
34
|
-
mccode_plumber-0.
|
|
35
|
-
mccode_plumber-0.
|
|
32
|
+
mccode_plumber-0.14.0.dist-info/METADATA,sha256=tceaL7T1Li53p4HVOLaUOpKgvrEx12o8Npoqui_LgDY,594
|
|
33
|
+
mccode_plumber-0.14.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
34
|
+
mccode_plumber-0.14.0.dist-info/entry_points.txt,sha256=k3LDo_9HG2v4-IgMYlNukphdMmaAT6zkJZYaB1zJh3c,900
|
|
35
|
+
mccode_plumber-0.14.0.dist-info/top_level.txt,sha256=kCCIpYtKHCKWxiPEqX9J1UaGEm-ze0Qb-cemBCEPhDA,15
|
|
36
|
+
mccode_plumber-0.14.0.dist-info/RECORD,,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
mp-epics = mccode_plumber.epics:run
|
|
3
3
|
mp-epics-strings = mccode_plumber.epics:run_strings
|
|
4
4
|
mp-epics-update = mccode_plumber.epics:update
|
|
5
|
+
mp-epics-watch = mccode_plumber.epics_watcher:run_instr
|
|
5
6
|
mp-forwarder-setup = mccode_plumber.forwarder:setup
|
|
6
7
|
mp-forwarder-teardown = mccode_plumber.forwarder:teardown
|
|
7
8
|
mp-insert-hdf5-instr = mccode_plumber.mccode:insert
|
|
File without changes
|
|
File without changes
|