cgse 2023.38.0__py3-none-any.whl → 2024.1.3__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.
Files changed (653) hide show
  1. README.md +27 -0
  2. bump.py +77 -0
  3. cgse-2024.1.3.dist-info/METADATA +41 -0
  4. cgse-2024.1.3.dist-info/RECORD +5 -0
  5. {cgse-2023.38.0.dist-info → cgse-2024.1.3.dist-info}/WHEEL +1 -2
  6. cgse-2023.38.0.dist-info/COPYING +0 -674
  7. cgse-2023.38.0.dist-info/COPYING.LESSER +0 -165
  8. cgse-2023.38.0.dist-info/METADATA +0 -144
  9. cgse-2023.38.0.dist-info/RECORD +0 -649
  10. cgse-2023.38.0.dist-info/entry_points.txt +0 -75
  11. cgse-2023.38.0.dist-info/top_level.txt +0 -2
  12. egse/__init__.py +0 -12
  13. egse/__main__.py +0 -32
  14. egse/aeu/aeu.py +0 -5235
  15. egse/aeu/aeu_awg.yaml +0 -265
  16. egse/aeu/aeu_crio.yaml +0 -273
  17. egse/aeu/aeu_cs.py +0 -626
  18. egse/aeu/aeu_devif.py +0 -321
  19. egse/aeu/aeu_main_ui.py +0 -912
  20. egse/aeu/aeu_metrics.py +0 -131
  21. egse/aeu/aeu_protocol.py +0 -463
  22. egse/aeu/aeu_psu.yaml +0 -204
  23. egse/aeu/aeu_ui.py +0 -873
  24. egse/aeu/arbdata/FccdRead.arb +0 -2
  25. egse/aeu/arbdata/FccdRead_min_points.arb +0 -2
  26. egse/aeu/arbdata/HeaterSync_FccdRead.arb +0 -2
  27. egse/aeu/arbdata/HeaterSync_ccdRead25.arb +0 -2
  28. egse/aeu/arbdata/HeaterSync_ccdRead31_25.arb +0 -2
  29. egse/aeu/arbdata/HeaterSync_ccdRead37_50.arb +0 -2
  30. egse/aeu/arbdata/HeaterSync_ccdRead43_75.arb +0 -2
  31. egse/aeu/arbdata/HeaterSync_ccdRead50.arb +0 -2
  32. egse/aeu/arbdata/Heater_FccdRead_min_points.arb +0 -2
  33. egse/aeu/arbdata/ccdRead25.arb +0 -2
  34. egse/aeu/arbdata/ccdRead25_150ms.arb +0 -2
  35. egse/aeu/arbdata/ccdRead31_25.arb +0 -2
  36. egse/aeu/arbdata/ccdRead31_25_150ms.arb +0 -2
  37. egse/aeu/arbdata/ccdRead37_50.arb +0 -2
  38. egse/aeu/arbdata/ccdRead37_50_150ms.arb +0 -2
  39. egse/aeu/arbdata/ccdRead43_75.arb +0 -2
  40. egse/aeu/arbdata/ccdRead43_75_150ms.arb +0 -2
  41. egse/aeu/arbdata/ccdRead50.arb +0 -2
  42. egse/aeu/arbdata/ccdRead50_150ms.arb +0 -2
  43. egse/alert/__init__.py +0 -1049
  44. egse/alert/alertman.yaml +0 -37
  45. egse/alert/alertman_cs.py +0 -234
  46. egse/alert/alertman_ui.py +0 -603
  47. egse/alert/gsm/beaglebone.py +0 -138
  48. egse/alert/gsm/beaglebone.yaml +0 -51
  49. egse/alert/gsm/beaglebone_cs.py +0 -108
  50. egse/alert/gsm/beaglebone_devif.py +0 -130
  51. egse/alert/gsm/beaglebone_protocol.py +0 -48
  52. egse/bits.py +0 -318
  53. egse/camera.py +0 -44
  54. egse/collimator/__init__.py +0 -0
  55. egse/collimator/fcul/__init__.py +0 -0
  56. egse/collimator/fcul/ogse.py +0 -1077
  57. egse/collimator/fcul/ogse.yaml +0 -14
  58. egse/collimator/fcul/ogse_cs.py +0 -154
  59. egse/collimator/fcul/ogse_devif.py +0 -358
  60. egse/collimator/fcul/ogse_protocol.py +0 -129
  61. egse/collimator/fcul/ogse_sim.py +0 -431
  62. egse/collimator/fcul/ogse_ui.py +0 -1108
  63. egse/command.py +0 -699
  64. egse/config.py +0 -410
  65. egse/confman/__init__.py +0 -1015
  66. egse/confman/confman.yaml +0 -67
  67. egse/confman/confman_cs.py +0 -239
  68. egse/confman/confman_ui.py +0 -381
  69. egse/confman/setup_ui.py +0 -565
  70. egse/control.py +0 -442
  71. egse/coordinates/__init__.py +0 -531
  72. egse/coordinates/avoidance.py +0 -103
  73. egse/coordinates/cslmodel.py +0 -127
  74. egse/coordinates/laser_tracker_to_dict.py +0 -120
  75. egse/coordinates/point.py +0 -707
  76. egse/coordinates/pyplot.py +0 -195
  77. egse/coordinates/referenceFrame.py +0 -1279
  78. egse/coordinates/refmodel.py +0 -737
  79. egse/coordinates/rotationMatrix.py +0 -85
  80. egse/coordinates/transform3d_addon.py +0 -419
  81. egse/csl/__init__.py +0 -50
  82. egse/csl/commanding.py +0 -78
  83. egse/csl/icons/hexapod-connected-selected.svg +0 -30
  84. egse/csl/icons/hexapod-connected.svg +0 -30
  85. egse/csl/icons/hexapod-homing-selected.svg +0 -68
  86. egse/csl/icons/hexapod-homing.svg +0 -68
  87. egse/csl/icons/hexapod-retract-selected.svg +0 -56
  88. egse/csl/icons/hexapod-retract.svg +0 -51
  89. egse/csl/icons/hexapod-zero-selected.svg +0 -56
  90. egse/csl/icons/hexapod-zero.svg +0 -56
  91. egse/csl/icons/logo-puna.svg +0 -92
  92. egse/csl/icons/stop.svg +0 -1
  93. egse/csl/initialisation.py +0 -102
  94. egse/csl/mech_pos_settings.yaml +0 -18
  95. egse/das.py +0 -1247
  96. egse/das.yaml +0 -7
  97. egse/data/conf/SETUP_CSL_00000_170620_150000.yaml +0 -5
  98. egse/data/conf/SETUP_CSL_00001_170620_151010.yaml +0 -69
  99. egse/data/conf/SETUP_CSL_00002_170620_151020.yaml +0 -69
  100. egse/data/conf/SETUP_CSL_00003_170620_151030.yaml +0 -69
  101. egse/data/conf/SETUP_CSL_00004_170620_151040.yaml +0 -69
  102. egse/data/conf/SETUP_CSL_00005_170620_151050.yaml +0 -69
  103. egse/data/conf/SETUP_CSL_00006_170620_151060.yaml +0 -69
  104. egse/data/conf/SETUP_CSL_00007_170620_151070.yaml +0 -69
  105. egse/data/conf/SETUP_CSL_00008_170620_151080.yaml +0 -75
  106. egse/data/conf/SETUP_CSL_00010_210308_083016.yaml +0 -138
  107. egse/data/conf/SETUP_INTA_00000_170620_150000.yaml +0 -4
  108. egse/data/conf/SETUP_SRON_00000_170620_150000.yaml +0 -4
  109. egse/decorators.py +0 -415
  110. egse/device.py +0 -269
  111. egse/dpu/__init__.py +0 -2681
  112. egse/dpu/ccd_ui.py +0 -508
  113. egse/dpu/dpu.py +0 -786
  114. egse/dpu/dpu.yaml +0 -153
  115. egse/dpu/dpu_cs.py +0 -272
  116. egse/dpu/dpu_ui.py +0 -668
  117. egse/dpu/fitsgen.py +0 -2077
  118. egse/dpu/fitsgen_test.py +0 -752
  119. egse/dpu/fitsgen_ui.py +0 -399
  120. egse/dpu/hdf5_model.py +0 -332
  121. egse/dpu/hdf5_ui.py +0 -277
  122. egse/dpu/hdf5_viewer.py +0 -506
  123. egse/dpu/hk_ui.py +0 -468
  124. egse/dpu_commands.py +0 -81
  125. egse/dsi/constants.py +0 -220
  126. egse/dsi/esl.py +0 -870
  127. egse/dsi/rmap.py +0 -1042
  128. egse/dsi/rmapci.py +0 -37
  129. egse/dsi/spw.py +0 -154
  130. egse/dsi/spw_state.py +0 -29
  131. egse/dummy.py +0 -258
  132. egse/dyndummy.py +0 -179
  133. egse/env.py +0 -278
  134. egse/exceptions.py +0 -88
  135. egse/fdir/__init__.py +0 -28
  136. egse/fdir/fdir_manager.py +0 -85
  137. egse/fdir/fdir_manager.yaml +0 -51
  138. egse/fdir/fdir_manager_controller.py +0 -228
  139. egse/fdir/fdir_manager_cs.py +0 -164
  140. egse/fdir/fdir_manager_interface.py +0 -25
  141. egse/fdir/fdir_remote.py +0 -73
  142. egse/fdir/fdir_remote.yaml +0 -37
  143. egse/fdir/fdir_remote_controller.py +0 -50
  144. egse/fdir/fdir_remote_cs.py +0 -97
  145. egse/fdir/fdir_remote_interface.py +0 -14
  146. egse/fdir/fdir_remote_popup.py +0 -31
  147. egse/fee/__init__.py +0 -114
  148. egse/fee/f_fee_register.yaml +0 -43
  149. egse/fee/fee.py +0 -631
  150. egse/fee/feesim.py +0 -750
  151. egse/fee/n_fee_hk.py +0 -761
  152. egse/fee/nfee.py +0 -187
  153. egse/filterwheel/__init__.py +0 -4
  154. egse/filterwheel/eksma/__init__.py +0 -24
  155. egse/filterwheel/eksma/fw8smc4.py +0 -661
  156. egse/filterwheel/eksma/fw8smc4.yaml +0 -121
  157. egse/filterwheel/eksma/fw8smc4_cs.py +0 -144
  158. egse/filterwheel/eksma/fw8smc4_devif.py +0 -473
  159. egse/filterwheel/eksma/fw8smc4_protocol.py +0 -81
  160. egse/filterwheel/eksma/fw8smc4_ui.py +0 -940
  161. egse/filterwheel/eksma/fw8smc5.py +0 -111
  162. egse/filterwheel/eksma/fw8smc5.yaml +0 -105
  163. egse/filterwheel/eksma/fw8smc5_controller.py +0 -307
  164. egse/filterwheel/eksma/fw8smc5_cs.py +0 -141
  165. egse/filterwheel/eksma/fw8smc5_interface.py +0 -65
  166. egse/filterwheel/eksma/fw8smc5_simulator.py +0 -29
  167. egse/filterwheel/eksma/fw8smc5_ui.py +0 -1068
  168. egse/filterwheel/eksma/testpythonfw.py +0 -215
  169. egse/fov/__init__.py +0 -65
  170. egse/fov/fov_hk.py +0 -712
  171. egse/fov/fov_ui.py +0 -861
  172. egse/fov/fov_ui_controller.py +0 -140
  173. egse/fov/fov_ui_model.py +0 -200
  174. egse/fov/fov_ui_view.py +0 -345
  175. egse/gimbal/__init__.py +0 -32
  176. egse/gimbal/symetrie/__init__.py +0 -26
  177. egse/gimbal/symetrie/alpha.py +0 -586
  178. egse/gimbal/symetrie/generic_gimbal_ui.py +0 -1521
  179. egse/gimbal/symetrie/gimbal.py +0 -877
  180. egse/gimbal/symetrie/gimbal.yaml +0 -168
  181. egse/gimbal/symetrie/gimbal_cs.py +0 -183
  182. egse/gimbal/symetrie/gimbal_protocol.py +0 -135
  183. egse/gimbal/symetrie/gimbal_ui.py +0 -361
  184. egse/gimbal/symetrie/pmac.py +0 -1006
  185. egse/gimbal/symetrie/pmac_regex.py +0 -83
  186. egse/graph.py +0 -132
  187. egse/gui/__init__.py +0 -47
  188. egse/gui/buttons.py +0 -378
  189. egse/gui/focalplane.py +0 -1281
  190. egse/gui/formatter.py +0 -10
  191. egse/gui/led.py +0 -162
  192. egse/gui/limitswitch.py +0 -143
  193. egse/gui/mechanisms.py +0 -588
  194. egse/gui/states.py +0 -148
  195. egse/gui/stripchart.py +0 -729
  196. egse/gui/switch.py +0 -112
  197. egse/h5.py +0 -274
  198. egse/help/__init__.py +0 -0
  199. egse/help/help_ui.py +0 -126
  200. egse/hexapod/__init__.py +0 -32
  201. egse/hexapod/symetrie/__init__.py +0 -138
  202. egse/hexapod/symetrie/alpha.py +0 -874
  203. egse/hexapod/symetrie/dynalpha.py +0 -1387
  204. egse/hexapod/symetrie/hexapod_ui.py +0 -1516
  205. egse/hexapod/symetrie/pmac.py +0 -1010
  206. egse/hexapod/symetrie/pmac_regex.py +0 -83
  207. egse/hexapod/symetrie/puna.py +0 -1167
  208. egse/hexapod/symetrie/puna.yaml +0 -193
  209. egse/hexapod/symetrie/puna_cs.py +0 -196
  210. egse/hexapod/symetrie/puna_protocol.py +0 -131
  211. egse/hexapod/symetrie/puna_ui.py +0 -434
  212. egse/hexapod/symetrie/punaplus.py +0 -107
  213. egse/hexapod/symetrie/zonda.py +0 -872
  214. egse/hexapod/symetrie/zonda.yaml +0 -337
  215. egse/hexapod/symetrie/zonda_cs.py +0 -172
  216. egse/hexapod/symetrie/zonda_devif.py +0 -415
  217. egse/hexapod/symetrie/zonda_protocol.py +0 -119
  218. egse/hexapod/symetrie/zonda_ui.py +0 -449
  219. egse/hk.py +0 -765
  220. egse/icons/aeu-cs-start.svg +0 -117
  221. egse/icons/aeu-cs-stop.svg +0 -118
  222. egse/icons/aeu-cs.svg +0 -107
  223. egse/icons/aeu_cs-started.svg +0 -112
  224. egse/icons/aeu_cs-stopped.svg +0 -112
  225. egse/icons/aeu_cs.svg +0 -55
  226. egse/icons/alert.svg +0 -1
  227. egse/icons/arrow-double-left.png +0 -0
  228. egse/icons/arrow-double-right.png +0 -0
  229. egse/icons/arrow-up.svg +0 -11
  230. egse/icons/backward.svg +0 -1
  231. egse/icons/busy.svg +0 -1
  232. egse/icons/cleaning.svg +0 -115
  233. egse/icons/color-scheme.svg +0 -1
  234. egse/icons/cs-connected-alert.svg +0 -91
  235. egse/icons/cs-connected-disabled.svg +0 -43
  236. egse/icons/cs-connected.svg +0 -89
  237. egse/icons/cs-not-connected.svg +0 -44
  238. egse/icons/double-left-arrow.svg +0 -1
  239. egse/icons/double-right-arrow.svg +0 -1
  240. egse/icons/erase-disabled.svg +0 -19
  241. egse/icons/erase.svg +0 -59
  242. egse/icons/fitsgen-start.svg +0 -47
  243. egse/icons/fitsgen-stop.svg +0 -48
  244. egse/icons/fitsgen.svg +0 -1
  245. egse/icons/forward.svg +0 -1
  246. egse/icons/fov-hk-start.svg +0 -33
  247. egse/icons/fov-hk-stop.svg +0 -37
  248. egse/icons/fov-hk.svg +0 -1
  249. egse/icons/front-desk.svg +0 -1
  250. egse/icons/home-actioned.svg +0 -15
  251. egse/icons/home-disabled.svg +0 -15
  252. egse/icons/home.svg +0 -13
  253. egse/icons/info.svg +0 -1
  254. egse/icons/invalid.png +0 -0
  255. egse/icons/led-green.svg +0 -20
  256. egse/icons/led-grey.svg +0 -20
  257. egse/icons/led-orange.svg +0 -20
  258. egse/icons/led-red.svg +0 -20
  259. egse/icons/led-square-green.svg +0 -134
  260. egse/icons/led-square-grey.svg +0 -134
  261. egse/icons/led-square-orange.svg +0 -134
  262. egse/icons/led-square-red.svg +0 -134
  263. egse/icons/limit-switch-all-green.svg +0 -115
  264. egse/icons/limit-switch-all-red.svg +0 -117
  265. egse/icons/limit-switch-el+.svg +0 -116
  266. egse/icons/limit-switch-el-.svg +0 -117
  267. egse/icons/location-marker.svg +0 -1
  268. egse/icons/logo-dpu.svg +0 -48
  269. egse/icons/logo-gimbal.svg +0 -112
  270. egse/icons/logo-huber.svg +0 -23
  271. egse/icons/logo-ogse.svg +0 -31
  272. egse/icons/logo-puna.svg +0 -92
  273. egse/icons/logo-tcs.svg +0 -29
  274. egse/icons/logo-zonda.svg +0 -66
  275. egse/icons/maximize.svg +0 -1
  276. egse/icons/meter.svg +0 -1
  277. egse/icons/more.svg +0 -45
  278. egse/icons/n-fee-hk-start.svg +0 -24
  279. egse/icons/n-fee-hk-stop.svg +0 -25
  280. egse/icons/n-fee-hk.svg +0 -83
  281. egse/icons/observing-off.svg +0 -46
  282. egse/icons/observing-on.svg +0 -46
  283. egse/icons/open-document-hdf5.png +0 -0
  284. egse/icons/open-document-hdf5.svg +0 -21
  285. egse/icons/ops-mode.svg +0 -1
  286. egse/icons/play-green.svg +0 -17
  287. egse/icons/plugged-disabled.svg +0 -27
  288. egse/icons/plugged.svg +0 -21
  289. egse/icons/pm_ui.svg +0 -1
  290. egse/icons/power-button-green.svg +0 -27
  291. egse/icons/power-button-red.svg +0 -27
  292. egse/icons/power-button.svg +0 -27
  293. egse/icons/radar.svg +0 -1
  294. egse/icons/radioactive.svg +0 -2
  295. egse/icons/reload.svg +0 -1
  296. egse/icons/remote-control-off.svg +0 -28
  297. egse/icons/remote-control-on.svg +0 -28
  298. egse/icons/repeat-blue.svg +0 -15
  299. egse/icons/repeat.svg +0 -1
  300. egse/icons/settings.svg +0 -1
  301. egse/icons/shrink.svg +0 -1
  302. egse/icons/shutter.svg +0 -1
  303. egse/icons/sign-off.svg +0 -1
  304. egse/icons/sign-on.svg +0 -1
  305. egse/icons/sim-mode.svg +0 -1
  306. egse/icons/small-buttons-go.svg +0 -20
  307. egse/icons/small-buttons-minus.svg +0 -51
  308. egse/icons/small-buttons-plus.svg +0 -51
  309. egse/icons/sponge.svg +0 -220
  310. egse/icons/start-button-disabled.svg +0 -84
  311. egse/icons/start-button.svg +0 -50
  312. egse/icons/stop-button-disabled.svg +0 -84
  313. egse/icons/stop-button.svg +0 -50
  314. egse/icons/stop-red.svg +0 -17
  315. egse/icons/stop.svg +0 -1
  316. egse/icons/switch-disabled-square.svg +0 -87
  317. egse/icons/switch-disabled.svg +0 -15
  318. egse/icons/switch-off-square.svg +0 -87
  319. egse/icons/switch-off.svg +0 -72
  320. egse/icons/switch-on-square.svg +0 -87
  321. egse/icons/switch-on.svg +0 -61
  322. egse/icons/temperature-control.svg +0 -44
  323. egse/icons/th_ui_logo.svg +0 -1
  324. egse/icons/unplugged.svg +0 -23
  325. egse/icons/unvalid.png +0 -0
  326. egse/icons/user-interface.svg +0 -1
  327. egse/icons/vacuum.svg +0 -1
  328. egse/icons/valid.png +0 -0
  329. egse/icons/zoom-to-pixel-dark.svg +0 -64
  330. egse/icons/zoom-to-pixel-white.svg +0 -36
  331. egse/images/big-rotation-stage.png +0 -0
  332. egse/images/connected-100.png +0 -0
  333. egse/images/cross.svg +0 -6
  334. egse/images/disconnected-100.png +0 -0
  335. egse/images/gui-icon.png +0 -0
  336. egse/images/home.svg +0 -6
  337. egse/images/info-icon.png +0 -0
  338. egse/images/led-black.svg +0 -89
  339. egse/images/led-green.svg +0 -85
  340. egse/images/led-orange.svg +0 -85
  341. egse/images/led-red.svg +0 -85
  342. egse/images/load-icon.png +0 -0
  343. egse/images/load-setup.png +0 -0
  344. egse/images/load.png +0 -0
  345. egse/images/pause.png +0 -0
  346. egse/images/play-button.svg +0 -8
  347. egse/images/play.png +0 -0
  348. egse/images/process-status.png +0 -0
  349. egse/images/restart.png +0 -0
  350. egse/images/search.png +0 -0
  351. egse/images/sma.png +0 -0
  352. egse/images/start.png +0 -0
  353. egse/images/stop-button.svg +0 -8
  354. egse/images/stop.png +0 -0
  355. egse/images/switch-off.svg +0 -48
  356. egse/images/switch-on.svg +0 -48
  357. egse/images/undo.png +0 -0
  358. egse/images/update-button.svg +0 -11
  359. egse/imageviewer/exposureselection.py +0 -475
  360. egse/imageviewer/imageviewer.py +0 -198
  361. egse/imageviewer/matchfocalplane.py +0 -179
  362. egse/imageviewer/subfieldposition.py +0 -133
  363. egse/lampcontrol/__init__.py +0 -4
  364. egse/lampcontrol/beaglebone/beaglebone.py +0 -178
  365. egse/lampcontrol/beaglebone/beaglebone.yaml +0 -62
  366. egse/lampcontrol/beaglebone/beaglebone_cs.py +0 -106
  367. egse/lampcontrol/beaglebone/beaglebone_devif.py +0 -150
  368. egse/lampcontrol/beaglebone/beaglebone_protocol.py +0 -73
  369. egse/lampcontrol/energetiq/__init__.py +0 -22
  370. egse/lampcontrol/energetiq/eq99.yaml +0 -98
  371. egse/lampcontrol/energetiq/lampEQ99.py +0 -283
  372. egse/lampcontrol/energetiq/lampEQ99_cs.py +0 -128
  373. egse/lampcontrol/energetiq/lampEQ99_devif.py +0 -158
  374. egse/lampcontrol/energetiq/lampEQ99_encode_decode_errors.py +0 -73
  375. egse/lampcontrol/energetiq/lampEQ99_protocol.py +0 -69
  376. egse/lampcontrol/energetiq/lampEQ99_ui.py +0 -465
  377. egse/lib/CentOS-7/EtherSpaceLink_v34_86.dylib +0 -0
  378. egse/lib/CentOS-8/ESL-RMAP_v34_86.dylib +0 -0
  379. egse/lib/CentOS-8/EtherSpaceLink_v34_86.dylib +0 -0
  380. egse/lib/Debian/ESL-RMAP_v34_86.dylib +0 -0
  381. egse/lib/Debian/EtherSpaceLink_v34_86.dylib +0 -0
  382. egse/lib/Debian/libetherspacelink_v35_21.dylib +0 -0
  383. egse/lib/Linux/ESL-RMAP_v34_86.dylib +0 -0
  384. egse/lib/Linux/EtherSpaceLink_v34_86.dylib +0 -0
  385. egse/lib/Ubuntu-20/ESL-RMAP_v34_86.dylib +0 -0
  386. egse/lib/Ubuntu-20/EtherSpaceLink_v34_86.dylib +0 -0
  387. egse/lib/gssw/python3-gssw_2.2.3+31f63c9f-1_all.deb +0 -0
  388. egse/lib/macOS/ESL-RMAP_v34_86.dylib +0 -0
  389. egse/lib/macOS/EtherSpaceLink_v34_86.dylib +0 -0
  390. egse/lib/ximc/__pycache__/pyximc.cpython-38 2.pyc +0 -0
  391. egse/lib/ximc/__pycache__/pyximc.cpython-38.pyc +0 -0
  392. egse/lib/ximc/libximc.framework/Frameworks/libbindy.dylib +0 -0
  393. egse/lib/ximc/libximc.framework/Frameworks/libxiwrapper.dylib +0 -0
  394. egse/lib/ximc/libximc.framework/Headers/ximc.h +0 -5510
  395. egse/lib/ximc/libximc.framework/Resources/Info.plist +0 -42
  396. egse/lib/ximc/libximc.framework/Resources/keyfile.sqlite +0 -0
  397. egse/lib/ximc/libximc.framework/libbindy.so +0 -0
  398. egse/lib/ximc/libximc.framework/libximc +0 -0
  399. egse/lib/ximc/libximc.framework/libximc.so +0 -0
  400. egse/lib/ximc/libximc.framework/libximc.so.7.0.0 +0 -0
  401. egse/lib/ximc/libximc.framework/libxiwrapper.so +0 -0
  402. egse/lib/ximc/pyximc.py +0 -922
  403. egse/listener.py +0 -73
  404. egse/logger/__init__.py +0 -243
  405. egse/logger/log_cs.py +0 -321
  406. egse/metrics.py +0 -98
  407. egse/mixin.py +0 -464
  408. egse/monitoring.py +0 -95
  409. egse/ni/alarms/__init__.py +0 -26
  410. egse/ni/alarms/cdaq9375.py +0 -300
  411. egse/ni/alarms/cdaq9375.yaml +0 -89
  412. egse/ni/alarms/cdaq9375_cs.py +0 -130
  413. egse/ni/alarms/cdaq9375_devif.py +0 -183
  414. egse/ni/alarms/cdaq9375_protocol.py +0 -48
  415. egse/obs_inspection.py +0 -163
  416. egse/observer.py +0 -41
  417. egse/obsid.py +0 -163
  418. egse/powermeter/__init__.py +0 -0
  419. egse/powermeter/ni/__init__.py +0 -38
  420. egse/powermeter/ni/cdaq9184.py +0 -224
  421. egse/powermeter/ni/cdaq9184.yaml +0 -73
  422. egse/powermeter/ni/cdaq9184_cs.py +0 -130
  423. egse/powermeter/ni/cdaq9184_devif.py +0 -201
  424. egse/powermeter/ni/cdaq9184_protocol.py +0 -48
  425. egse/powermeter/ni/cdaq9184_ui.py +0 -544
  426. egse/powermeter/thorlabs/__init__.py +0 -25
  427. egse/powermeter/thorlabs/pm100a.py +0 -380
  428. egse/powermeter/thorlabs/pm100a.yaml +0 -132
  429. egse/powermeter/thorlabs/pm100a_cs.py +0 -136
  430. egse/powermeter/thorlabs/pm100a_devif.py +0 -127
  431. egse/powermeter/thorlabs/pm100a_protocol.py +0 -80
  432. egse/powermeter/thorlabs/pm100a_ui.py +0 -725
  433. egse/process.py +0 -451
  434. egse/procman/__init__.py +0 -811
  435. egse/procman/cannot_start_process_popup.py +0 -43
  436. egse/procman/procman.yaml +0 -49
  437. egse/procman/procman_cs.py +0 -201
  438. egse/procman/procman_ui.py +0 -2081
  439. egse/protocol.py +0 -603
  440. egse/proxy.py +0 -522
  441. egse/randomwalk.py +0 -140
  442. egse/reg.py +0 -585
  443. egse/reload.py +0 -122
  444. egse/reprocess.py +0 -675
  445. egse/resource.py +0 -333
  446. egse/rst.py +0 -135
  447. egse/search.py +0 -182
  448. egse/serialdevice.py +0 -190
  449. egse/services.py +0 -212
  450. egse/services.yaml +0 -51
  451. egse/settings.py +0 -379
  452. egse/settings.yaml +0 -980
  453. egse/setup.py +0 -1180
  454. egse/shutter/__init__.py +0 -0
  455. egse/shutter/thorlabs/__init__.py +0 -19
  456. egse/shutter/thorlabs/ksc101.py +0 -205
  457. egse/shutter/thorlabs/ksc101.yaml +0 -105
  458. egse/shutter/thorlabs/ksc101_cs.py +0 -136
  459. egse/shutter/thorlabs/ksc101_devif.py +0 -201
  460. egse/shutter/thorlabs/ksc101_protocol.py +0 -69
  461. egse/shutter/thorlabs/ksc101_ui.py +0 -548
  462. egse/shutter/thorlabs/sc10.py +0 -82
  463. egse/shutter/thorlabs/sc10.yaml +0 -52
  464. egse/shutter/thorlabs/sc10_controller.py +0 -81
  465. egse/shutter/thorlabs/sc10_cs.py +0 -108
  466. egse/shutter/thorlabs/sc10_interface.py +0 -25
  467. egse/shutter/thorlabs/sc10_simulator.py +0 -30
  468. egse/simulator.py +0 -41
  469. egse/slack.py +0 -61
  470. egse/socketdevice.py +0 -218
  471. egse/sockets.py +0 -218
  472. egse/spw.py +0 -1479
  473. egse/stages/__init__.py +0 -12
  474. egse/stages/aerotech/ensemble.py +0 -247
  475. egse/stages/aerotech/ensemble.yaml +0 -205
  476. egse/stages/aerotech/ensemble_controller.py +0 -275
  477. egse/stages/aerotech/ensemble_cs.py +0 -110
  478. egse/stages/aerotech/ensemble_interface.py +0 -132
  479. egse/stages/aerotech/ensemble_parameters.py +0 -433
  480. egse/stages/aerotech/ensemble_simulator.py +0 -27
  481. egse/stages/aerotech/mgse_sim.py +0 -193
  482. egse/stages/arun/smd3.py +0 -111
  483. egse/stages/arun/smd3.yaml +0 -68
  484. egse/stages/arun/smd3_controller.py +0 -472
  485. egse/stages/arun/smd3_cs.py +0 -112
  486. egse/stages/arun/smd3_interface.py +0 -53
  487. egse/stages/arun/smd3_simulator.py +0 -27
  488. egse/stages/arun/smd3_stop.py +0 -16
  489. egse/stages/huber/__init__.py +0 -49
  490. egse/stages/huber/smc9300.py +0 -904
  491. egse/stages/huber/smc9300.yaml +0 -63
  492. egse/stages/huber/smc9300_cs.py +0 -178
  493. egse/stages/huber/smc9300_devif.py +0 -345
  494. egse/stages/huber/smc9300_protocol.py +0 -111
  495. egse/stages/huber/smc9300_sim.py +0 -547
  496. egse/stages/huber/smc9300_ui.py +0 -973
  497. egse/state.py +0 -173
  498. egse/statemachine.py +0 -274
  499. egse/storage/__init__.py +0 -1004
  500. egse/storage/persistence.py +0 -2295
  501. egse/storage/storage.yaml +0 -72
  502. egse/storage/storage_cs.py +0 -214
  503. egse/styles/dark.qss +0 -343
  504. egse/styles/default.qss +0 -48
  505. egse/synoptics/__init__.py +0 -412
  506. egse/synoptics/syn.yaml +0 -9
  507. egse/synoptics/syn_cs.py +0 -195
  508. egse/system.py +0 -1408
  509. egse/tcs/__init__.py +0 -14
  510. egse/tcs/tcs.py +0 -874
  511. egse/tcs/tcs.yaml +0 -14
  512. egse/tcs/tcs_cs.py +0 -202
  513. egse/tcs/tcs_devif.py +0 -292
  514. egse/tcs/tcs_protocol.py +0 -177
  515. egse/tcs/tcs_sim.py +0 -177
  516. egse/tcs/tcs_ui.py +0 -543
  517. egse/tdms.py +0 -171
  518. egse/tempcontrol/__init__.py +0 -23
  519. egse/tempcontrol/agilent/agilent34970.py +0 -109
  520. egse/tempcontrol/agilent/agilent34970.yaml +0 -44
  521. egse/tempcontrol/agilent/agilent34970_cs.py +0 -116
  522. egse/tempcontrol/agilent/agilent34970_devif.py +0 -182
  523. egse/tempcontrol/agilent/agilent34970_protocol.py +0 -99
  524. egse/tempcontrol/agilent/agilent34972.py +0 -111
  525. egse/tempcontrol/agilent/agilent34972.yaml +0 -44
  526. egse/tempcontrol/agilent/agilent34972_cs.py +0 -117
  527. egse/tempcontrol/agilent/agilent34972_devif.py +0 -189
  528. egse/tempcontrol/agilent/agilent34972_protocol.py +0 -101
  529. egse/tempcontrol/beaglebone/beaglebone.py +0 -342
  530. egse/tempcontrol/beaglebone/beaglebone.yaml +0 -110
  531. egse/tempcontrol/beaglebone/beaglebone_cs.py +0 -117
  532. egse/tempcontrol/beaglebone/beaglebone_protocol.py +0 -135
  533. egse/tempcontrol/beaglebone/beaglebone_ui.py +0 -681
  534. egse/tempcontrol/digalox/digalox.py +0 -107
  535. egse/tempcontrol/digalox/digalox.yaml +0 -36
  536. egse/tempcontrol/digalox/digalox_cs.py +0 -112
  537. egse/tempcontrol/digalox/digalox_protocol.py +0 -55
  538. egse/tempcontrol/keithley/__init__.py +0 -33
  539. egse/tempcontrol/keithley/daq6510.py +0 -662
  540. egse/tempcontrol/keithley/daq6510.yaml +0 -105
  541. egse/tempcontrol/keithley/daq6510_cs.py +0 -163
  542. egse/tempcontrol/keithley/daq6510_devif.py +0 -343
  543. egse/tempcontrol/keithley/daq6510_protocol.py +0 -78
  544. egse/tempcontrol/keithley/daq6510_sim.py +0 -186
  545. egse/tempcontrol/lakeshore/__init__.py +0 -33
  546. egse/tempcontrol/lakeshore/lsci.py +0 -361
  547. egse/tempcontrol/lakeshore/lsci.yaml +0 -162
  548. egse/tempcontrol/lakeshore/lsci_cs.py +0 -174
  549. egse/tempcontrol/lakeshore/lsci_devif.py +0 -292
  550. egse/tempcontrol/lakeshore/lsci_protocol.py +0 -73
  551. egse/tempcontrol/lakeshore/lsci_ui.py +0 -389
  552. egse/tempcontrol/ni/__init__.py +0 -0
  553. egse/tempcontrol/spid/spid.py +0 -109
  554. egse/tempcontrol/spid/spid.yaml +0 -81
  555. egse/tempcontrol/spid/spid_controller.py +0 -279
  556. egse/tempcontrol/spid/spid_cs.py +0 -136
  557. egse/tempcontrol/spid/spid_protocol.py +0 -107
  558. egse/tempcontrol/spid/spid_ui.py +0 -727
  559. egse/tempcontrol/srs/__init__.py +0 -22
  560. egse/tempcontrol/srs/ptc10.py +0 -875
  561. egse/tempcontrol/srs/ptc10.yaml +0 -227
  562. egse/tempcontrol/srs/ptc10_cs.py +0 -128
  563. egse/tempcontrol/srs/ptc10_devif.py +0 -118
  564. egse/tempcontrol/srs/ptc10_protocol.py +0 -42
  565. egse/tempcontrol/srs/ptc10_ui.py +0 -906
  566. egse/ups/apc/apc.py +0 -236
  567. egse/ups/apc/apc.yaml +0 -45
  568. egse/ups/apc/apc_cs.py +0 -101
  569. egse/ups/apc/apc_protocol.py +0 -125
  570. egse/user.yaml +0 -7
  571. egse/vacuum/beaglebone/beaglebone.py +0 -149
  572. egse/vacuum/beaglebone/beaglebone.yaml +0 -44
  573. egse/vacuum/beaglebone/beaglebone_cs.py +0 -108
  574. egse/vacuum/beaglebone/beaglebone_devif.py +0 -164
  575. egse/vacuum/beaglebone/beaglebone_protocol.py +0 -193
  576. egse/vacuum/beaglebone/beaglebone_ui.py +0 -638
  577. egse/vacuum/instrutech/igm402.py +0 -92
  578. egse/vacuum/instrutech/igm402.yaml +0 -90
  579. egse/vacuum/instrutech/igm402_controller.py +0 -128
  580. egse/vacuum/instrutech/igm402_cs.py +0 -108
  581. egse/vacuum/instrutech/igm402_interface.py +0 -49
  582. egse/vacuum/instrutech/igm402_simulator.py +0 -36
  583. egse/vacuum/keller/kellerBus.py +0 -256
  584. egse/vacuum/keller/leo3.py +0 -102
  585. egse/vacuum/keller/leo3.yaml +0 -38
  586. egse/vacuum/keller/leo3_controller.py +0 -83
  587. egse/vacuum/keller/leo3_cs.py +0 -101
  588. egse/vacuum/keller/leo3_interface.py +0 -33
  589. egse/vacuum/mks/evision.py +0 -86
  590. egse/vacuum/mks/evision.yaml +0 -75
  591. egse/vacuum/mks/evision_cs.py +0 -101
  592. egse/vacuum/mks/evision_devif.py +0 -316
  593. egse/vacuum/mks/evision_interface.py +0 -60
  594. egse/vacuum/mks/evision_simulator.py +0 -24
  595. egse/vacuum/mks/evision_ui.py +0 -704
  596. egse/vacuum/pfeiffer/acp40.py +0 -87
  597. egse/vacuum/pfeiffer/acp40.yaml +0 -60
  598. egse/vacuum/pfeiffer/acp40_controller.py +0 -117
  599. egse/vacuum/pfeiffer/acp40_cs.py +0 -109
  600. egse/vacuum/pfeiffer/acp40_interface.py +0 -40
  601. egse/vacuum/pfeiffer/acp40_simulator.py +0 -39
  602. egse/vacuum/pfeiffer/tc400.py +0 -113
  603. egse/vacuum/pfeiffer/tc400.yaml +0 -83
  604. egse/vacuum/pfeiffer/tc400_controller.py +0 -140
  605. egse/vacuum/pfeiffer/tc400_cs.py +0 -109
  606. egse/vacuum/pfeiffer/tc400_interface.py +0 -70
  607. egse/vacuum/pfeiffer/tc400_simulator.py +0 -24
  608. egse/vacuum/pfeiffer/tpg261.py +0 -81
  609. egse/vacuum/pfeiffer/tpg261.yaml +0 -66
  610. egse/vacuum/pfeiffer/tpg261_controller.py +0 -150
  611. egse/vacuum/pfeiffer/tpg261_cs.py +0 -109
  612. egse/vacuum/pfeiffer/tpg261_interface.py +0 -60
  613. egse/vacuum/pfeiffer/tpg261_simulator.py +0 -24
  614. egse/version.py +0 -174
  615. egse/visitedpositions.py +0 -398
  616. egse/windowing.py +0 -213
  617. egse/zmq/__init__.py +0 -28
  618. egse/zmq/spw.py +0 -160
  619. egse/zmq_ser.py +0 -41
  620. scripts/alerts/cold.yaml +0 -278
  621. scripts/alerts/example_alerts.yaml +0 -54
  622. scripts/alerts/transition.yaml +0 -14
  623. scripts/alerts/warm.yaml +0 -49
  624. scripts/analyse_n_fee_hk_data.py +0 -44
  625. scripts/check_hdf5_files.py +0 -192
  626. scripts/check_register_sync.py +0 -47
  627. scripts/create_hdf5_report.py +0 -295
  628. scripts/csl_model.py +0 -436
  629. scripts/csl_restore_setup.py +0 -230
  630. scripts/export-grafana-dashboards.py +0 -50
  631. scripts/fdir/cs_recovery/fdir_cs_recovery.py +0 -59
  632. scripts/fdir/fdir_table.yaml +0 -70
  633. scripts/fdir/fdir_test_recovery.py +0 -11
  634. scripts/fdir/hw_recovery/fdir_agilent_hw_recovery.py +0 -73
  635. scripts/fdir/limit_recovery/fdir_agilent_limit.py +0 -64
  636. scripts/fdir/limit_recovery/fdir_bb_heater_limit.py +0 -61
  637. scripts/fdir/limit_recovery/fdir_ensemble_limit.py +0 -33
  638. scripts/fdir/limit_recovery/fdir_pressure_limit_recovery.py +0 -71
  639. scripts/fix_csv.py +0 -80
  640. scripts/n_fee_supply_voltage_calculation.py +0 -92
  641. scripts/playground.py +0 -30
  642. scripts/print_hdf5_hk_data.py +0 -68
  643. scripts/print_register_map.py +0 -43
  644. scripts/sron/commanding/control_heaters.py +0 -44
  645. scripts/sron/commanding/pumpdown.py +0 -46
  646. scripts/sron/commanding/set_pid_setpoint.py +0 -19
  647. scripts/sron/commanding/shutdown_bbb_heaters.py +0 -10
  648. scripts/sron/commanding/shutdown_pumps.py +0 -33
  649. scripts/sron/tm_gen/tm_gen_agilent.py +0 -38
  650. scripts/sron/tm_gen/tm_gen_heaters.py +0 -4
  651. scripts/sron/tm_gen/tm_gen_spid.py +0 -13
  652. scripts/update_operational_cgse.py +0 -268
  653. scripts/update_operational_cgse_old.py +0 -273
egse/confman/__init__.py DELETED
@@ -1,1015 +0,0 @@
1
- """
2
- This module provides configuration management for the Common-EGSE.
3
-
4
- The configuration manager knows about the configuration of the system and the test setup. It's
5
- main responsibility is to maintain the setup of the tests that are performed. It is the single
6
- point access for all configuration information.
7
-
8
- ## The Configuration aka Setup
9
-
10
- The Setup contains the identification of all the devices, mechanisms, controllers etc. that are
11
- used for a particular test. For each of these items the Setup contains hardware and software
12
- version, conversion and calibration information, location, components, specific settings,
13
- defaults, in a word, all information that is needed to uniquely identify the components,
14
- and to reproduce the test under the same circumstances. The details for the Setup are explained
15
- in the `egse.setup` module.
16
-
17
- ## Prerequisites:
18
-
19
- When the configuration manager (`cm_cs`) is started, no Setup is loaded. The configuration
20
- manager will then be in a default Setup state without any devices configured. This is called the
21
- _Zero_ Setup. The only keyword/attribute available from this Setup is `site_id`.
22
-
23
- ## Setup commands
24
-
25
- The main purpose of the configuration manager is to maintain and manage Setups. These Setups
26
- will reside in a GitHub repository for which the `cm_cs` has access to read and write Setups. The
27
- `cm_cs` provides all configuration information on request with the following commands that
28
- are available from the `ConfigurationManagerProxy`.
29
-
30
- #### `list_setups()`
31
-
32
- You can request a list of available Setups with the `list_setups` command. This function takes
33
- keyword arguments which are the attributes of the Setup and compares the attribute with the
34
- given value. An example should make this clear. A setup has a `site_id` and for the CSL site
35
- also a `position`. You can access these value as follows:
36
-
37
- >>> from egse.state import GlobalState
38
- >>> setup = GlobalState.setup
39
- >>> setup.site_id
40
- 'CSL'
41
- >>> setup.position
42
- 2
43
-
44
- When you now want a list of all Setups specific for CSL that were applicable for position 2,
45
- the following command will return that list.
46
- ```
47
- with ConfigurationManagerProxy() as cm:
48
- print(cm.list_setups(site_id="CSL", position=2))
49
- ```
50
- When you need to know which of these setups has the PUNA Hexapod with id=172543, add this
51
- attribute as a keyword.
52
- ```
53
- with ConfigurationManagerProxy() as cm:
54
- print(cm.list_setups(site_id="CSL", position=2, gse__hexapod__ID=172543))
55
- ```
56
- When multiple attributes are specified, they are checked using a logical AND, not a logical OR,
57
- meaning they have to meet _every_ attribute passed in and not just one of them.
58
-
59
- You probably also noticed that instead of using the normal dot-notation to reach the hexapod id,
60
- e.g. `gse.hexapod.ID`, we use double underscores to replace the dots. The reason for that is
61
- that you can not have dots in keyword argument names. When you put a dot, you will get a
62
- `SyntaxError`.
63
-
64
- #### `load_setup(setup_id: int)`
65
-
66
- Load a new Setup into the configuration manager. This command can only be called outside the
67
- scope of an observation and will not have any effect when an observation is currently running.
68
- Since the `cm_cs` knowns what the site_id is, the Setup for the current site is loaded
69
- automativally.
70
-
71
- #### `get_setup()`
72
-
73
- Returns the Setup that is currently loaded on the configuration manager.
74
-
75
-
76
- ## Observation (aka Test) Commands
77
-
78
- The configuration manager needs to know when an observation is started. It will keep track and
79
- inform clients of the running observation.
80
-
81
- #### `start_observation()`
82
-
83
- This command starts a new observation. This will assign an new unique observation
84
- identifier (`obsid`) for the observation and inform the Storage Manager that a new test has been
85
- started with that `obsid`. A new test can not start before the previous test has been finished.
86
- Also, a new Setup can not be loaded when an observation is running.
87
-
88
- #### `end_observation()`
89
-
90
- This command ends the current observation and notifies the Storage Manager that the test
91
- has been ended.
92
-
93
- #### `get_obsid()`
94
-
95
- Returns the observation identifier of the currently running observation.
96
-
97
-
98
- ## Convenience Functions
99
-
100
- The package also defines a number of convenience functions that simplify the communication
101
- with the configuration manager `cm_cs`.
102
-
103
- #### `is_configuration_manager_active()`
104
-
105
- A function that checks if the `cm_cs` is running and responding to commands. This function makes
106
- a connection with the `cm_cs` and sends it a _Ping_ command. This is the recommended way to check
107
- the availability of the configuration manager.
108
-
109
- """
110
- from __future__ import annotations
111
-
112
- import logging
113
- import operator
114
- import subprocess
115
- import textwrap
116
- import threading
117
- from pathlib import Path
118
- from typing import NamedTuple
119
- from typing import Optional
120
- from typing import Union
121
-
122
- import git
123
- import rich
124
- from git import GitCommandError
125
- from prometheus_client import Gauge
126
-
127
- from egse.command import ClientServerCommand
128
- from egse.command import stringify_function_call
129
- from egse.config import find_file
130
- from egse.config import find_files
131
- from egse.config import get_common_egse_root
132
- from egse.control import ControlServer
133
- from egse.control import Failure
134
- from egse.control import Response
135
- from egse.control import Success
136
- from egse.control import is_control_server_active
137
- from egse.decorators import dynamic_interface
138
- from egse.decorators import static_vars
139
- from egse.exceptions import InternalError
140
- from egse.obsid import ObservationIdentifier
141
- from egse.protocol import CommandProtocol
142
- from egse.proxy import Proxy
143
- from egse.settings import Settings
144
- from egse.settings import SettingsError
145
- from egse.setup import Setup
146
- from egse.setup import load_last_setup_id
147
- from egse.setup import save_last_setup_id
148
- from egse.system import filter_by_attr
149
- from egse.system import format_datetime
150
- from egse.system import replace_environment_variable
151
- from egse.version import VERSION
152
- from egse.zmq_ser import bind_address
153
- from egse.zmq_ser import connect_address
154
-
155
- LOGGER = logging.getLogger(__name__)
156
-
157
- CTRL_SETTINGS = Settings.load("Configuration Manager Control Server")
158
- SITE = Settings.load("SITE")
159
- COMMAND_SETTINGS = Settings.load(filename="confman.yaml")
160
- REPO = Settings.load("REPO")
161
-
162
- CM_SETUP_ID = Gauge("CM_SETUP_ID", 'Setup ID')
163
- CM_TEST_ID = Gauge("CM_TEST_ID", 'Test ID')
164
-
165
- def _push_setup_to_repo(filename: str, commit_msg: str) -> Failure | Success:
166
- """
167
- Push the Setup file to the `plato-cgse-conf` repository on GitHub.
168
-
169
- Args:
170
- filename: the basename of the new Setup file
171
-
172
- Returns:
173
- None.
174
- """
175
-
176
- repo_workdir = REPO.PLATO_CGSE_CONF
177
- repo_workdir = replace_environment_variable(repo_workdir)
178
- if repo_workdir is None:
179
- msg = textwrap.dedent(
180
- """\
181
- Couldn't determine the repository location for plato-cgse-conf.
182
- Check if the environment variable 'PLATO_CONF_REPO_LOCATION' is set
183
- before starting the configuration manager.
184
- """
185
- )
186
- LOGGER.error(msg)
187
- return Failure(msg)
188
-
189
- repo = git.Repo(repo_workdir)
190
-
191
- if repo.is_dirty():
192
- LOGGER.warning(
193
- f"The plato-cgse-conf repository is dirty. Check the git status at '{repo_workdir}'.")
194
-
195
- untracked = repo.untracked_files
196
-
197
- if len(untracked) != 1:
198
- msg = textwrap.dedent(
199
- f"""\
200
- The number of untracked files ({len(untracked)}) in the plato-cgse-conf repository doesn't match
201
- the expected. Check the git status at '{repo_workdir}' on the egse-server.
202
- Only '{filename}' should be untracked.
203
-
204
- Untracked files: {untracked}
205
- """
206
- )
207
- LOGGER.error(msg)
208
- return Failure(msg)
209
-
210
- # match the filename to extract the full path to the file
211
-
212
- untracked = [x for x in untracked if filename in x]
213
- if (n := len(untracked)) != 1:
214
- msg = f"There should be one match for the filename, found {n}{'' if n == 0 else untracked}."
215
- LOGGER.error(msg)
216
- return Failure(msg)
217
-
218
- untracked = untracked[0]
219
-
220
- # The response is a list of tuples containing the path of the file added to the stages/index.
221
-
222
- try:
223
- response = repo.index.add(untracked)
224
- # assert response[0].path == untracked
225
- except FileNotFoundError:
226
- # if for some reason the untracked file can not be found, should not happen..
227
- LOGGER.warning(
228
- f"Untracked file {untracked} not found. Check the git status at {repo_workdir}."
229
- )
230
-
231
- # The response is a Commit object containing e.g. the commit message, the hash, the author, ...
232
-
233
- response = repo.index.commit(message=commit_msg)
234
-
235
- # The response is a list of FetchInfo instances
236
- # We need this `pull` command before we will push the changes because otherwise the push will
237
- # be rejected, see https://github.com/IvS-KULeuven/plato-common-egse/issues/2027. The problem
238
- # should not abort the submit command, but needs to be logged.
239
-
240
- try:
241
- response = repo.remote('upload').pull("main")
242
- except Exception as exc:
243
- LOGGER.error(exc, exc_info=True)
244
-
245
- # The response is a PushInfo object
246
-
247
- try:
248
- response = repo.remote('upload').push("main")
249
- except ValueError as exc:
250
- LOGGER.error(exc, exc_info=True)
251
- return Failure(f"Push of setup [{filename}] failed", exc)
252
- except GitCommandError as exc:
253
- LOGGER.error(exc, exc_info=True)
254
- return Failure(f"Push of setup [{filename}] failed", exc)
255
-
256
- return Success(f"Successfully pushed the setup to the repo {repo}")
257
-
258
- # We have seen that especially when listing the setups, we have a performance problem.
259
- # Therefore, we implement a cache for the Setup info that we use in different functions.
260
- #
261
- # The key is the Setup ID
262
- # The value is the named tuple SetupInfo
263
-
264
- _cached_setup_info = {}
265
-
266
-
267
- class SetupInfo(NamedTuple):
268
- path: Path
269
- site_id: str
270
- cam_id: str
271
- description: str
272
-
273
-
274
- def _populate_cached_setup_info():
275
- """
276
- Populates the internal cache of Setup information.
277
-
278
- Raises:
279
- InternalError when a Setup is loaded that doesn't have an ID associated.
280
-
281
- """
282
- global _cached_setup_info
283
-
284
- LOGGER.info("Populating cache with Setup Info.")
285
-
286
- location = replace_environment_variable(CTRL_SETTINGS.FILE_STORAGE_LOCATION)
287
- data_conf_location = Path(location) if location else get_common_egse_root()
288
-
289
- setup_info = {}
290
-
291
- for fn in find_files(pattern="SETUP*", root=data_conf_location):
292
- setup = Setup.from_yaml_file(fn)
293
- if id := setup.get_id():
294
- id = int(id)
295
- site_id = _get_site_id_for_setup(setup)
296
- cam_id = _get_cam_id_for_setup(setup)
297
- description = _get_description_for_setup(setup)
298
- setup_info[id] = SetupInfo(fn, site_id, cam_id, description)
299
- else:
300
- raise InternalError(f"Setup loaded without an ID, {fn=}")
301
-
302
- _cached_setup_info = dict(sorted(setup_info.items()))
303
-
304
- LOGGER.info("SetupInfo cache populated.")
305
-
306
-
307
- def _add_setup_info_to_cache(setup: Setup):
308
- global _cached_setup_info
309
-
310
- if (_id := setup.get_id()) is None:
311
- raise InternalError(f"Setup loaded without an ID, {setup=!s}")
312
-
313
- if (_fn := setup.get_filename()) is None:
314
- raise InternalError(f"Setup with id={_id} has no filename associated.")
315
-
316
- _id = int(_id)
317
- _fn = Path(_fn)
318
-
319
- site_id = _get_site_id_for_setup(setup)
320
- cam_id = _get_cam_id_for_setup(setup)
321
- description = _get_description_for_setup(setup)
322
-
323
- _cached_setup_info[_id] = SetupInfo(_fn, site_id, cam_id, description)
324
-
325
-
326
- def _print_cached_setup_info():
327
- global _cached_setup_info
328
-
329
- rich.print(_cached_setup_info)
330
-
331
-
332
- def _get_cached_setup_info(setup_id: int) -> Optional[SetupInfo]:
333
- """Returns a setup info named tuple for the given setup id or None when no
334
- SetupInfo for the given setup_id is available.."""
335
- global _cached_setup_info
336
-
337
- return _cached_setup_info.get(setup_id)
338
-
339
-
340
- def _reload_cached_setup_info():
341
-
342
- try:
343
- Setup.from_yaml_file.cache_clear()
344
- except AttributeError:
345
- LOGGER.warning("Setup.from_yaml_file() method is not decorated with an lru_cache.")
346
-
347
- _populate_cached_setup_info()
348
-
349
-
350
- def is_configuration_manager_active(timeout: float = 0.5):
351
- """
352
- Checks whether the Configuration Manager is running.
353
-
354
- Args:
355
- timeout (float): Timeout when waiting for a reply [seconds, default=0.01]
356
-
357
- Returns:
358
- True if the Configuration Manager is running and replied with the expected answer.
359
- """
360
-
361
- endpoint = connect_address(
362
- CTRL_SETTINGS.PROTOCOL, CTRL_SETTINGS.HOSTNAME, CTRL_SETTINGS.COMMANDING_PORT
363
- )
364
-
365
- return is_control_server_active(endpoint, timeout)
366
-
367
-
368
- def _construct_filename(site_id: str, setup_id: int, creation_time: str = None):
369
- """Construct a filename for a Setup.
370
-
371
- FIXME: describe the restrictions on file naming and how they are parsed etc.
372
-
373
- Args:
374
- site_id (str): the site identifier
375
- setup_id (int): the setup identifier
376
- creation_time (str): the date-time shall be formatted as `YYMMDD_HHMMSS`
377
- """
378
-
379
- if creation_time:
380
- filename = f"SETUP_{site_id}_{setup_id:05d}_{creation_time}.yaml"
381
- else:
382
- filename = f"SETUP_{site_id}_{setup_id:05d}_{format_datetime(fmt='%y%m%d_%H%M%S')}.yaml"
383
-
384
- return filename
385
-
386
-
387
- def _get_description_for_setup(setup: Setup, setup_id: int = None) -> str:
388
- setup_id = setup_id or int(setup.get_id())
389
- try:
390
- description = setup.history.get(setup_id)
391
- except AttributeError:
392
- description = None
393
- return description or f"no description found for Setup {setup_id}"
394
-
395
-
396
- def _get_cam_id_for_setup(setup: Setup) -> str:
397
-
398
- try:
399
- if "id" in setup.camera:
400
- cam_id = setup.camera.id
401
- elif "ID" in setup.camera:
402
- cam_id = setup.camera.ID
403
- else:
404
- cam_id = None
405
- except AttributeError:
406
- cam_id = None
407
-
408
- return cam_id or "no cam_id"
409
-
410
-
411
- def _get_site_id_for_setup(setup: Setup) -> str:
412
-
413
- try:
414
- site_id = setup.site_id if "site_id" in setup else None
415
- except AttributeError:
416
- site_id = None
417
-
418
- return site_id or "no site_id"
419
-
420
-
421
- @static_vars(test_id=0)
422
- def create_obsid(last_obsid: str, site_id: str, setup_id: int):
423
- # This is method is currently just a prove of concept, the real thing should
424
- # read the LID, SID from the current Setup and then generate or keep track
425
- # of a TEST ID.
426
-
427
- # How do we guarantee a unique OBSID? OBSIDs need to be made persistent at least for the Site.
428
- # That way we can, when a new ObservationIdentifier is generated, check if it's indeed unique.
429
-
430
- if last_obsid:
431
- create_obsid.test_id = int(last_obsid.split(maxsplit=1)[0])
432
-
433
- create_obsid.test_id += 1
434
-
435
- # We need access to the setup, because we need the LabID, the SetupID
436
- # How do we define the configuration ID and Test ID?
437
-
438
- return ObservationIdentifier(site_id, setup_id, create_obsid.test_id)
439
-
440
-
441
- class ConfigurationManagerInterface:
442
- """
443
- This interface is for sending commands to the configuration manager to e.g. start and stop
444
- an observation/test, or get information about the Setups.
445
-
446
- The interface should be implemented by the `ConfigurationManagerController` and the
447
- `ConfigurationManagerProxy` (and possibly a `ConfigurationManagerSimulator` should we
448
- need that e.g. for testing purposes).
449
- """
450
-
451
- @dynamic_interface
452
- def start_observation(self, function_info: dict) -> Response:
453
- """Starts a new observation or test. The following actions will be taken:
454
-
455
- * create an observation identifier, aka `obsid`
456
- * notify the Storage Control Server that a new observation is started
457
- * return the generated `obsid`
458
-
459
- Args:
460
- function_info: dictionary with information about the function called
461
- Returns:
462
- `Success` (with `obsid` as `return_code`) or `Failure` when already in an observation
463
- or Storage returned Failure.
464
- """
465
- raise NotImplementedError
466
-
467
- @dynamic_interface
468
- def end_observation(self) -> Response:
469
- """Ends the current observation and notifies the Storage Control Server.
470
-
471
- Returns:
472
- `Success` when the observation could be closed properly and the Storage CS was notified
473
- or `Failure` otherwise.
474
- """
475
- raise NotImplementedError
476
-
477
- @dynamic_interface
478
- def get_obsid(self) -> Success:
479
- """Returns the current observation identifier. When no observation is running, `None` is
480
- returned as the `return_code` in `Success`.
481
-
482
- Returns:
483
- Always returns `Success` with current observation identifier, i.e. `obsid`.
484
- """
485
- raise NotImplementedError
486
-
487
- @dynamic_interface
488
- def load_setup(self, setup_id: int = None) -> Union[Setup, Failure]:
489
- raise NotImplementedError
490
-
491
- @dynamic_interface
492
- def get_setup(self, setup_id: int = None):
493
- raise NotImplementedError
494
-
495
- @dynamic_interface
496
- def reload_setups(self):
497
- raise NotImplementedError
498
-
499
- @dynamic_interface
500
- def list_setups(self, **attr):
501
- raise NotImplementedError
502
-
503
- @dynamic_interface
504
- def submit_setup(self, setup: Setup, description: str, replace: bool = True) -> Setup | None:
505
- raise NotImplementedError
506
-
507
- @dynamic_interface
508
- def get_setup_for_obsid(self, obsid):
509
- raise NotImplementedError
510
-
511
-
512
- class ConfigurationManagerController(ConfigurationManagerInterface):
513
- """Handles the commands that are sent to the configuration manager.
514
-
515
- .. note::
516
- The docstrings for each of the commands are in the `ConfigurationManagerInterface`.
517
- """
518
-
519
- def __init__(self):
520
-
521
- # Import these modules here as to optimize the import of classes and functions in other parts of the CGSE.
522
- # The CongifurationManagerController is only used by the CM CS and these Storage imports are only used in
523
- # this class and take too much loading time...
524
-
525
- from egse.storage import StorageProxy
526
- from egse.storage import is_storage_manager_active
527
- from egse.storage.persistence import TXT
528
-
529
- self._obsid: ObservationIdentifier | None = None
530
- self._setup_id: int | None = None
531
- self._camera_name: str | None = None
532
-
533
- if is_storage_manager_active():
534
- self._storage = StorageProxy()
535
- response = self._storage.register(
536
- {
537
- "origin": "obsid",
538
- "persistence_class": TXT,
539
- "prep": {"mode": "a", "ending": "\n"},
540
- "persistence_count": True,
541
- "filename": "obsid-table.txt",
542
- }
543
- )
544
- LOGGER.info(response)
545
- else:
546
- self._storage = None
547
- LOGGER.error("No Storage Manager available !!!!")
548
-
549
- # Find the location for the configuration data
550
-
551
- location = replace_environment_variable(CTRL_SETTINGS.FILE_STORAGE_LOCATION)
552
- self._data_conf_location = Path(location) if location else get_common_egse_root()
553
-
554
- # Populate the cache with information from the available Setups. This will also load each
555
- # Setup and cache them with the lru_cache decorator. Since this takes about 5s for 100
556
- # Setups, we run this function in a daemon thread in order not to block the cm_cs from
557
- # reacting to command requests.
558
-
559
- cache_thread = threading.Thread(target=_populate_cached_setup_info)
560
- cache_thread.daemon = True
561
- cache_thread.start()
562
-
563
- # Load the last used Setup
564
-
565
- setup_id = load_last_setup_id()
566
- self.load_setup(setup_id)
567
-
568
- def quit(self):
569
- if self._storage:
570
- self._storage.disconnect_cs()
571
-
572
- @property
573
- def data_location(self) -> Path:
574
- """Return the location of the configuration data, i.e. the Setup YAML files."""
575
- return self._data_conf_location
576
-
577
- def start_observation(self, function_info: dict) -> Response:
578
- if self._obsid is not None:
579
- return Failure(
580
- "An new observation can not be started before the previous observation is "
581
- "finished. You will need to first send an end_observation request to the "
582
- "configuration manager."
583
- )
584
-
585
- last_obsid = None
586
-
587
- if self._storage:
588
- last_obsid = self._storage.read({"origin": "obsid", "select": "last_line"})
589
- last_obsid = last_obsid.return_code if isinstance(last_obsid, Success) else None
590
-
591
- self._obsid = create_obsid(last_obsid, SITE.ID, self._setup_id)
592
-
593
- if self._storage:
594
- response = self._storage.start_observation(self._obsid, self._camera_name)
595
- else:
596
- return Failure(
597
- "Couldn't send start observation to Storage Manager, no Storage Manager available."
598
- )
599
-
600
- if not response.successful:
601
- self._obsid = None
602
- return Failure(
603
- "Sending a start_observation to the Storage Control Server failed",
604
- response,
605
- )
606
-
607
- description = function_info.pop("description", "")
608
- cmd = stringify_function_call(function_info).replace('\n', ' ')
609
-
610
- if description:
611
- cmd += f" [{description}]"
612
-
613
- response = self._storage.save(
614
- {
615
- "origin": "obsid",
616
- "data": f"{self._obsid.test_id:05d} "
617
- f"{self._obsid.lab_id} "
618
- f"{self._obsid.setup_id:05d} "
619
- f"{format_datetime()} "
620
- f"{cmd}",
621
- }
622
- )
623
-
624
- if isinstance(response, Failure):
625
- LOGGER.warning(
626
- f"There was a Failure when saving to the obsid-table: "
627
- f"{response}")
628
- else:
629
- LOGGER.info(f"Successfully created an observation with obsid={self._obsid}.")
630
-
631
- return Success("Returning the OBSID", self._obsid)
632
-
633
- def end_observation(self) -> Response:
634
- if not self._obsid:
635
- return Failure(
636
- "Received end_observation command while not currently in an observation context."
637
- )
638
-
639
- if self._storage:
640
- response = self._storage.end_observation(self._obsid)
641
- else:
642
- return Failure(
643
- "Couldn't send end observation to Storage Manager, no Storage Manager available."
644
- )
645
-
646
- if not response.successful:
647
- return Failure(
648
- "Sending an end_observation to the Storage Control Server failed.",
649
- response,
650
- )
651
-
652
- LOGGER.info(f"Successfully ended observation with obsid={self._obsid}.")
653
-
654
- self._obsid = None
655
-
656
- return Success("Successfully ended the observation.")
657
-
658
- def get_obsid(self) -> Success:
659
- if self._obsid:
660
- msg = "Returning the current OBSID."
661
- else:
662
- msg = "No observation running. Use start_observation() to start an observation."
663
- return Success(msg, self._obsid)
664
-
665
- def load_setup(self, setup_id: int = None) -> Union[Setup, Failure]:
666
- """Load the Setup with the given setup_id.
667
-
668
- Args:
669
- setup_id (int): the identifier for the requested Setup.
670
- Returns:
671
- The requested Setup.
672
- """
673
- # The current implementation is file based. The files have a strict naming convention and
674
- # are located in the `data/conf` directory.
675
- #
676
- # 1. Find the Setup for the given setup_id and the Site (is this read from the Settings
677
- # file, or set by some GUI or process?
678
- # 2. Load that Setup from its file at the default location
679
- # 3. Return an acknowledgement that the Setup is loaded on the CM_CS or not
680
-
681
- if setup_id is None:
682
- return Failure(
683
- f"No Setup ID was given, cannot load a Setup into the configuration manager. "
684
- f"If you wanted to get the current Setup from the configuration manager, use the "
685
- f"get_setup() method instead."
686
- )
687
-
688
- if self._obsid:
689
- return Failure(
690
- f"A new Setup can not be loaded when an observation is running. "
691
- f"The current obsid is {self._obsid}. Use `end_observation()` before "
692
- f"loading a new Setup."
693
- )
694
-
695
- setup_files = list(
696
- find_files(
697
- pattern=f"SETUP_{SITE.ID}_{setup_id:05d}_*.yaml", root=self._data_conf_location
698
- )
699
- )
700
-
701
- if len(setup_files) != 1:
702
- LOGGER.error(
703
- msg := f"Expected to find just one Setup YAML file, found {len(setup_files)}. "
704
- f"[{SITE.ID = }, {setup_id = }, data_conf_location={self._data_conf_location}]"
705
- )
706
- return Failure("Loading Setup", InternalError(msg))
707
-
708
- setup_file = setup_files[0]
709
-
710
- try:
711
- self._setup = Setup.from_yaml_file(setup_file)
712
- self._setup_id = setup_id
713
- self._camera_name = self._setup.camera.ID.lower()
714
- LOGGER.info(f"New Setup loaded from {setup_file}")
715
- save_last_setup_id(self._setup_id)
716
- return self._setup
717
- except SettingsError as exc:
718
- return Failure(f"The Setup file can not be loaded from {setup_file}.", exc)
719
- except AttributeError as exc:
720
- msg = f"The Setup [id={setup_id}] has no camera.ID entry."
721
- LOGGER.error(msg, exc_info=True)
722
- # FIXME: if we come here, shouldn't we load the zero Setup so that the problem of the
723
- # missing camera ID gets solved?
724
- return Failure(msg)
725
-
726
- def get_setup(self, setup_id: int = None) -> Union[Setup, Failure]:
727
- """
728
- Returns the Setup for the given setup_id. If no setup_id argument was provided,
729
- the current Setup from the configuration manager will be returned.
730
-
731
- This is a -read-only function.
732
- Under no circumstance will the Setup of the configuration manager be changed.
733
-
734
- Args:
735
- setup_id (int): the identifier for the requested Setup.
736
- Returns:
737
- The requested Setup.
738
- """
739
-
740
- if setup_id:
741
- # If a Setup ID is given, just load and return the Setup for that ID
742
- # The Setup is NOT added to the Configuration Manager as the current Setup.
743
-
744
- setup_files = list(
745
- find_files(
746
- pattern=f"SETUP_{SITE.ID}_{setup_id:05d}_*.yaml", root=self._data_conf_location
747
- )
748
- )
749
-
750
- if len(setup_files) != 1:
751
- LOGGER.error(
752
- msg := f"Expected to find just one Setup YAML file, found {len(setup_files)}."
753
- )
754
- return Failure("Expected only one Setup.", InternalError(msg))
755
-
756
- setup_file = setup_files[0]
757
-
758
- try:
759
- return Setup.from_yaml_file(setup_file)
760
- except SettingsError as exc:
761
- return Failure(f"The Setup file can not be loaded from {setup_file}.", exc)
762
-
763
- else:
764
- # No Setup ID was given, so we return the current Setup loaded in the Configuration Manager
765
-
766
- if self._setup:
767
- return self._setup
768
- else:
769
- return Failure("No Setup was loaded on the Configuration Manager.")
770
-
771
- def get_setup_id(self) -> int:
772
- """Returns the Setup identifier for the currently loaded Setup.
773
-
774
- Returns:
775
- The `setup_id` of the Setup loaded by the `cm_cs`, or None.
776
- """
777
-
778
- return self._setup_id
779
-
780
- def get_site_id(self) -> str:
781
- """Returns the Site identifier that is used by the configuration manager.
782
-
783
- Returns:
784
- The Site identifier as a string.
785
- """
786
-
787
- return SITE.ID
788
-
789
- def reload_setups(self):
790
- """
791
- Clears the cache and Reloads the available Setups.
792
-
793
- This function does not affect the currently loaded Setup.
794
- """
795
- _reload_cached_setup_info()
796
-
797
- def list_setups(self, **attr):
798
- """
799
- Returns a sorted list of all the available Setups for the current site. The list contains
800
- tuples with the following content: setup_id, site_id, description, cam_id.
801
-
802
- Args:
803
- **attr: see egse.system.filter_by_attr()
804
-
805
- Returns:
806
- A list with information on the available Setups.
807
- """
808
- # The current implementation is file based. The files have a strict naming convention and
809
- # are located in the `data/conf` directory.
810
- #
811
- # 1. Get a list of the Setup files from the default location, i.e. data/conf
812
- # 2. Prepare a list of tuples with that information ordered by Setup ID
813
- # 3. Return that list
814
-
815
- setup_list = []
816
-
817
- setups = [Setup.from_yaml_file(info.path) for info in _cached_setup_info.values()]
818
-
819
- setups = filter_by_attr(setups, **attr)
820
-
821
- for setup in setups:
822
- _, setup_site, setup_id, _ = str(setup._filename).split("_", maxsplit=3)
823
- description = _get_description_for_setup(setup, int(setup_id))
824
- cam_id = _get_cam_id_for_setup(setup)
825
- setup_list.append((setup_id, setup_site, description, cam_id))
826
-
827
- # Sort by site, then by id
828
-
829
- return sorted(setup_list, key=operator.itemgetter(1, 0), reverse=False)
830
-
831
- def get_setup_for_obsid(self, obsid):
832
- obsid = f"{obsid:05d}" if isinstance(obsid, int) else obsid
833
- rc = self._storage.read({"origin": "obsid", "select": ("startswith", obsid)})
834
- if rc.successful:
835
- # FIXME: this should be a function that can also be used in load_setup(),
836
- # because they do basically the same thing
837
- try:
838
- setup_id = int(rc.return_code[-1].split(maxsplit=3)[2])
839
- setup_file = find_file(
840
- name=f"SETUP_{SITE.ID}_{setup_id:05d}_*.yaml", root=self._data_conf_location
841
- )
842
- setup = Setup.from_yaml_file(setup_file)
843
- except (IndexError, SettingsError):
844
- setup = None
845
-
846
- return setup
847
-
848
- def submit_setup(self, setup: Setup, description: str, replace: bool = True):
849
-
850
- # 1. Determine the Site for this Setup, or should this be the Site that is known by the
851
- # CM_CS?
852
- # 2. Find the correct (next) number for the Setup for the given Site
853
- # 3. Do I want to make some comparison?
854
- # Do we need to keep a record from which this Setup is derived?
855
-
856
- # FIXME: define and handle exceptional conditions, like IOError
857
-
858
- if self._obsid is not None:
859
- return Failure(
860
- "An new Setup can not be submitted when an observation is running. You will need "
861
- "to first send an end_observation request to the configuration manager."
862
- )
863
-
864
- site = setup.site_id
865
-
866
- setup_id = self.get_next_setup_id_for_site(site)
867
-
868
- filename = _construct_filename(SITE.ID, setup_id)
869
-
870
- if not hasattr(setup, "history"):
871
- setup.history = {}
872
-
873
- setup.history.update({f"{setup_id}": description})
874
- setup.set_private_attribute("_setup_id", setup_id)
875
- setup.to_yaml_file(self._data_conf_location / filename)
876
-
877
- try:
878
- rc = _push_setup_to_repo(filename, description)
879
- if isinstance(rc, Failure):
880
- return rc
881
- _add_setup_info_to_cache(setup)
882
- except (Exception, ) as exc:
883
- msg = "Submit_setup could not complete it's task to send the new Setup to the repo."
884
- LOGGER.error(msg, exc_info=True)
885
- return Failure("Submit_setup could not complete it's task to send the new Setup to the repo.", exc)
886
- else:
887
- LOGGER.info(f"Successfully pushed Setup {setup_id} to the repository.")
888
-
889
- if replace:
890
- self._setup = setup
891
- self._setup_id = setup_id
892
- save_last_setup_id(setup_id)
893
-
894
- return setup
895
-
896
- def get_next_setup_id_for_site(self, site: str) -> int:
897
- """Return the next available Setup ID for the given Site.
898
-
899
- Args:
900
- site (str): site identification, e.g. CSL, SRON, ...
901
- """
902
- site = site or SITE.ID
903
- files = sorted(find_files(pattern=f"SETUP_{site}_*.yaml", root=self._data_conf_location))
904
- last_file = files[-1]
905
- setup_id = last_file.name.split("_")[2]
906
-
907
- return int(setup_id) + 1
908
-
909
-
910
- class ConfigurationManagerCommand(ClientServerCommand):
911
- pass
912
-
913
-
914
- class ConfigurationManagerProxy(Proxy, ConfigurationManagerInterface):
915
- """
916
- The Configuration Manager Proxy class is used to connect to the Configuration Manager
917
- Control Server and send commands and requests for the configuration manager.
918
- """
919
-
920
- def __init__(
921
- self,
922
- protocol=CTRL_SETTINGS.PROTOCOL,
923
- hostname=CTRL_SETTINGS.HOSTNAME,
924
- port=CTRL_SETTINGS.COMMANDING_PORT,
925
- ):
926
- """
927
- Args:
928
- protocol: the transport protocol [default is taken from settings file]
929
- hostname: location of the control server (IP address) [default is taken
930
- from settings file]
931
- port: TCP port on which the control server is listening for commands
932
- [default is taken from settings file]
933
- """
934
- super().__init__(connect_address(protocol, hostname, port))
935
-
936
-
937
- class ConfigurationManagerProtocol(CommandProtocol):
938
- def __init__(self, control_server: ControlServer):
939
- super().__init__()
940
- self.control_server = control_server
941
-
942
- self.controller = ConfigurationManagerController()
943
-
944
- self.load_commands(
945
- COMMAND_SETTINGS.Commands,
946
- ConfigurationManagerCommand,
947
- ConfigurationManagerController,
948
- )
949
-
950
- self.build_device_method_lookup_table(self.controller)
951
-
952
- self.cgse_version = VERSION
953
-
954
- try:
955
- self.git_version = subprocess.check_output(
956
- ["git", "describe", "--tags", "--long"], stderr=subprocess.STDOUT)
957
- self.git_version = self.git_version.strip().decode("ascii")
958
- except subprocess.CalledProcessError as exc:
959
- LOGGER.debug(
960
- f"A git error occurred for the `git describe` command: {exc}", stack_info=True)
961
- self.git_version = "no git-version determined"
962
-
963
- def get_bind_address(self):
964
- return bind_address(
965
- self.control_server.get_communication_protocol(),
966
- self.control_server.get_commanding_port(),
967
- )
968
-
969
- def get_status(self) -> dict:
970
- status = super().get_status()
971
-
972
- status.update({"obsid": self.controller.get_obsid().return_code})
973
- status.update({"setup": self.controller.get_setup()})
974
-
975
- return status
976
-
977
- def get_housekeeping(self) -> dict:
978
- obsid = self.controller.get_obsid().return_code
979
- test_id = obsid.test_id if obsid else float('nan')
980
- setup_id = self.controller.get_setup_id()
981
- site_id = self.controller.get_site_id()
982
-
983
- hk = {
984
- "timestamp": format_datetime(),
985
- "CM_SITE_ID": site_id,
986
- "CM_SETUP_ID": setup_id,
987
- "CM_TEST_ID": test_id,
988
- "CM_OBSID": obsid,
989
- "CM_CGSE_VERSION": self.cgse_version,
990
- "CM_GIT_VERSION": self.git_version,
991
- }
992
-
993
- # Update the metrics
994
-
995
- CM_SETUP_ID.set(float(setup_id))
996
- CM_TEST_ID.set(float(test_id))
997
-
998
- return hk
999
-
1000
- def quit(self):
1001
- self.controller.quit()
1002
-
1003
-
1004
- # The following functions are defined here to allow them to be used in the list_setups() method
1005
- # and be pickled and passed over ZeroMQ.
1006
-
1007
-
1008
- def is_in(a, b):
1009
- """Returns result of `a in b`."""
1010
- return a in b
1011
-
1012
-
1013
- def is_not_in(a, b):
1014
- """Returns result of `a not in b`."""
1015
- return a not in b