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.
- README.md +27 -0
- bump.py +77 -0
- cgse-2024.1.3.dist-info/METADATA +41 -0
- cgse-2024.1.3.dist-info/RECORD +5 -0
- {cgse-2023.38.0.dist-info → cgse-2024.1.3.dist-info}/WHEEL +1 -2
- cgse-2023.38.0.dist-info/COPYING +0 -674
- cgse-2023.38.0.dist-info/COPYING.LESSER +0 -165
- cgse-2023.38.0.dist-info/METADATA +0 -144
- cgse-2023.38.0.dist-info/RECORD +0 -649
- cgse-2023.38.0.dist-info/entry_points.txt +0 -75
- cgse-2023.38.0.dist-info/top_level.txt +0 -2
- egse/__init__.py +0 -12
- egse/__main__.py +0 -32
- egse/aeu/aeu.py +0 -5235
- egse/aeu/aeu_awg.yaml +0 -265
- egse/aeu/aeu_crio.yaml +0 -273
- egse/aeu/aeu_cs.py +0 -626
- egse/aeu/aeu_devif.py +0 -321
- egse/aeu/aeu_main_ui.py +0 -912
- egse/aeu/aeu_metrics.py +0 -131
- egse/aeu/aeu_protocol.py +0 -463
- egse/aeu/aeu_psu.yaml +0 -204
- egse/aeu/aeu_ui.py +0 -873
- egse/aeu/arbdata/FccdRead.arb +0 -2
- egse/aeu/arbdata/FccdRead_min_points.arb +0 -2
- egse/aeu/arbdata/HeaterSync_FccdRead.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead25.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead31_25.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead37_50.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead43_75.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead50.arb +0 -2
- egse/aeu/arbdata/Heater_FccdRead_min_points.arb +0 -2
- egse/aeu/arbdata/ccdRead25.arb +0 -2
- egse/aeu/arbdata/ccdRead25_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead31_25.arb +0 -2
- egse/aeu/arbdata/ccdRead31_25_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead37_50.arb +0 -2
- egse/aeu/arbdata/ccdRead37_50_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead43_75.arb +0 -2
- egse/aeu/arbdata/ccdRead43_75_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead50.arb +0 -2
- egse/aeu/arbdata/ccdRead50_150ms.arb +0 -2
- egse/alert/__init__.py +0 -1049
- egse/alert/alertman.yaml +0 -37
- egse/alert/alertman_cs.py +0 -234
- egse/alert/alertman_ui.py +0 -603
- egse/alert/gsm/beaglebone.py +0 -138
- egse/alert/gsm/beaglebone.yaml +0 -51
- egse/alert/gsm/beaglebone_cs.py +0 -108
- egse/alert/gsm/beaglebone_devif.py +0 -130
- egse/alert/gsm/beaglebone_protocol.py +0 -48
- egse/bits.py +0 -318
- egse/camera.py +0 -44
- egse/collimator/__init__.py +0 -0
- egse/collimator/fcul/__init__.py +0 -0
- egse/collimator/fcul/ogse.py +0 -1077
- egse/collimator/fcul/ogse.yaml +0 -14
- egse/collimator/fcul/ogse_cs.py +0 -154
- egse/collimator/fcul/ogse_devif.py +0 -358
- egse/collimator/fcul/ogse_protocol.py +0 -129
- egse/collimator/fcul/ogse_sim.py +0 -431
- egse/collimator/fcul/ogse_ui.py +0 -1108
- egse/command.py +0 -699
- egse/config.py +0 -410
- egse/confman/__init__.py +0 -1015
- egse/confman/confman.yaml +0 -67
- egse/confman/confman_cs.py +0 -239
- egse/confman/confman_ui.py +0 -381
- egse/confman/setup_ui.py +0 -565
- egse/control.py +0 -442
- egse/coordinates/__init__.py +0 -531
- egse/coordinates/avoidance.py +0 -103
- egse/coordinates/cslmodel.py +0 -127
- egse/coordinates/laser_tracker_to_dict.py +0 -120
- egse/coordinates/point.py +0 -707
- egse/coordinates/pyplot.py +0 -195
- egse/coordinates/referenceFrame.py +0 -1279
- egse/coordinates/refmodel.py +0 -737
- egse/coordinates/rotationMatrix.py +0 -85
- egse/coordinates/transform3d_addon.py +0 -419
- egse/csl/__init__.py +0 -50
- egse/csl/commanding.py +0 -78
- egse/csl/icons/hexapod-connected-selected.svg +0 -30
- egse/csl/icons/hexapod-connected.svg +0 -30
- egse/csl/icons/hexapod-homing-selected.svg +0 -68
- egse/csl/icons/hexapod-homing.svg +0 -68
- egse/csl/icons/hexapod-retract-selected.svg +0 -56
- egse/csl/icons/hexapod-retract.svg +0 -51
- egse/csl/icons/hexapod-zero-selected.svg +0 -56
- egse/csl/icons/hexapod-zero.svg +0 -56
- egse/csl/icons/logo-puna.svg +0 -92
- egse/csl/icons/stop.svg +0 -1
- egse/csl/initialisation.py +0 -102
- egse/csl/mech_pos_settings.yaml +0 -18
- egse/das.py +0 -1247
- egse/das.yaml +0 -7
- egse/data/conf/SETUP_CSL_00000_170620_150000.yaml +0 -5
- egse/data/conf/SETUP_CSL_00001_170620_151010.yaml +0 -69
- egse/data/conf/SETUP_CSL_00002_170620_151020.yaml +0 -69
- egse/data/conf/SETUP_CSL_00003_170620_151030.yaml +0 -69
- egse/data/conf/SETUP_CSL_00004_170620_151040.yaml +0 -69
- egse/data/conf/SETUP_CSL_00005_170620_151050.yaml +0 -69
- egse/data/conf/SETUP_CSL_00006_170620_151060.yaml +0 -69
- egse/data/conf/SETUP_CSL_00007_170620_151070.yaml +0 -69
- egse/data/conf/SETUP_CSL_00008_170620_151080.yaml +0 -75
- egse/data/conf/SETUP_CSL_00010_210308_083016.yaml +0 -138
- egse/data/conf/SETUP_INTA_00000_170620_150000.yaml +0 -4
- egse/data/conf/SETUP_SRON_00000_170620_150000.yaml +0 -4
- egse/decorators.py +0 -415
- egse/device.py +0 -269
- egse/dpu/__init__.py +0 -2681
- egse/dpu/ccd_ui.py +0 -508
- egse/dpu/dpu.py +0 -786
- egse/dpu/dpu.yaml +0 -153
- egse/dpu/dpu_cs.py +0 -272
- egse/dpu/dpu_ui.py +0 -668
- egse/dpu/fitsgen.py +0 -2077
- egse/dpu/fitsgen_test.py +0 -752
- egse/dpu/fitsgen_ui.py +0 -399
- egse/dpu/hdf5_model.py +0 -332
- egse/dpu/hdf5_ui.py +0 -277
- egse/dpu/hdf5_viewer.py +0 -506
- egse/dpu/hk_ui.py +0 -468
- egse/dpu_commands.py +0 -81
- egse/dsi/constants.py +0 -220
- egse/dsi/esl.py +0 -870
- egse/dsi/rmap.py +0 -1042
- egse/dsi/rmapci.py +0 -37
- egse/dsi/spw.py +0 -154
- egse/dsi/spw_state.py +0 -29
- egse/dummy.py +0 -258
- egse/dyndummy.py +0 -179
- egse/env.py +0 -278
- egse/exceptions.py +0 -88
- egse/fdir/__init__.py +0 -28
- egse/fdir/fdir_manager.py +0 -85
- egse/fdir/fdir_manager.yaml +0 -51
- egse/fdir/fdir_manager_controller.py +0 -228
- egse/fdir/fdir_manager_cs.py +0 -164
- egse/fdir/fdir_manager_interface.py +0 -25
- egse/fdir/fdir_remote.py +0 -73
- egse/fdir/fdir_remote.yaml +0 -37
- egse/fdir/fdir_remote_controller.py +0 -50
- egse/fdir/fdir_remote_cs.py +0 -97
- egse/fdir/fdir_remote_interface.py +0 -14
- egse/fdir/fdir_remote_popup.py +0 -31
- egse/fee/__init__.py +0 -114
- egse/fee/f_fee_register.yaml +0 -43
- egse/fee/fee.py +0 -631
- egse/fee/feesim.py +0 -750
- egse/fee/n_fee_hk.py +0 -761
- egse/fee/nfee.py +0 -187
- egse/filterwheel/__init__.py +0 -4
- egse/filterwheel/eksma/__init__.py +0 -24
- egse/filterwheel/eksma/fw8smc4.py +0 -661
- egse/filterwheel/eksma/fw8smc4.yaml +0 -121
- egse/filterwheel/eksma/fw8smc4_cs.py +0 -144
- egse/filterwheel/eksma/fw8smc4_devif.py +0 -473
- egse/filterwheel/eksma/fw8smc4_protocol.py +0 -81
- egse/filterwheel/eksma/fw8smc4_ui.py +0 -940
- egse/filterwheel/eksma/fw8smc5.py +0 -111
- egse/filterwheel/eksma/fw8smc5.yaml +0 -105
- egse/filterwheel/eksma/fw8smc5_controller.py +0 -307
- egse/filterwheel/eksma/fw8smc5_cs.py +0 -141
- egse/filterwheel/eksma/fw8smc5_interface.py +0 -65
- egse/filterwheel/eksma/fw8smc5_simulator.py +0 -29
- egse/filterwheel/eksma/fw8smc5_ui.py +0 -1068
- egse/filterwheel/eksma/testpythonfw.py +0 -215
- egse/fov/__init__.py +0 -65
- egse/fov/fov_hk.py +0 -712
- egse/fov/fov_ui.py +0 -861
- egse/fov/fov_ui_controller.py +0 -140
- egse/fov/fov_ui_model.py +0 -200
- egse/fov/fov_ui_view.py +0 -345
- egse/gimbal/__init__.py +0 -32
- egse/gimbal/symetrie/__init__.py +0 -26
- egse/gimbal/symetrie/alpha.py +0 -586
- egse/gimbal/symetrie/generic_gimbal_ui.py +0 -1521
- egse/gimbal/symetrie/gimbal.py +0 -877
- egse/gimbal/symetrie/gimbal.yaml +0 -168
- egse/gimbal/symetrie/gimbal_cs.py +0 -183
- egse/gimbal/symetrie/gimbal_protocol.py +0 -135
- egse/gimbal/symetrie/gimbal_ui.py +0 -361
- egse/gimbal/symetrie/pmac.py +0 -1006
- egse/gimbal/symetrie/pmac_regex.py +0 -83
- egse/graph.py +0 -132
- egse/gui/__init__.py +0 -47
- egse/gui/buttons.py +0 -378
- egse/gui/focalplane.py +0 -1281
- egse/gui/formatter.py +0 -10
- egse/gui/led.py +0 -162
- egse/gui/limitswitch.py +0 -143
- egse/gui/mechanisms.py +0 -588
- egse/gui/states.py +0 -148
- egse/gui/stripchart.py +0 -729
- egse/gui/switch.py +0 -112
- egse/h5.py +0 -274
- egse/help/__init__.py +0 -0
- egse/help/help_ui.py +0 -126
- egse/hexapod/__init__.py +0 -32
- egse/hexapod/symetrie/__init__.py +0 -138
- egse/hexapod/symetrie/alpha.py +0 -874
- egse/hexapod/symetrie/dynalpha.py +0 -1387
- egse/hexapod/symetrie/hexapod_ui.py +0 -1516
- egse/hexapod/symetrie/pmac.py +0 -1010
- egse/hexapod/symetrie/pmac_regex.py +0 -83
- egse/hexapod/symetrie/puna.py +0 -1167
- egse/hexapod/symetrie/puna.yaml +0 -193
- egse/hexapod/symetrie/puna_cs.py +0 -196
- egse/hexapod/symetrie/puna_protocol.py +0 -131
- egse/hexapod/symetrie/puna_ui.py +0 -434
- egse/hexapod/symetrie/punaplus.py +0 -107
- egse/hexapod/symetrie/zonda.py +0 -872
- egse/hexapod/symetrie/zonda.yaml +0 -337
- egse/hexapod/symetrie/zonda_cs.py +0 -172
- egse/hexapod/symetrie/zonda_devif.py +0 -415
- egse/hexapod/symetrie/zonda_protocol.py +0 -119
- egse/hexapod/symetrie/zonda_ui.py +0 -449
- egse/hk.py +0 -765
- egse/icons/aeu-cs-start.svg +0 -117
- egse/icons/aeu-cs-stop.svg +0 -118
- egse/icons/aeu-cs.svg +0 -107
- egse/icons/aeu_cs-started.svg +0 -112
- egse/icons/aeu_cs-stopped.svg +0 -112
- egse/icons/aeu_cs.svg +0 -55
- egse/icons/alert.svg +0 -1
- egse/icons/arrow-double-left.png +0 -0
- egse/icons/arrow-double-right.png +0 -0
- egse/icons/arrow-up.svg +0 -11
- egse/icons/backward.svg +0 -1
- egse/icons/busy.svg +0 -1
- egse/icons/cleaning.svg +0 -115
- egse/icons/color-scheme.svg +0 -1
- egse/icons/cs-connected-alert.svg +0 -91
- egse/icons/cs-connected-disabled.svg +0 -43
- egse/icons/cs-connected.svg +0 -89
- egse/icons/cs-not-connected.svg +0 -44
- egse/icons/double-left-arrow.svg +0 -1
- egse/icons/double-right-arrow.svg +0 -1
- egse/icons/erase-disabled.svg +0 -19
- egse/icons/erase.svg +0 -59
- egse/icons/fitsgen-start.svg +0 -47
- egse/icons/fitsgen-stop.svg +0 -48
- egse/icons/fitsgen.svg +0 -1
- egse/icons/forward.svg +0 -1
- egse/icons/fov-hk-start.svg +0 -33
- egse/icons/fov-hk-stop.svg +0 -37
- egse/icons/fov-hk.svg +0 -1
- egse/icons/front-desk.svg +0 -1
- egse/icons/home-actioned.svg +0 -15
- egse/icons/home-disabled.svg +0 -15
- egse/icons/home.svg +0 -13
- egse/icons/info.svg +0 -1
- egse/icons/invalid.png +0 -0
- egse/icons/led-green.svg +0 -20
- egse/icons/led-grey.svg +0 -20
- egse/icons/led-orange.svg +0 -20
- egse/icons/led-red.svg +0 -20
- egse/icons/led-square-green.svg +0 -134
- egse/icons/led-square-grey.svg +0 -134
- egse/icons/led-square-orange.svg +0 -134
- egse/icons/led-square-red.svg +0 -134
- egse/icons/limit-switch-all-green.svg +0 -115
- egse/icons/limit-switch-all-red.svg +0 -117
- egse/icons/limit-switch-el+.svg +0 -116
- egse/icons/limit-switch-el-.svg +0 -117
- egse/icons/location-marker.svg +0 -1
- egse/icons/logo-dpu.svg +0 -48
- egse/icons/logo-gimbal.svg +0 -112
- egse/icons/logo-huber.svg +0 -23
- egse/icons/logo-ogse.svg +0 -31
- egse/icons/logo-puna.svg +0 -92
- egse/icons/logo-tcs.svg +0 -29
- egse/icons/logo-zonda.svg +0 -66
- egse/icons/maximize.svg +0 -1
- egse/icons/meter.svg +0 -1
- egse/icons/more.svg +0 -45
- egse/icons/n-fee-hk-start.svg +0 -24
- egse/icons/n-fee-hk-stop.svg +0 -25
- egse/icons/n-fee-hk.svg +0 -83
- egse/icons/observing-off.svg +0 -46
- egse/icons/observing-on.svg +0 -46
- egse/icons/open-document-hdf5.png +0 -0
- egse/icons/open-document-hdf5.svg +0 -21
- egse/icons/ops-mode.svg +0 -1
- egse/icons/play-green.svg +0 -17
- egse/icons/plugged-disabled.svg +0 -27
- egse/icons/plugged.svg +0 -21
- egse/icons/pm_ui.svg +0 -1
- egse/icons/power-button-green.svg +0 -27
- egse/icons/power-button-red.svg +0 -27
- egse/icons/power-button.svg +0 -27
- egse/icons/radar.svg +0 -1
- egse/icons/radioactive.svg +0 -2
- egse/icons/reload.svg +0 -1
- egse/icons/remote-control-off.svg +0 -28
- egse/icons/remote-control-on.svg +0 -28
- egse/icons/repeat-blue.svg +0 -15
- egse/icons/repeat.svg +0 -1
- egse/icons/settings.svg +0 -1
- egse/icons/shrink.svg +0 -1
- egse/icons/shutter.svg +0 -1
- egse/icons/sign-off.svg +0 -1
- egse/icons/sign-on.svg +0 -1
- egse/icons/sim-mode.svg +0 -1
- egse/icons/small-buttons-go.svg +0 -20
- egse/icons/small-buttons-minus.svg +0 -51
- egse/icons/small-buttons-plus.svg +0 -51
- egse/icons/sponge.svg +0 -220
- egse/icons/start-button-disabled.svg +0 -84
- egse/icons/start-button.svg +0 -50
- egse/icons/stop-button-disabled.svg +0 -84
- egse/icons/stop-button.svg +0 -50
- egse/icons/stop-red.svg +0 -17
- egse/icons/stop.svg +0 -1
- egse/icons/switch-disabled-square.svg +0 -87
- egse/icons/switch-disabled.svg +0 -15
- egse/icons/switch-off-square.svg +0 -87
- egse/icons/switch-off.svg +0 -72
- egse/icons/switch-on-square.svg +0 -87
- egse/icons/switch-on.svg +0 -61
- egse/icons/temperature-control.svg +0 -44
- egse/icons/th_ui_logo.svg +0 -1
- egse/icons/unplugged.svg +0 -23
- egse/icons/unvalid.png +0 -0
- egse/icons/user-interface.svg +0 -1
- egse/icons/vacuum.svg +0 -1
- egse/icons/valid.png +0 -0
- egse/icons/zoom-to-pixel-dark.svg +0 -64
- egse/icons/zoom-to-pixel-white.svg +0 -36
- egse/images/big-rotation-stage.png +0 -0
- egse/images/connected-100.png +0 -0
- egse/images/cross.svg +0 -6
- egse/images/disconnected-100.png +0 -0
- egse/images/gui-icon.png +0 -0
- egse/images/home.svg +0 -6
- egse/images/info-icon.png +0 -0
- egse/images/led-black.svg +0 -89
- egse/images/led-green.svg +0 -85
- egse/images/led-orange.svg +0 -85
- egse/images/led-red.svg +0 -85
- egse/images/load-icon.png +0 -0
- egse/images/load-setup.png +0 -0
- egse/images/load.png +0 -0
- egse/images/pause.png +0 -0
- egse/images/play-button.svg +0 -8
- egse/images/play.png +0 -0
- egse/images/process-status.png +0 -0
- egse/images/restart.png +0 -0
- egse/images/search.png +0 -0
- egse/images/sma.png +0 -0
- egse/images/start.png +0 -0
- egse/images/stop-button.svg +0 -8
- egse/images/stop.png +0 -0
- egse/images/switch-off.svg +0 -48
- egse/images/switch-on.svg +0 -48
- egse/images/undo.png +0 -0
- egse/images/update-button.svg +0 -11
- egse/imageviewer/exposureselection.py +0 -475
- egse/imageviewer/imageviewer.py +0 -198
- egse/imageviewer/matchfocalplane.py +0 -179
- egse/imageviewer/subfieldposition.py +0 -133
- egse/lampcontrol/__init__.py +0 -4
- egse/lampcontrol/beaglebone/beaglebone.py +0 -178
- egse/lampcontrol/beaglebone/beaglebone.yaml +0 -62
- egse/lampcontrol/beaglebone/beaglebone_cs.py +0 -106
- egse/lampcontrol/beaglebone/beaglebone_devif.py +0 -150
- egse/lampcontrol/beaglebone/beaglebone_protocol.py +0 -73
- egse/lampcontrol/energetiq/__init__.py +0 -22
- egse/lampcontrol/energetiq/eq99.yaml +0 -98
- egse/lampcontrol/energetiq/lampEQ99.py +0 -283
- egse/lampcontrol/energetiq/lampEQ99_cs.py +0 -128
- egse/lampcontrol/energetiq/lampEQ99_devif.py +0 -158
- egse/lampcontrol/energetiq/lampEQ99_encode_decode_errors.py +0 -73
- egse/lampcontrol/energetiq/lampEQ99_protocol.py +0 -69
- egse/lampcontrol/energetiq/lampEQ99_ui.py +0 -465
- egse/lib/CentOS-7/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/CentOS-8/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/CentOS-8/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/Debian/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/Debian/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/Debian/libetherspacelink_v35_21.dylib +0 -0
- egse/lib/Linux/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/Linux/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/Ubuntu-20/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/Ubuntu-20/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/gssw/python3-gssw_2.2.3+31f63c9f-1_all.deb +0 -0
- egse/lib/macOS/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/macOS/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/ximc/__pycache__/pyximc.cpython-38 2.pyc +0 -0
- egse/lib/ximc/__pycache__/pyximc.cpython-38.pyc +0 -0
- egse/lib/ximc/libximc.framework/Frameworks/libbindy.dylib +0 -0
- egse/lib/ximc/libximc.framework/Frameworks/libxiwrapper.dylib +0 -0
- egse/lib/ximc/libximc.framework/Headers/ximc.h +0 -5510
- egse/lib/ximc/libximc.framework/Resources/Info.plist +0 -42
- egse/lib/ximc/libximc.framework/Resources/keyfile.sqlite +0 -0
- egse/lib/ximc/libximc.framework/libbindy.so +0 -0
- egse/lib/ximc/libximc.framework/libximc +0 -0
- egse/lib/ximc/libximc.framework/libximc.so +0 -0
- egse/lib/ximc/libximc.framework/libximc.so.7.0.0 +0 -0
- egse/lib/ximc/libximc.framework/libxiwrapper.so +0 -0
- egse/lib/ximc/pyximc.py +0 -922
- egse/listener.py +0 -73
- egse/logger/__init__.py +0 -243
- egse/logger/log_cs.py +0 -321
- egse/metrics.py +0 -98
- egse/mixin.py +0 -464
- egse/monitoring.py +0 -95
- egse/ni/alarms/__init__.py +0 -26
- egse/ni/alarms/cdaq9375.py +0 -300
- egse/ni/alarms/cdaq9375.yaml +0 -89
- egse/ni/alarms/cdaq9375_cs.py +0 -130
- egse/ni/alarms/cdaq9375_devif.py +0 -183
- egse/ni/alarms/cdaq9375_protocol.py +0 -48
- egse/obs_inspection.py +0 -163
- egse/observer.py +0 -41
- egse/obsid.py +0 -163
- egse/powermeter/__init__.py +0 -0
- egse/powermeter/ni/__init__.py +0 -38
- egse/powermeter/ni/cdaq9184.py +0 -224
- egse/powermeter/ni/cdaq9184.yaml +0 -73
- egse/powermeter/ni/cdaq9184_cs.py +0 -130
- egse/powermeter/ni/cdaq9184_devif.py +0 -201
- egse/powermeter/ni/cdaq9184_protocol.py +0 -48
- egse/powermeter/ni/cdaq9184_ui.py +0 -544
- egse/powermeter/thorlabs/__init__.py +0 -25
- egse/powermeter/thorlabs/pm100a.py +0 -380
- egse/powermeter/thorlabs/pm100a.yaml +0 -132
- egse/powermeter/thorlabs/pm100a_cs.py +0 -136
- egse/powermeter/thorlabs/pm100a_devif.py +0 -127
- egse/powermeter/thorlabs/pm100a_protocol.py +0 -80
- egse/powermeter/thorlabs/pm100a_ui.py +0 -725
- egse/process.py +0 -451
- egse/procman/__init__.py +0 -811
- egse/procman/cannot_start_process_popup.py +0 -43
- egse/procman/procman.yaml +0 -49
- egse/procman/procman_cs.py +0 -201
- egse/procman/procman_ui.py +0 -2081
- egse/protocol.py +0 -603
- egse/proxy.py +0 -522
- egse/randomwalk.py +0 -140
- egse/reg.py +0 -585
- egse/reload.py +0 -122
- egse/reprocess.py +0 -675
- egse/resource.py +0 -333
- egse/rst.py +0 -135
- egse/search.py +0 -182
- egse/serialdevice.py +0 -190
- egse/services.py +0 -212
- egse/services.yaml +0 -51
- egse/settings.py +0 -379
- egse/settings.yaml +0 -980
- egse/setup.py +0 -1180
- egse/shutter/__init__.py +0 -0
- egse/shutter/thorlabs/__init__.py +0 -19
- egse/shutter/thorlabs/ksc101.py +0 -205
- egse/shutter/thorlabs/ksc101.yaml +0 -105
- egse/shutter/thorlabs/ksc101_cs.py +0 -136
- egse/shutter/thorlabs/ksc101_devif.py +0 -201
- egse/shutter/thorlabs/ksc101_protocol.py +0 -69
- egse/shutter/thorlabs/ksc101_ui.py +0 -548
- egse/shutter/thorlabs/sc10.py +0 -82
- egse/shutter/thorlabs/sc10.yaml +0 -52
- egse/shutter/thorlabs/sc10_controller.py +0 -81
- egse/shutter/thorlabs/sc10_cs.py +0 -108
- egse/shutter/thorlabs/sc10_interface.py +0 -25
- egse/shutter/thorlabs/sc10_simulator.py +0 -30
- egse/simulator.py +0 -41
- egse/slack.py +0 -61
- egse/socketdevice.py +0 -218
- egse/sockets.py +0 -218
- egse/spw.py +0 -1479
- egse/stages/__init__.py +0 -12
- egse/stages/aerotech/ensemble.py +0 -247
- egse/stages/aerotech/ensemble.yaml +0 -205
- egse/stages/aerotech/ensemble_controller.py +0 -275
- egse/stages/aerotech/ensemble_cs.py +0 -110
- egse/stages/aerotech/ensemble_interface.py +0 -132
- egse/stages/aerotech/ensemble_parameters.py +0 -433
- egse/stages/aerotech/ensemble_simulator.py +0 -27
- egse/stages/aerotech/mgse_sim.py +0 -193
- egse/stages/arun/smd3.py +0 -111
- egse/stages/arun/smd3.yaml +0 -68
- egse/stages/arun/smd3_controller.py +0 -472
- egse/stages/arun/smd3_cs.py +0 -112
- egse/stages/arun/smd3_interface.py +0 -53
- egse/stages/arun/smd3_simulator.py +0 -27
- egse/stages/arun/smd3_stop.py +0 -16
- egse/stages/huber/__init__.py +0 -49
- egse/stages/huber/smc9300.py +0 -904
- egse/stages/huber/smc9300.yaml +0 -63
- egse/stages/huber/smc9300_cs.py +0 -178
- egse/stages/huber/smc9300_devif.py +0 -345
- egse/stages/huber/smc9300_protocol.py +0 -111
- egse/stages/huber/smc9300_sim.py +0 -547
- egse/stages/huber/smc9300_ui.py +0 -973
- egse/state.py +0 -173
- egse/statemachine.py +0 -274
- egse/storage/__init__.py +0 -1004
- egse/storage/persistence.py +0 -2295
- egse/storage/storage.yaml +0 -72
- egse/storage/storage_cs.py +0 -214
- egse/styles/dark.qss +0 -343
- egse/styles/default.qss +0 -48
- egse/synoptics/__init__.py +0 -412
- egse/synoptics/syn.yaml +0 -9
- egse/synoptics/syn_cs.py +0 -195
- egse/system.py +0 -1408
- egse/tcs/__init__.py +0 -14
- egse/tcs/tcs.py +0 -874
- egse/tcs/tcs.yaml +0 -14
- egse/tcs/tcs_cs.py +0 -202
- egse/tcs/tcs_devif.py +0 -292
- egse/tcs/tcs_protocol.py +0 -177
- egse/tcs/tcs_sim.py +0 -177
- egse/tcs/tcs_ui.py +0 -543
- egse/tdms.py +0 -171
- egse/tempcontrol/__init__.py +0 -23
- egse/tempcontrol/agilent/agilent34970.py +0 -109
- egse/tempcontrol/agilent/agilent34970.yaml +0 -44
- egse/tempcontrol/agilent/agilent34970_cs.py +0 -116
- egse/tempcontrol/agilent/agilent34970_devif.py +0 -182
- egse/tempcontrol/agilent/agilent34970_protocol.py +0 -99
- egse/tempcontrol/agilent/agilent34972.py +0 -111
- egse/tempcontrol/agilent/agilent34972.yaml +0 -44
- egse/tempcontrol/agilent/agilent34972_cs.py +0 -117
- egse/tempcontrol/agilent/agilent34972_devif.py +0 -189
- egse/tempcontrol/agilent/agilent34972_protocol.py +0 -101
- egse/tempcontrol/beaglebone/beaglebone.py +0 -342
- egse/tempcontrol/beaglebone/beaglebone.yaml +0 -110
- egse/tempcontrol/beaglebone/beaglebone_cs.py +0 -117
- egse/tempcontrol/beaglebone/beaglebone_protocol.py +0 -135
- egse/tempcontrol/beaglebone/beaglebone_ui.py +0 -681
- egse/tempcontrol/digalox/digalox.py +0 -107
- egse/tempcontrol/digalox/digalox.yaml +0 -36
- egse/tempcontrol/digalox/digalox_cs.py +0 -112
- egse/tempcontrol/digalox/digalox_protocol.py +0 -55
- egse/tempcontrol/keithley/__init__.py +0 -33
- egse/tempcontrol/keithley/daq6510.py +0 -662
- egse/tempcontrol/keithley/daq6510.yaml +0 -105
- egse/tempcontrol/keithley/daq6510_cs.py +0 -163
- egse/tempcontrol/keithley/daq6510_devif.py +0 -343
- egse/tempcontrol/keithley/daq6510_protocol.py +0 -78
- egse/tempcontrol/keithley/daq6510_sim.py +0 -186
- egse/tempcontrol/lakeshore/__init__.py +0 -33
- egse/tempcontrol/lakeshore/lsci.py +0 -361
- egse/tempcontrol/lakeshore/lsci.yaml +0 -162
- egse/tempcontrol/lakeshore/lsci_cs.py +0 -174
- egse/tempcontrol/lakeshore/lsci_devif.py +0 -292
- egse/tempcontrol/lakeshore/lsci_protocol.py +0 -73
- egse/tempcontrol/lakeshore/lsci_ui.py +0 -389
- egse/tempcontrol/ni/__init__.py +0 -0
- egse/tempcontrol/spid/spid.py +0 -109
- egse/tempcontrol/spid/spid.yaml +0 -81
- egse/tempcontrol/spid/spid_controller.py +0 -279
- egse/tempcontrol/spid/spid_cs.py +0 -136
- egse/tempcontrol/spid/spid_protocol.py +0 -107
- egse/tempcontrol/spid/spid_ui.py +0 -727
- egse/tempcontrol/srs/__init__.py +0 -22
- egse/tempcontrol/srs/ptc10.py +0 -875
- egse/tempcontrol/srs/ptc10.yaml +0 -227
- egse/tempcontrol/srs/ptc10_cs.py +0 -128
- egse/tempcontrol/srs/ptc10_devif.py +0 -118
- egse/tempcontrol/srs/ptc10_protocol.py +0 -42
- egse/tempcontrol/srs/ptc10_ui.py +0 -906
- egse/ups/apc/apc.py +0 -236
- egse/ups/apc/apc.yaml +0 -45
- egse/ups/apc/apc_cs.py +0 -101
- egse/ups/apc/apc_protocol.py +0 -125
- egse/user.yaml +0 -7
- egse/vacuum/beaglebone/beaglebone.py +0 -149
- egse/vacuum/beaglebone/beaglebone.yaml +0 -44
- egse/vacuum/beaglebone/beaglebone_cs.py +0 -108
- egse/vacuum/beaglebone/beaglebone_devif.py +0 -164
- egse/vacuum/beaglebone/beaglebone_protocol.py +0 -193
- egse/vacuum/beaglebone/beaglebone_ui.py +0 -638
- egse/vacuum/instrutech/igm402.py +0 -92
- egse/vacuum/instrutech/igm402.yaml +0 -90
- egse/vacuum/instrutech/igm402_controller.py +0 -128
- egse/vacuum/instrutech/igm402_cs.py +0 -108
- egse/vacuum/instrutech/igm402_interface.py +0 -49
- egse/vacuum/instrutech/igm402_simulator.py +0 -36
- egse/vacuum/keller/kellerBus.py +0 -256
- egse/vacuum/keller/leo3.py +0 -102
- egse/vacuum/keller/leo3.yaml +0 -38
- egse/vacuum/keller/leo3_controller.py +0 -83
- egse/vacuum/keller/leo3_cs.py +0 -101
- egse/vacuum/keller/leo3_interface.py +0 -33
- egse/vacuum/mks/evision.py +0 -86
- egse/vacuum/mks/evision.yaml +0 -75
- egse/vacuum/mks/evision_cs.py +0 -101
- egse/vacuum/mks/evision_devif.py +0 -316
- egse/vacuum/mks/evision_interface.py +0 -60
- egse/vacuum/mks/evision_simulator.py +0 -24
- egse/vacuum/mks/evision_ui.py +0 -704
- egse/vacuum/pfeiffer/acp40.py +0 -87
- egse/vacuum/pfeiffer/acp40.yaml +0 -60
- egse/vacuum/pfeiffer/acp40_controller.py +0 -117
- egse/vacuum/pfeiffer/acp40_cs.py +0 -109
- egse/vacuum/pfeiffer/acp40_interface.py +0 -40
- egse/vacuum/pfeiffer/acp40_simulator.py +0 -39
- egse/vacuum/pfeiffer/tc400.py +0 -113
- egse/vacuum/pfeiffer/tc400.yaml +0 -83
- egse/vacuum/pfeiffer/tc400_controller.py +0 -140
- egse/vacuum/pfeiffer/tc400_cs.py +0 -109
- egse/vacuum/pfeiffer/tc400_interface.py +0 -70
- egse/vacuum/pfeiffer/tc400_simulator.py +0 -24
- egse/vacuum/pfeiffer/tpg261.py +0 -81
- egse/vacuum/pfeiffer/tpg261.yaml +0 -66
- egse/vacuum/pfeiffer/tpg261_controller.py +0 -150
- egse/vacuum/pfeiffer/tpg261_cs.py +0 -109
- egse/vacuum/pfeiffer/tpg261_interface.py +0 -60
- egse/vacuum/pfeiffer/tpg261_simulator.py +0 -24
- egse/version.py +0 -174
- egse/visitedpositions.py +0 -398
- egse/windowing.py +0 -213
- egse/zmq/__init__.py +0 -28
- egse/zmq/spw.py +0 -160
- egse/zmq_ser.py +0 -41
- scripts/alerts/cold.yaml +0 -278
- scripts/alerts/example_alerts.yaml +0 -54
- scripts/alerts/transition.yaml +0 -14
- scripts/alerts/warm.yaml +0 -49
- scripts/analyse_n_fee_hk_data.py +0 -44
- scripts/check_hdf5_files.py +0 -192
- scripts/check_register_sync.py +0 -47
- scripts/create_hdf5_report.py +0 -295
- scripts/csl_model.py +0 -436
- scripts/csl_restore_setup.py +0 -230
- scripts/export-grafana-dashboards.py +0 -50
- scripts/fdir/cs_recovery/fdir_cs_recovery.py +0 -59
- scripts/fdir/fdir_table.yaml +0 -70
- scripts/fdir/fdir_test_recovery.py +0 -11
- scripts/fdir/hw_recovery/fdir_agilent_hw_recovery.py +0 -73
- scripts/fdir/limit_recovery/fdir_agilent_limit.py +0 -64
- scripts/fdir/limit_recovery/fdir_bb_heater_limit.py +0 -61
- scripts/fdir/limit_recovery/fdir_ensemble_limit.py +0 -33
- scripts/fdir/limit_recovery/fdir_pressure_limit_recovery.py +0 -71
- scripts/fix_csv.py +0 -80
- scripts/n_fee_supply_voltage_calculation.py +0 -92
- scripts/playground.py +0 -30
- scripts/print_hdf5_hk_data.py +0 -68
- scripts/print_register_map.py +0 -43
- scripts/sron/commanding/control_heaters.py +0 -44
- scripts/sron/commanding/pumpdown.py +0 -46
- scripts/sron/commanding/set_pid_setpoint.py +0 -19
- scripts/sron/commanding/shutdown_bbb_heaters.py +0 -10
- scripts/sron/commanding/shutdown_pumps.py +0 -33
- scripts/sron/tm_gen/tm_gen_agilent.py +0 -38
- scripts/sron/tm_gen/tm_gen_heaters.py +0 -4
- scripts/sron/tm_gen/tm_gen_spid.py +0 -13
- scripts/update_operational_cgse.py +0 -268
- 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
|