pyobs-gui 2.0.0.dev16__tar.gz → 2.0.0.dev18__tar.gz
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.
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/PKG-INFO +1 -1
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/acquisitionwidget.py +8 -5
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/autofocuswidget.py +12 -9
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/autoguidingwidget.py +12 -7
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/base.py +28 -14
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/camerawidget.py +14 -18
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/coolingwidget.py +4 -3
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/datadisplaywidget.py +0 -1
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/filterwidget.py +7 -5
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/focuswidget.py +6 -6
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/roofwidget.py +12 -7
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/spectrographwidget.py +8 -5
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/statuswidget.py +6 -3
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/telescopewidget.py +19 -17
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/videowidget.py +13 -8
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyproject.toml +1 -1
- pyobs_gui-2.0.0.dev18/specs/2026-08-20-gui-remote-call-error-handling.md +232 -0
- pyobs_gui-2.0.0.dev18/specs/index.md +45 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/tests/test_camerawidget.py +5 -3
- pyobs_gui-2.0.0.dev18/tests/test_videowidget.py +38 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/uv.lock +1 -1
- pyobs_gui-2.0.0.dev16/specs/index.md +0 -34
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/.claude/skills/verify/SKILL.md +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/.github/dependabot.yml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/.github/workflows/pypi.yml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/.github/workflows/pyrefly.yml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/.github/workflows/ruff.yml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/.gitignore +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/.pre-commit-config.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/.readthedocs.yml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/CHANGELOG.rst +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/LICENSE +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/README.md +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/bin/mypyuic5 +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/docs/Makefile +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/docs/make.bat +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/docs/requirements.txt +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/docs/source/_static/pyobs.gif +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/docs/source/conf.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/docs/source/index.rst +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/mypy.ini +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/__init__.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/__main__.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/_nuitka_astropy_patch.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/accounts.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/commandinputwidget.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/compassmovewidget.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/eventswidget.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/fitsheaderswidget.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/gui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/login.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/loginwindow.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/logmodel.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/mainwindow.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/modewidget.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/modifiedmixin.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/modulegui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/__init__.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/acquisitionwidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/acquisitionwidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/autofocuswidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/autofocuswidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/autoguidingwidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/autoguidingwidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/camerawidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/camerawidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/compassmoveplugin.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/compassmovewidget.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/compassmovewidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/compassmovewidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/compile.sh +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/coolingwidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/coolingwidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/datadisplayplugin.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/datadisplaywidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/datadisplaywidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/designer.sh +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/eventswidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/eventswidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/filterwidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/filterwidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/fitsheaderswidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/fitsheaderswidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/focuswidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/focuswidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/mainwindow.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/mainwindow_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/modewidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/modewidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/arrow-alt-circle-down-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/arrow-alt-circle-left-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/arrow-alt-circle-right-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/arrow-alt-circle-up-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/arrow-up-right-from-square-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/arrows-to-eye-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/chart-line-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/circle-question-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/cloud-sun-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/edit-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/search-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources/undo-solid.svg +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources.qrc +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/resources_rc.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/roofwidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/roofwidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/shellwidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/shellwidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/spectrographwidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/spectrographwidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/telescopewidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/telescopewidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/temperaturesplotwidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/temperaturesplotwidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/temperatureswidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/temperatureswidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/videowidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/videowidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/weatherwidget.ui +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/qt/weatherwidget_ui.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/shellwidget.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/temperaturesplotwidget.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/temperatureswidget.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/utils.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/watchedlabel.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pyobs_gui/weatherwidget.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/pysidedeploy.spec +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/spike_standalone/main.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/spike_standalone/pysidedeploy.spec +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/acquisition.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/autofocus.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/camera.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/full.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/guiding.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/mode.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/roof.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/spectrograph.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/telescope.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/telescope_acl.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/telescope_acl_denied.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/test/video.yaml +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/tests/__init__.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/tests/conftest.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/tests/test_accounts.py +0 -0
- {pyobs_gui-2.0.0.dev16 → pyobs_gui-2.0.0.dev18}/tests/test_loginwindow.py +0 -0
|
@@ -2,7 +2,6 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
|
-
import qasync # type: ignore
|
|
6
5
|
from PySide6 import QtCore, QtWidgets # type: ignore
|
|
7
6
|
|
|
8
7
|
os.environ["QT_API"] = "PySide6"
|
|
@@ -147,13 +146,17 @@ class AcquisitionWidget(BaseWidget, Ui_AcquisitionWidget):
|
|
|
147
146
|
|
|
148
147
|
self.canvas.draw()
|
|
149
148
|
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
def _acquire(self) -> None:
|
|
150
|
+
self.run_background(self._acquire_target)
|
|
151
|
+
|
|
152
|
+
async def _acquire_target(self) -> None:
|
|
152
153
|
async with self.comm.proxy(self.module, IAcquisition) as proxy:
|
|
153
154
|
await proxy.acquire_target()
|
|
154
155
|
|
|
155
|
-
|
|
156
|
-
|
|
156
|
+
def _abort(self) -> None:
|
|
157
|
+
self.run_background(self._abort_acquisition)
|
|
158
|
+
|
|
159
|
+
async def _abort_acquisition(self) -> None:
|
|
157
160
|
async with self.comm.proxy(self.module, IAcquisition) as proxy:
|
|
158
161
|
await proxy.abort()
|
|
159
162
|
|
|
@@ -2,7 +2,6 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
|
-
import qasync # type: ignore
|
|
6
5
|
from PySide6 import QtCore, QtWidgets # type: ignore
|
|
7
6
|
|
|
8
7
|
os.environ["QT_API"] = "PySide6"
|
|
@@ -78,9 +77,7 @@ class AutoFocusWidget(BaseWidget, Ui_AutoFocusWidget):
|
|
|
78
77
|
self.labelStatus.setText(
|
|
79
78
|
"Running..."
|
|
80
79
|
if self._running
|
|
81
|
-
else f"Focus: {self._last_result[0]:.3f} ± {self._last_result[1]:.3f} mm"
|
|
82
|
-
if self._last_result
|
|
83
|
-
else "Idle"
|
|
80
|
+
else f"Focus: {self._last_result[0]:.3f} ± {self._last_result[1]:.3f} mm" if self._last_result else "Idle"
|
|
84
81
|
)
|
|
85
82
|
|
|
86
83
|
self.ax.clear()
|
|
@@ -95,13 +92,19 @@ class AutoFocusWidget(BaseWidget, Ui_AutoFocusWidget):
|
|
|
95
92
|
self.ax.set_axisbelow(True)
|
|
96
93
|
self.canvas.draw()
|
|
97
94
|
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
def _run_auto_focus(self) -> None:
|
|
96
|
+
self.run_background(
|
|
97
|
+
self._auto_focus, self.spinCount.value(), self.spinStep.value(), self.spinExposureTime.value()
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
async def _auto_focus(self, count: int, step: float, exposure_time: float) -> None:
|
|
100
101
|
async with self.comm.proxy(self.module, IAutoFocus) as proxy:
|
|
101
|
-
await proxy.auto_focus(
|
|
102
|
+
await proxy.auto_focus(count, step, exposure_time)
|
|
103
|
+
|
|
104
|
+
def _abort(self) -> None:
|
|
105
|
+
self.run_background(self._abort_focus)
|
|
102
106
|
|
|
103
|
-
|
|
104
|
-
async def _abort(self) -> None:
|
|
107
|
+
async def _abort_focus(self) -> None:
|
|
105
108
|
async with self.comm.proxy(self.module, IAutoFocus) as proxy:
|
|
106
109
|
await proxy.abort()
|
|
107
110
|
|
|
@@ -4,7 +4,6 @@ import os
|
|
|
4
4
|
from collections import deque
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
|
-
import qasync # type: ignore
|
|
8
7
|
from PySide6 import QtCore, QtWidgets # type: ignore
|
|
9
8
|
|
|
10
9
|
os.environ["QT_API"] = "PySide6"
|
|
@@ -130,19 +129,25 @@ class AutoGuidingWidget(BaseWidget, Ui_AutoGuidingWidget):
|
|
|
130
129
|
self.figure.tight_layout()
|
|
131
130
|
self.canvas.draw()
|
|
132
131
|
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
def _start(self) -> None:
|
|
133
|
+
self.run_background(self._start_guiding)
|
|
134
|
+
|
|
135
|
+
async def _start_guiding(self) -> None:
|
|
135
136
|
async with self.comm.proxy(self.module, IAutoGuiding) as proxy:
|
|
136
137
|
await proxy.start()
|
|
137
138
|
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
def _stop(self) -> None:
|
|
140
|
+
self.run_background(self._stop_guiding)
|
|
141
|
+
|
|
142
|
+
async def _stop_guiding(self) -> None:
|
|
140
143
|
async with self.comm.proxy(self.module, IAutoGuiding) as proxy:
|
|
141
144
|
await proxy.stop()
|
|
142
145
|
|
|
143
|
-
|
|
144
|
-
async def _set_exposure_time(self) -> None:
|
|
146
|
+
def _set_exposure_time(self) -> None:
|
|
145
147
|
value = self.spinExposureTime.value()
|
|
148
|
+
self.run_background(self._set_exposure_time_async, value)
|
|
149
|
+
|
|
150
|
+
async def _set_exposure_time_async(self, value: float) -> None:
|
|
146
151
|
async with self.comm.proxy(self.module, IExposureTime) as proxy:
|
|
147
152
|
await proxy.set_exposure_time(value)
|
|
148
153
|
|
|
@@ -26,6 +26,24 @@ log = logging.getLogger(__name__)
|
|
|
26
26
|
WidgetClass = TypeVar("WidgetClass", bound="BaseWidget")
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
async def show_remote_error(parent: QtWidgets.QWidget, exception: Exception) -> None:
|
|
30
|
+
"""Show a remote-call failure to the user.
|
|
31
|
+
|
|
32
|
+
Single shared path for surfacing exceptions from remote method calls: `PyobsError`
|
|
33
|
+
(domain errors like `MoveError`, and transport errors like `RemoteError`) shows a warning
|
|
34
|
+
box titled with the exception class; any other `Exception` is logged and shown as a plain
|
|
35
|
+
warning. Used by `BaseWidget._background_task()` (everything routed through
|
|
36
|
+
`run_background()`) and by non-`BaseWidget` callers like `StatusItem`.
|
|
37
|
+
"""
|
|
38
|
+
if isinstance(exception, exc.PyobsError):
|
|
39
|
+
# PyobsError.__str__ already prefixes the class name ("<MoveError> msg"); the class name
|
|
40
|
+
# is the dialog title, so show only the message itself
|
|
41
|
+
await QAsyncMessageBox.warning(parent, type(exception).__name__, exception.message or str(exception))
|
|
42
|
+
else:
|
|
43
|
+
log.exception("An error occurred.")
|
|
44
|
+
await QAsyncMessageBox.warning(parent, "Error", str(exception))
|
|
45
|
+
|
|
46
|
+
|
|
29
47
|
class BaseWindow:
|
|
30
48
|
def __init__(self) -> None:
|
|
31
49
|
"""Base class for MainWindow and all widgets."""
|
|
@@ -120,7 +138,6 @@ class BaseWindow:
|
|
|
120
138
|
|
|
121
139
|
|
|
122
140
|
class BaseWidget(BaseWindow, QtWidgets.QWidget): # type: ignore
|
|
123
|
-
_show_error = QtCore.Signal(str)
|
|
124
141
|
_enable_buttons = QtCore.Signal(list, bool)
|
|
125
142
|
|
|
126
143
|
def __init__(
|
|
@@ -134,7 +151,6 @@ class BaseWidget(BaseWindow, QtWidgets.QWidget): # type: ignore
|
|
|
134
151
|
QtWidgets.QWidget.__init__(self)
|
|
135
152
|
|
|
136
153
|
# signals
|
|
137
|
-
self._show_error.connect(self.show_error)
|
|
138
154
|
self._enable_buttons.connect(self.enable_buttons)
|
|
139
155
|
|
|
140
156
|
# update
|
|
@@ -271,6 +287,7 @@ class BaseWidget(BaseWindow, QtWidgets.QWidget): # type: ignore
|
|
|
271
287
|
self._update_task = None
|
|
272
288
|
|
|
273
289
|
async def _update_loop(self) -> None:
|
|
290
|
+
consecutive_failures = 0
|
|
274
291
|
while True:
|
|
275
292
|
try:
|
|
276
293
|
# get module state
|
|
@@ -288,9 +305,14 @@ class BaseWidget(BaseWindow, QtWidgets.QWidget): # type: ignore
|
|
|
288
305
|
|
|
289
306
|
# sleep a little
|
|
290
307
|
await asyncio.sleep(1)
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
308
|
+
consecutive_failures = 0
|
|
309
|
+
|
|
310
|
+
except (exc.PyobsError, IndexError) as e:
|
|
311
|
+
# background polling failures must not pop a dialog per failed poll -- log the
|
|
312
|
+
# first failure, then every 60th (~once a minute at the 1s poll interval)
|
|
313
|
+
consecutive_failures += 1
|
|
314
|
+
if consecutive_failures % 60 == 1:
|
|
315
|
+
log.warning("Update of %s failed: %s", self.module, e)
|
|
294
316
|
await asyncio.sleep(1)
|
|
295
317
|
|
|
296
318
|
def run_background(self, method: Callable[..., Coroutine[Any, Any, None]], *args: Any, **kwargs: Any) -> None:
|
|
@@ -308,20 +330,12 @@ class BaseWidget(BaseWindow, QtWidgets.QWidget): # type: ignore
|
|
|
308
330
|
# call method
|
|
309
331
|
try:
|
|
310
332
|
await method(*args, **kwargs)
|
|
311
|
-
except exc.PyobsError as e:
|
|
312
|
-
await self.show_error(e)
|
|
313
333
|
except Exception as e:
|
|
314
|
-
|
|
315
|
-
await QAsyncMessageBox.warning(self, "Error", str(e))
|
|
334
|
+
await show_remote_error(self, e)
|
|
316
335
|
finally:
|
|
317
336
|
# enable widgets
|
|
318
337
|
self._enable_buttons.emit(disable, True)
|
|
319
338
|
|
|
320
|
-
async def show_error(self, exception: exc.PyobsError) -> None:
|
|
321
|
-
err = str(exception)
|
|
322
|
-
title, message = err.split(":") if ":" in err else ("Error", err)
|
|
323
|
-
await QAsyncMessageBox.warning(self, title, message)
|
|
324
|
-
|
|
325
339
|
def enable_buttons(self, widgets: list[QtWidgets.QWidget], enable: bool) -> None:
|
|
326
340
|
for w in widgets:
|
|
327
341
|
w.setEnabled(enable)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from typing import Any
|
|
3
|
-
import qasync # type: ignore
|
|
4
3
|
from PySide6 import QtWidgets, QtCore # type: ignore
|
|
5
4
|
from astroplan import Observer
|
|
6
5
|
|
|
@@ -225,8 +224,10 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
|
|
|
225
224
|
self.exposures_left = state.count_left
|
|
226
225
|
self.update_gui()
|
|
227
226
|
|
|
228
|
-
|
|
229
|
-
|
|
227
|
+
def set_full_frame(self) -> None:
|
|
228
|
+
self.run_background(self._do_set_full_frame)
|
|
229
|
+
|
|
230
|
+
async def _do_set_full_frame(self) -> None:
|
|
230
231
|
caps = await self.comm.get_capabilities(self.module, IWindow)
|
|
231
232
|
if caps is not None:
|
|
232
233
|
# get binning
|
|
@@ -268,18 +269,15 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
|
|
|
268
269
|
else:
|
|
269
270
|
self.spinExpTime.setEnabled(True)
|
|
270
271
|
|
|
271
|
-
|
|
272
|
-
|
|
272
|
+
def expose(self) -> None:
|
|
273
|
+
self.run_background(self._do_expose)
|
|
274
|
+
|
|
275
|
+
async def _do_expose(self) -> None:
|
|
273
276
|
# set binning
|
|
274
277
|
async with self.comm.safe_proxy(self.module, IBinning) as proxy:
|
|
275
278
|
if proxy is not None:
|
|
276
279
|
binning = int(self.comboBinning.currentText()[0])
|
|
277
|
-
|
|
278
|
-
await proxy.set_binning(binning, binning)
|
|
279
|
-
except Exception:
|
|
280
|
-
log.exception("bla")
|
|
281
|
-
QtWidgets.QMessageBox.information(self, "Error", "Could not set binning.")
|
|
282
|
-
return
|
|
280
|
+
await proxy.set_binning(binning, binning)
|
|
283
281
|
else:
|
|
284
282
|
binning = 1
|
|
285
283
|
|
|
@@ -288,11 +286,7 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
|
|
|
288
286
|
if proxy is not None:
|
|
289
287
|
left, top = self.spinWindowLeft.value(), self.spinWindowTop.value()
|
|
290
288
|
width, height = self.spinWindowWidth.value(), self.spinWindowHeight.value()
|
|
291
|
-
|
|
292
|
-
await proxy.set_window(left, top, width * binning, height * binning)
|
|
293
|
-
except Exception:
|
|
294
|
-
QtWidgets.QMessageBox.information(self, "Error", "Could not set window.")
|
|
295
|
-
return
|
|
289
|
+
await proxy.set_window(left, top, width * binning, height * binning)
|
|
296
290
|
|
|
297
291
|
# set image format
|
|
298
292
|
async with self.comm.safe_proxy(self.module, IImageFormat) as proxy:
|
|
@@ -348,13 +342,15 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
|
|
|
348
342
|
self.exposures_left -= 1
|
|
349
343
|
self.signal_update_gui.emit()
|
|
350
344
|
|
|
351
|
-
|
|
352
|
-
async def abort(self) -> None:
|
|
345
|
+
def abort(self) -> None:
|
|
353
346
|
"""Abort exposure."""
|
|
354
347
|
# do we have a running exposure?
|
|
355
348
|
if self.exposures_left == 0:
|
|
356
349
|
return
|
|
357
350
|
|
|
351
|
+
self.run_background(self._do_abort)
|
|
352
|
+
|
|
353
|
+
async def _do_abort(self) -> None:
|
|
358
354
|
# got exposures left?
|
|
359
355
|
if self.exposures_left > 1:
|
|
360
356
|
# soft-stop the sequence server-side (current grab finishes normally), if
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import qasync
|
|
2
1
|
import logging
|
|
3
2
|
from typing import Any
|
|
4
3
|
from PySide6 import QtCore # type: ignore
|
|
@@ -47,9 +46,11 @@ class CoolingWidget(BaseWidget, Ui_CoolingWidget):
|
|
|
47
46
|
def checkEnabled_toggled(self, enabled: bool) -> None:
|
|
48
47
|
self.spinSetPoint.setEnabled(enabled)
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
async def buttonApply_clicked(self) -> None:
|
|
49
|
+
def buttonApply_clicked(self) -> None:
|
|
52
50
|
enabled = self.checkEnabled.isChecked()
|
|
53
51
|
temp = self.spinSetPoint.value()
|
|
52
|
+
self.run_background(self._apply_cooling, enabled, temp)
|
|
53
|
+
|
|
54
|
+
async def _apply_cooling(self, enabled: bool, temp: float) -> None:
|
|
54
55
|
async with self.comm.proxy(self.module, ICooling) as proxy:
|
|
55
56
|
await proxy.set_cooling(enabled, temp)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
|
-
import qasync
|
|
4
3
|
from PySide6 import QtWidgets, QtCore # type: ignore
|
|
5
4
|
|
|
6
5
|
from pyobs.interfaces import IFilters, FilterState, IMotion, MotionState
|
|
@@ -61,12 +60,15 @@ class FilterWidget(BaseWidget, Ui_FilterWidget):
|
|
|
61
60
|
]
|
|
62
61
|
self.buttonSetFilter.setEnabled(initialized and self.permitted("set_filter"))
|
|
63
62
|
|
|
64
|
-
|
|
65
|
-
async def set_filter(self) -> None:
|
|
63
|
+
def set_filter(self) -> None:
|
|
66
64
|
new_value, ok = QtWidgets.QInputDialog.getItem(self, "Set filter", "New filter", self._filters, 0, False)
|
|
67
65
|
if ok:
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
|
|
67
|
+
async def _do_set_filter() -> None:
|
|
68
|
+
async with self.comm.proxy(self.module, IFilters) as proxy:
|
|
69
|
+
await proxy.set_filter(new_value)
|
|
70
|
+
|
|
71
|
+
self.run_background(_do_set_filter)
|
|
70
72
|
|
|
71
73
|
|
|
72
74
|
__all__ = ["FilterWidget"]
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import asyncio
|
|
2
1
|
import logging
|
|
3
2
|
from typing import Any
|
|
4
3
|
|
|
5
|
-
import qasync # type: ignore
|
|
6
4
|
from PySide6 import QtWidgets, QtCore # type: ignore
|
|
7
5
|
|
|
8
6
|
from pyobs.interfaces import IFocuser, FocuserState, IMotion, MotionState
|
|
@@ -71,7 +69,7 @@ class FocusWidget(BaseWidget, Ui_FocusWidget):
|
|
|
71
69
|
value = self._focus or 0.0
|
|
72
70
|
new_value, ok = QtWidgets.QInputDialog.getDouble(self, "Focus", "New value", value, 0, 100, 2)
|
|
73
71
|
if ok:
|
|
74
|
-
|
|
72
|
+
self.run_background(self._set_focus_base_async, new_value)
|
|
75
73
|
|
|
76
74
|
async def _set_focus_base_async(self, new_value: float) -> None:
|
|
77
75
|
async with self.comm.proxy(self.module, IFocuser) as proxy:
|
|
@@ -81,14 +79,16 @@ class FocusWidget(BaseWidget, Ui_FocusWidget):
|
|
|
81
79
|
value = self._focus_offset or 0.0
|
|
82
80
|
new_value, ok = QtWidgets.QInputDialog.getDouble(self, "Focus offset", "New value", value, -5, 5, 2)
|
|
83
81
|
if ok:
|
|
84
|
-
|
|
82
|
+
self.run_background(self._set_focus_offset_async, new_value)
|
|
85
83
|
|
|
86
84
|
async def _set_focus_offset_async(self, new_value: float) -> None:
|
|
87
85
|
async with self.comm.proxy(self.module, IFocuser) as proxy:
|
|
88
86
|
await proxy.set_focus_offset(new_value)
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
def _reset_focus_offset(self) -> None:
|
|
89
|
+
self.run_background(self._do_reset_focus_offset)
|
|
90
|
+
|
|
91
|
+
async def _do_reset_focus_offset(self) -> None:
|
|
92
92
|
async with self.comm.proxy(self.module, IFocuser) as proxy:
|
|
93
93
|
await proxy.set_focus_offset(0.0)
|
|
94
94
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from typing import Any, TYPE_CHECKING
|
|
4
|
-
import qasync # type: ignore
|
|
5
4
|
from PySide6 import QtCore # type: ignore
|
|
6
5
|
|
|
7
6
|
from pyobs.interfaces import IMotion, MotionState, IPointingAltAz, AltAzState
|
|
@@ -53,17 +52,23 @@ class RoofWidget(BaseWidget, Ui_RoofWidget):
|
|
|
53
52
|
else:
|
|
54
53
|
self.labelAzimuth.setText(f"{self._azimuth:.1f}°")
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
def open_roof(self) -> None:
|
|
56
|
+
self.run_background(self._open_roof)
|
|
57
|
+
|
|
58
|
+
async def _open_roof(self) -> None:
|
|
58
59
|
async with self.comm.proxy(self.module, IMotion) as proxy:
|
|
59
60
|
await proxy.init()
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
def close_roof(self) -> None:
|
|
63
|
+
self.run_background(self._close_roof)
|
|
64
|
+
|
|
65
|
+
async def _close_roof(self) -> None:
|
|
63
66
|
async with self.comm.proxy(self.module, IMotion) as proxy:
|
|
64
67
|
await proxy.park()
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
def stop_roof(self) -> None:
|
|
70
|
+
self.run_background(self._stop_roof)
|
|
71
|
+
|
|
72
|
+
async def _stop_roof(self) -> None:
|
|
68
73
|
async with self.comm.proxy(self.module, IMotion) as proxy:
|
|
69
74
|
await proxy.stop_motion()
|
|
@@ -2,7 +2,6 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
from typing import Any, TYPE_CHECKING
|
|
5
|
-
import qasync # type: ignore
|
|
6
5
|
from PySide6 import QtCore # type: ignore
|
|
7
6
|
|
|
8
7
|
from pyobs.interfaces import IAbortable, IExposure, ExposureState
|
|
@@ -59,8 +58,10 @@ class SpectrographWidget(BaseWidget, Ui_SpectrographWidget):
|
|
|
59
58
|
self.exposure_status = state.status
|
|
60
59
|
self.signal_update_gui.emit()
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
def grab_spectrum(self) -> None:
|
|
62
|
+
self.run_background(self._grab_spectra)
|
|
63
|
+
|
|
64
|
+
async def _grab_spectra(self) -> None:
|
|
64
65
|
broadcast = self.checkBroadcast.isChecked()
|
|
65
66
|
|
|
66
67
|
# take the requested number of spectra; an exception (e.g. from a failed exposure,
|
|
@@ -72,10 +73,12 @@ class SpectrographWidget(BaseWidget, Ui_SpectrographWidget):
|
|
|
72
73
|
self.exposures_left -= 1
|
|
73
74
|
self.signal_update_gui.emit()
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
async def abort(self) -> None:
|
|
76
|
+
def abort(self) -> None:
|
|
77
77
|
# stop the sequence after the current spectrum finishes aborting
|
|
78
78
|
self.exposures_left = 0
|
|
79
|
+
self.run_background(self._abort_sequence)
|
|
80
|
+
|
|
81
|
+
async def _abort_sequence(self) -> None:
|
|
79
82
|
async with self.comm.proxy(self.module, IAbortable) as proxy:
|
|
80
83
|
await proxy.abort()
|
|
81
84
|
|
|
@@ -13,7 +13,7 @@ from pyobs.events import Event, ModuleOpenedEvent, ModuleClosedEvent
|
|
|
13
13
|
from pyobs.interfaces import IModule, Interface
|
|
14
14
|
from pyobs.utils.enums import ModuleState
|
|
15
15
|
from pyobs.vfs import VirtualFileSystem
|
|
16
|
-
from pyobs_gui.base import BaseWidget
|
|
16
|
+
from pyobs_gui.base import BaseWidget, show_remote_error
|
|
17
17
|
|
|
18
18
|
log = logging.getLogger(__name__)
|
|
19
19
|
|
|
@@ -131,8 +131,11 @@ class StatusItem(QtWidgets.QWidget):
|
|
|
131
131
|
|
|
132
132
|
@qasync.asyncSlot() # type: ignore
|
|
133
133
|
async def button_clicked(self) -> None:
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
try:
|
|
135
|
+
async with self.comm.proxy(self.name, IModule) as proxy:
|
|
136
|
+
await proxy.reset_error()
|
|
137
|
+
except Exception as e:
|
|
138
|
+
await show_remote_error(self, e)
|
|
136
139
|
|
|
137
140
|
|
|
138
141
|
class StateItem(QtCore.QObject):
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import asyncio
|
|
2
1
|
from enum import Enum
|
|
3
2
|
from typing import Any
|
|
4
3
|
|
|
5
4
|
import numpy as np
|
|
6
|
-
import qasync # type: ignore
|
|
7
5
|
from PySide6 import QtWidgets, QtCore # type: ignore
|
|
8
6
|
from astropy.coordinates import SkyCoord, ICRS, AltAz, get_sun, EarthLocation
|
|
9
7
|
from astroplan import Observer
|
|
@@ -473,9 +471,7 @@ class TelescopeWidget(BaseWidget, Ui_TelescopeWidget):
|
|
|
473
471
|
|
|
474
472
|
if IPointingHelioprojective in self._interfaces and self.permitted("move_helioprojective"):
|
|
475
473
|
self.run_background(self._do_move_helioprojective, heliproj.Tx.degree, heliproj.Ty.degree)
|
|
476
|
-
elif IPointingHeliographicStonyhurst in self._interfaces and self.permitted(
|
|
477
|
-
"move_heliographic_stonyhurst"
|
|
478
|
-
):
|
|
474
|
+
elif IPointingHeliographicStonyhurst in self._interfaces and self.permitted("move_heliographic_stonyhurst"):
|
|
479
475
|
stony = heliproj.transform_to(HeliographicStonyhurst)
|
|
480
476
|
# pyrefly: ignore [missing-attribute]
|
|
481
477
|
lon, lat = float(stony.lon.to(u.degree).value), float(stony.lat.to(u.degree).value)
|
|
@@ -517,18 +513,24 @@ class TelescopeWidget(BaseWidget, Ui_TelescopeWidget):
|
|
|
517
513
|
# Motion control slots
|
|
518
514
|
# -------------------------------------------------------------------------
|
|
519
515
|
|
|
520
|
-
|
|
521
|
-
|
|
516
|
+
def _init_telescope(self) -> None:
|
|
517
|
+
self.run_background(self._do_init)
|
|
518
|
+
|
|
519
|
+
async def _do_init(self) -> None:
|
|
522
520
|
async with self.comm.proxy(self.module, IMotion) as proxy:
|
|
523
521
|
await proxy.init()
|
|
524
522
|
|
|
525
|
-
|
|
526
|
-
|
|
523
|
+
def _park_telescope(self) -> None:
|
|
524
|
+
self.run_background(self._do_park)
|
|
525
|
+
|
|
526
|
+
async def _do_park(self) -> None:
|
|
527
527
|
async with self.comm.proxy(self.module, IMotion) as proxy:
|
|
528
528
|
await proxy.park()
|
|
529
529
|
|
|
530
|
-
|
|
531
|
-
|
|
530
|
+
def _stop_telescope(self) -> None:
|
|
531
|
+
self.run_background(self._do_stop)
|
|
532
|
+
|
|
533
|
+
async def _do_stop(self) -> None:
|
|
532
534
|
async with self.comm.proxy(self.module, IMotion) as proxy:
|
|
533
535
|
await proxy.stop_motion("ITelescope")
|
|
534
536
|
|
|
@@ -539,20 +541,20 @@ class TelescopeWidget(BaseWidget, Ui_TelescopeWidget):
|
|
|
539
541
|
@QtCore.Slot() # type: ignore
|
|
540
542
|
def _set_offset(self) -> None:
|
|
541
543
|
if self.sender() == self.buttonResetHorizontalOffsets:
|
|
542
|
-
|
|
544
|
+
self.run_background(self._do_set_offsets_altaz, 0.0, 0.0)
|
|
543
545
|
elif self.sender() == self.buttonResetEquatorialOffsets:
|
|
544
|
-
|
|
546
|
+
self.run_background(self._do_set_offsets_radec, 0.0, 0.0)
|
|
545
547
|
else:
|
|
546
548
|
new_value, ok = QtWidgets.QInputDialog.getDouble(self, "Set offset", 'New offset ["]', 0, -9999, 9999)
|
|
547
549
|
if ok:
|
|
548
550
|
if self.sender() == self.buttonSetAltOffset:
|
|
549
|
-
|
|
551
|
+
self.run_background(self._do_set_offsets_altaz, new_value / 3600.0, self._off_az or 0.0)
|
|
550
552
|
elif self.sender() == self.buttonSetAzOffset:
|
|
551
|
-
|
|
553
|
+
self.run_background(self._do_set_offsets_altaz, self._off_alt or 0.0, new_value / 3600.0)
|
|
552
554
|
elif self.sender() == self.buttonSetRaOffset:
|
|
553
|
-
|
|
555
|
+
self.run_background(self._do_set_offsets_radec, new_value / 3600.0, self._off_dec or 0.0)
|
|
554
556
|
elif self.sender() == self.buttonSetDecOffset:
|
|
555
|
-
|
|
557
|
+
self.run_background(self._do_set_offsets_radec, self._off_ra or 0.0, new_value / 3600.0)
|
|
556
558
|
|
|
557
559
|
async def _do_set_offsets_altaz(self, alt: float, az: float) -> None:
|
|
558
560
|
async with self.comm.proxy(self.module, IOffsetsAltAz) as proxy:
|
|
@@ -3,7 +3,6 @@ import logging
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
from urllib.parse import urlparse
|
|
5
5
|
|
|
6
|
-
import qasync # type: ignore
|
|
7
6
|
from astroplan import Observer
|
|
8
7
|
from pyobs.comm import Comm
|
|
9
8
|
from pyobs.interfaces import (
|
|
@@ -224,8 +223,10 @@ class VideoWidget(BaseWidget, Ui_VideoWidget):
|
|
|
224
223
|
qp.loadFromData(image_data)
|
|
225
224
|
self.widgetLiveView.setPixmap(qp)
|
|
226
225
|
|
|
227
|
-
|
|
228
|
-
|
|
226
|
+
def grab_image(self) -> None:
|
|
227
|
+
self.run_background(self._grab_image)
|
|
228
|
+
|
|
229
|
+
async def _grab_image(self) -> None:
|
|
229
230
|
# set image format
|
|
230
231
|
if IImageFormat in self._interfaces:
|
|
231
232
|
image_format = ImageFormat[self.comboImageFormat.currentText()] # type: ignore[attr-defined]
|
|
@@ -239,7 +240,7 @@ class VideoWidget(BaseWidget, Ui_VideoWidget):
|
|
|
239
240
|
self.signal_update_gui.emit()
|
|
240
241
|
|
|
241
242
|
# start exposures
|
|
242
|
-
|
|
243
|
+
await self._expose_task_func()
|
|
243
244
|
|
|
244
245
|
async def _expose_task_func(self) -> None:
|
|
245
246
|
# get image type
|
|
@@ -266,22 +267,26 @@ class VideoWidget(BaseWidget, Ui_VideoWidget):
|
|
|
266
267
|
def abort_sequence(self) -> None:
|
|
267
268
|
self.exposures_left = 0
|
|
268
269
|
|
|
269
|
-
|
|
270
|
-
async def exposure_time_changed(self) -> None:
|
|
270
|
+
def exposure_time_changed(self) -> None:
|
|
271
271
|
# get exp_time
|
|
272
272
|
exp_time = self.spinExpTime.value()
|
|
273
273
|
|
|
274
274
|
# set it
|
|
275
|
+
self.run_background(self._set_exposure_time, exp_time)
|
|
276
|
+
|
|
277
|
+
async def _set_exposure_time(self, exp_time: float) -> None:
|
|
275
278
|
if IExposureTime in self._interfaces:
|
|
276
279
|
async with self.comm.proxy(self.module, IExposureTime) as proxy:
|
|
277
280
|
await proxy.set_exposure_time(exp_time)
|
|
278
281
|
|
|
279
|
-
|
|
280
|
-
async def gain_changed(self) -> None:
|
|
282
|
+
def gain_changed(self) -> None:
|
|
281
283
|
# get gain
|
|
282
284
|
gain = self.spinGain.value()
|
|
283
285
|
|
|
284
286
|
# set it
|
|
287
|
+
self.run_background(self._set_gain, gain)
|
|
288
|
+
|
|
289
|
+
async def _set_gain(self, gain: float) -> None:
|
|
285
290
|
if IGain in self._interfaces:
|
|
286
291
|
async with self.comm.proxy(self.module, IGain) as proxy:
|
|
287
292
|
await proxy.set_gain(gain)
|