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