pyobs-brot 2.0.0.dev1__tar.gz → 2.0.0.dev4__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.
@@ -0,0 +1,26 @@
1
+ name: Publish package to PyPI
2
+ on:
3
+ push:
4
+ tags:
5
+ - 'v*'
6
+ jobs:
7
+ build-n-publish:
8
+ name: Build and publish package to PyPI
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Check out repository code
12
+ uses: actions/checkout@v4
13
+
14
+ - name: Set up Python
15
+ uses: astral-sh/setup-uv@v5
16
+ with:
17
+ enable-cache: true
18
+ python-version: "3.11"
19
+
20
+ - name: Build
21
+ run: uv build
22
+
23
+ - name: Publish
24
+ env:
25
+ PYPI_TOKEN: ${{ secrets.pypi_password }}
26
+ run: uv publish --token $PYPI_TOKEN
@@ -0,0 +1,23 @@
1
+ name: ruff
2
+ on: push
3
+
4
+ jobs:
5
+ ruff:
6
+ runs-on: ubuntu-latest
7
+ timeout-minutes: 10
8
+
9
+ steps:
10
+ - name: Check out repository code
11
+ uses: actions/checkout@v4
12
+
13
+ - name: Set up Python
14
+ uses: astral-sh/setup-uv@v5
15
+ with:
16
+ enable-cache: true
17
+ python-version: "3.13"
18
+
19
+ - name: Install packages
20
+ run: uv sync --all-extras --dev
21
+
22
+ - name: Run ruff
23
+ run: uv run ruff check pyobs_brot/
@@ -1,8 +1,5 @@
1
1
  # https://github.com/github/gitignore/blob/main/Python.gitignore
2
2
 
3
- *.yaml
4
- *.yml
5
-
6
3
  #Byte-compiled / optimized / DLL files
7
4
  __pycache__/
8
5
  *.py[cod]
@@ -0,0 +1,10 @@
1
+ repos:
2
+ - repo: https://github.com/psf/black-pre-commit-mirror
3
+ rev: 23.7.0
4
+ hooks:
5
+ - id: black
6
+ language_version: python3.11
7
+ - repo: https://github.com/astral-sh/ruff-pre-commit
8
+ rev: v0.9.0
9
+ hooks:
10
+ - id: ruff
@@ -0,0 +1,15 @@
1
+ version: 2
2
+
3
+ build:
4
+ os: ubuntu-24.04
5
+ tools:
6
+ python: "3.11"
7
+
8
+ sphinx:
9
+ configuration: docs/source/conf.py
10
+
11
+ python:
12
+ install:
13
+ - method: pip
14
+ path: .
15
+ - requirements: docs/requirements.txt
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyobs-brot
3
- Version: 2.0.0.dev1
3
+ Version: 2.0.0.dev4
4
4
  Summary: pyobs module for BROTlib telescopes
5
5
  Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>, Lukas Melzig <lukas.melzig@stud.uni-goettingen.de>
6
6
  License-Expression: MIT
@@ -9,4 +9,4 @@ Requires-Python: >=3.11
9
9
  Requires-Dist: astropy<8,>=7.0.1
10
10
  Requires-Dist: paho-mqtt>=2.1.0
11
11
  Requires-Dist: pybrotlib>=1.0.0
12
- Requires-Dist: pyobs-core<3,>=2.0.0.dev6
12
+ Requires-Dist: pyobs-core<3,>=2.0.0.dev20
@@ -0,0 +1,60 @@
1
+ BROTlib module for *pyobs*
2
+ ==========================
3
+
4
+ This is a [pyobs](https://www.pyobs.org) module for telescopes, domes and roll-off roofs controlled via
5
+ [BROTlib](https://pypi.org/project/pybrotlib/) over MQTT.
6
+
7
+
8
+ Install *pyobs-brot*
9
+ ---------------------
10
+ Clone the repository:
11
+
12
+ git clone https://github.com/pyobs/pyobs-brot.git
13
+ cd pyobs-brot
14
+
15
+ Install it with [uv](https://docs.astral.sh/uv/):
16
+
17
+ uv sync
18
+
19
+ Alternatively, with plain `venv`/`pip`:
20
+
21
+ python3 -m venv .venv
22
+ source .venv/bin/activate
23
+ pip install .
24
+
25
+
26
+ Configuration
27
+ -------------
28
+ *BrotRaDecTelescope* (or its base class *BrotBaseTelescope*), *BrotDome* and *BrotRoof* all connect to the same
29
+ MQTT broker used by BROTlib:
30
+
31
+ host:
32
+ Hostname of the MQTT broker.
33
+ name:
34
+ Name of the BROT device.
35
+ port:
36
+ MQTT port (default: 1883).
37
+
38
+ A basic telescope configuration would look like this:
39
+
40
+ class: pyobs_brot.BrotRaDecTelescope
41
+ name: My telescope
42
+ host: 1.2.3.4
43
+ roof: roof
44
+ dome: dome
45
+
46
+ # communication
47
+ comm:
48
+ jid: test@example.com
49
+ password: ***
50
+
51
+ *BrotDome* and *BrotRoof* follow the same pattern, just with `class: pyobs_brot.BrotDome` respectively
52
+ `class: pyobs_brot.BrotRoof`.
53
+
54
+
55
+ Dependencies
56
+ ------------
57
+ * [pyobs-core](https://github.com/pyobs/pyobs-core) for the core functionality.
58
+ * [pybrotlib](https://pypi.org/project/pybrotlib/) for communicating with BROT devices.
59
+ * [paho-mqtt](https://pypi.org/project/paho-mqtt/) as the MQTT client used by BROTlib.
60
+ * [Astropy](http://www.astropy.org/) for FITS file handling.
@@ -0,0 +1,31 @@
1
+ # Minimal makefile for Sphinx documentation
2
+ #
3
+
4
+ # You can set these variables from the command line.
5
+ SPHINXOPTS =
6
+ SPHINXBUILD = sphinx-build
7
+ SPHINXPROJ = pyobs
8
+ SOURCEDIR = source
9
+ BUILDDIR = ../.doc-build
10
+
11
+ #.EXPORT_ALL_VARIABLES:
12
+
13
+ #PYTHONPATH:=../pyobs-core/:../pyobs-sbig/:../pyobs-fli:../pyobs-weather:../pyobs-archive:${PYTHONPATH}
14
+
15
+ # Put it first so that "make" without argument is like "make help".
16
+ help:
17
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
18
+
19
+ .PHONY: help Makefile
20
+
21
+ html:
22
+ @$(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
23
+
24
+ livehtml:
25
+ sphinx-autobuild -b html --watch ../pyobs_brot $(ALLSPHINXOPTS) "$(SOURCEDIR)/" "$(BUILDDIR)/html/"
26
+
27
+ # Catch-all target: route all unknown targets to Sphinx using the new
28
+ # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
29
+ %: Makefile
30
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
31
+
@@ -0,0 +1,36 @@
1
+ @ECHO OFF
2
+
3
+ pushd %~dp0
4
+
5
+ REM Command file for Sphinx documentation
6
+
7
+ if "%SPHINXBUILD%" == "" (
8
+ set SPHINXBUILD=sphinx-build
9
+ )
10
+ set SOURCEDIR=source
11
+ set BUILDDIR=build
12
+ set SPHINXPROJ=pyobs
13
+
14
+ if "%1" == "" goto help
15
+
16
+ %SPHINXBUILD% >NUL 2>NUL
17
+ if errorlevel 9009 (
18
+ echo.
19
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
20
+ echo.installed, then set the SPHINXBUILD environment variable to point
21
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
22
+ echo.may add the Sphinx directory to PATH.
23
+ echo.
24
+ echo.If you don't have Sphinx installed, grab it from
25
+ echo.http://sphinx-doc.org/
26
+ exit /b 1
27
+ )
28
+
29
+ %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
30
+ goto end
31
+
32
+ :help
33
+ %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
34
+
35
+ :end
36
+ popd
@@ -0,0 +1 @@
1
+ sphinx-rtd-theme
@@ -0,0 +1,117 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+ #
3
+ # This file does only contain a selection of the most common options. For a
4
+ # full list see the documentation:
5
+ # http://www.sphinx-doc.org/en/stable/config
6
+
7
+ # -- Path setup --------------------------------------------------------------
8
+
9
+ # If extensions (or modules to document with autodoc) are in another directory,
10
+ # add these directories to sys.path here. If the directory is relative to the
11
+ # documentation root, use os.path.abspath to make it absolute, like shown here.
12
+ #
13
+ import os
14
+ import sys
15
+
16
+ sys.path.insert(0, os.path.abspath("../../"))
17
+
18
+
19
+ # -- Project information -----------------------------------------------------
20
+
21
+ project = "pyobs-brot"
22
+ copyright = "2024, Tim-Oliver Husser"
23
+ author = "Tim-Oliver Husser"
24
+
25
+ # The short X.Y version
26
+ # version = "0.16"
27
+ # The full version, including alpha/beta/rc tags
28
+ # release = "0.16.0"
29
+
30
+
31
+ # -- General configuration ---------------------------------------------------
32
+
33
+ add_module_names = False
34
+
35
+ # If your documentation needs a minimal Sphinx version, state it here.
36
+ #
37
+ # needs_sphinx = '1.0'
38
+
39
+ # Add any Sphinx extension module names here, as strings. They can be
40
+ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
41
+ # ones.
42
+ extensions = [
43
+ "sphinx.ext.autodoc",
44
+ "sphinx.ext.githubpages",
45
+ "sphinx.ext.napoleon",
46
+ "sphinx.ext.viewcode",
47
+ "sphinx.ext.autosectionlabel",
48
+ "sphinx.ext.intersphinx",
49
+ #'sphinx_autodoc_typehints'
50
+ ]
51
+
52
+ intersphinx_mapping = {"http://docs.python.org/3": None}
53
+
54
+ # napoleon settings
55
+ napoleon_google_docstring = True
56
+ napoleon_numpy_docstring = False
57
+ napoleon_use_param = False
58
+ napoleon_use_ivar = True
59
+
60
+ # typehints
61
+ # set_type_checking_flag = True
62
+ # autodoc_typehints = "description"
63
+
64
+ # show c'tor parameters in class only
65
+ autoclass_content = "both"
66
+
67
+ # Add any paths that contain templates here, relative to this directory.
68
+ templates_path = ["_templates"]
69
+
70
+ # The suffix(es) of source filenames.
71
+ # You can specify multiple suffix as a list of string:
72
+ #
73
+ source_suffix = ".rst"
74
+
75
+ # The master toctree document.
76
+ master_doc = "index"
77
+
78
+ # The language for content autogenerated by Sphinx. Refer to documentation
79
+ # for a list of supported languages.
80
+ #
81
+ # This is also used if you do content translation via gettext catalogs.
82
+ # Usually you set "language" from the command line for these cases.
83
+ language = "en"
84
+
85
+ # List of patterns, relative to source directory, that match files and
86
+ # directories to ignore when looking for source files.
87
+ # This pattern also affects html_static_path and html_extra_path .
88
+ exclude_patterns = []
89
+
90
+ # The name of the Pygments (syntax highlighting) style to use.
91
+ pygments_style = "sphinx"
92
+
93
+ # Be a little nitpicky
94
+ nitpicky = True
95
+ nitpick_ignore = []
96
+
97
+ # intersphinx
98
+ intersphinx_mapping = {
99
+ "pyobs": ("https://pyobs-core.readthedocs.io/en/latest/", None),
100
+ }
101
+
102
+ # -- Options for HTML output -------------------------------------------------
103
+
104
+ # The theme to use for HTML and HTML Help pages. See the documentation for
105
+ # a list of builtin themes.
106
+ html_theme = "sphinx_rtd_theme"
107
+ html_theme_options = {
108
+ "collapse_navigation": False,
109
+ "sticky_navigation": True,
110
+ "navigation_depth": 4,
111
+ "display_version": False,
112
+ "logo_only": False,
113
+ "prev_next_buttons_location": "bottom",
114
+ "titles_only": False,
115
+ "style_nav_header_background": "#cccccc",
116
+ }
117
+ html_logo = "_static/pyobs.gif"
@@ -0,0 +1,75 @@
1
+ pyobs-brot
2
+ ##########
3
+
4
+ This is a `pyobs <https://www.pyobs.org>`_ (`documentation <https://docs.pyobs.org>`_) module for telescopes,
5
+ domes and roll-off roofs controlled via `BROTlib <https://pypi.org/project/pybrotlib/>`_ over MQTT.
6
+
7
+
8
+ Example configuration
9
+ *********************
10
+
11
+ This is an example configuration for a telescope::
12
+
13
+ class: pyobs_brot.BrotRaDecTelescope
14
+ host: 1.2.3.4
15
+ name: My telescope
16
+ roof: roof
17
+ dome: dome
18
+
19
+ # communication
20
+ comm:
21
+ jid: test@example.com
22
+ password: ***
23
+
24
+ The dome and roof connect to the same BROT device and MQTT broker::
25
+
26
+ class: pyobs_brot.BrotDome
27
+ host: 1.2.3.4
28
+ name: My telescope
29
+
30
+ # communication
31
+ comm:
32
+ jid: test@example.com
33
+ password: ***
34
+
35
+ ::
36
+
37
+ class: pyobs_brot.BrotRoof
38
+ host: 1.2.3.4
39
+ name: My telescope
40
+
41
+ # communication
42
+ comm:
43
+ jid: test@example.com
44
+ password: ***
45
+
46
+
47
+ Available classes
48
+ *****************
49
+
50
+ :class:`~pyobs_brot.BrotRaDecTelescope` (based on :class:`~pyobs_brot.BrotBaseTelescope`) drives a telescope,
51
+ :class:`~pyobs_brot.BrotDome` a dome, and :class:`~pyobs_brot.BrotRoof` a roll-off roof.
52
+
53
+ BrotBaseTelescope
54
+ =================
55
+ .. autoclass:: pyobs_brot.BrotBaseTelescope
56
+ :members:
57
+ :show-inheritance:
58
+
59
+ BrotRaDecTelescope
60
+ ==================
61
+ .. autoclass:: pyobs_brot.BrotRaDecTelescope
62
+ :members:
63
+ :show-inheritance:
64
+
65
+ BrotDome
66
+ ========
67
+ .. autoclass:: pyobs_brot.BrotDome
68
+ :members:
69
+ :show-inheritance:
70
+
71
+ BrotRoof
72
+ ========
73
+ .. autoclass:: pyobs_brot.BrotRoof
74
+ :members:
75
+ :show-inheritance:
@@ -9,6 +9,7 @@ from pybrotlib.transport import MQTTTransport # type: ignore
9
9
  from pyobs.interfaces import (
10
10
  AltAzOffsetState,
11
11
  AltAzState,
12
+ FitsHeaderEntry,
12
13
  FocuserState,
13
14
  IFocuser,
14
15
  IOffsetsAltAz,
@@ -185,6 +186,9 @@ class BrotBaseTelescope(
185
186
  return
186
187
  await asyncio.sleep(1)
187
188
 
189
+ async def _set_tracking_rate(self, ra_rate: float, dec_rate: float) -> None:
190
+ raise NotImplementedError
191
+
188
192
  async def set_focus(self, focus: float, **kwargs: Any) -> None:
189
193
  await self._change_motion_status(MotionStatus.SLEWING, interface="IFocuser")
190
194
  await self.brot.focus.set(focus + self.focus_offset)
@@ -305,11 +309,12 @@ class BrotRaDecTelescope(BrotBaseTelescope, IOffsetsRaDec):
305
309
 
306
310
  async def get_fits_header_before(
307
311
  self, namespaces: list[str] | None = None, **kwargs: Any
308
- ) -> dict[str, tuple[Any, str]]:
312
+ ) -> dict[str, FitsHeaderEntry]:
309
313
  hdr = await BrotBaseTelescope.get_fits_header_before(self)
310
- hdr["TEL-FOCU"] = (self.brot.focus.position, "Focus position [mm]")
311
- hdr["HAOFF"] = (self.brot.telescope._telemetry.POSITION.INSTRUMENTAL.HA.OFFSET, "Hour Angle offset")
312
- hdr["DECOFF"] = (self.brot.telescope._telemetry.POSITION.INSTRUMENTAL.DEC.OFFSET, "Declination offset")
314
+ tel = self.brot.telescope._telemetry
315
+ hdr["TEL-FOCU"] = FitsHeaderEntry(self.brot.focus.position, "Focus position [mm]")
316
+ hdr["HAOFF"] = FitsHeaderEntry(tel.POSITION.INSTRUMENTAL.HA.OFFSET, "Hour Angle offset")
317
+ hdr["DECOFF"] = FitsHeaderEntry(tel.POSITION.INSTRUMENTAL.DEC.OFFSET, "Declination offset")
313
318
  return self._filter_fits_namespace(hdr, namespaces=namespaces, **kwargs)
314
319
 
315
320
  async def add_pointing_measurement(self, **kwargs: Any) -> None:
@@ -352,11 +357,12 @@ class BrotAltAzTelescope(BrotBaseTelescope, IOffsetsAltAz, IPointingSeries):
352
357
 
353
358
  async def get_fits_header_before(
354
359
  self, namespaces: list[str] | None = None, **kwargs: Any
355
- ) -> dict[str, tuple[Any, str]]:
360
+ ) -> dict[str, FitsHeaderEntry]:
361
+ tel = self.brot.telescope._telemetry
356
362
  hdr = await BrotBaseTelescope.get_fits_header_before(self)
357
- hdr["TEL-FOCU"] = (self.brot.focus.position, "Focus position [mm]")
358
- hdr["HAOFF"] = (self.brot.telescope._telemetry.POSITION.INSTRUMENTAL.HA.OFFSET, "Hour Angle offset")
359
- hdr["DECOFF"] = (self.brot.telescope._telemetry.POSITION.INSTRUMENTAL.DEC.OFFSET, "Declination offset")
363
+ hdr["TEL-FOCU"] = FitsHeaderEntry(self.brot.focus.position, "Focus position [mm]")
364
+ hdr["HAOFF"] = FitsHeaderEntry(tel.POSITION.INSTRUMENTAL.HA.OFFSET, "Hour Angle offset")
365
+ hdr["DECOFF"] = FitsHeaderEntry(tel.POSITION.INSTRUMENTAL.DEC.OFFSET, "Declination offset")
360
366
  return self._filter_fits_namespace(hdr, namespaces=namespaces, **kwargs)
361
367
 
362
368
  async def add_pointing_measurement(self, **kwargs: Any) -> None:
@@ -1,13 +1,13 @@
1
1
  [project]
2
2
  name = "pyobs-brot"
3
- version = "2.0.0.dev1"
3
+ version = "2.0.0.dev4"
4
4
  description = "pyobs module for BROTlib telescopes"
5
5
  authors = [{ name = "Tim-Oliver Husser", email = "thusser@uni-goettingen.de" }, { name = "Lukas Melzig", email = "lukas.melzig@stud.uni-goettingen.de" }]
6
6
  requires-python = ">=3.11"
7
7
  license = "MIT"
8
8
  dependencies = [
9
9
  "astropy>=7.0.1,<8",
10
- "pyobs-core>=2.0.0.dev6,<3",
10
+ "pyobs-core>=2.0.0.dev20,<3",
11
11
  "paho-mqtt>=2.1.0",
12
12
  "pybrotlib>=1.0.0",
13
13
  ]
@@ -1783,7 +1783,7 @@ wheels = [
1783
1783
 
1784
1784
  [[package]]
1785
1785
  name = "pyobs-brot"
1786
- version = "2.0.0.dev1"
1786
+ version = "2.0.0.dev4"
1787
1787
  source = { editable = "." }
1788
1788
  dependencies = [
1789
1789
  { name = "astropy" },
@@ -1805,7 +1805,7 @@ requires-dist = [
1805
1805
  { name = "astropy", specifier = ">=7.0.1,<8" },
1806
1806
  { name = "paho-mqtt", specifier = ">=2.1.0" },
1807
1807
  { name = "pybrotlib", specifier = ">=1.0.0" },
1808
- { name = "pyobs-core", specifier = ">=2.0.0.dev6,<3" },
1808
+ { name = "pyobs-core", specifier = ">=2.0.0.dev20,<3" },
1809
1809
  ]
1810
1810
 
1811
1811
  [package.metadata.requires-dev]
@@ -1818,7 +1818,7 @@ dev = [
1818
1818
 
1819
1819
  [[package]]
1820
1820
  name = "pyobs-core"
1821
- version = "2.0.0.dev6"
1821
+ version = "2.0.0.dev20"
1822
1822
  source = { registry = "https://pypi.org/simple" }
1823
1823
  dependencies = [
1824
1824
  { name = "aiohttp" },
@@ -1848,9 +1848,9 @@ dependencies = [
1848
1848
  { name = "tenacity" },
1849
1849
  { name = "typing-extensions" },
1850
1850
  ]
1851
- sdist = { url = "https://files.pythonhosted.org/packages/ca/1f/f3ff220ff8cc908198a130f98aacb2bd0c9963befd9d0757bcff13800f84/pyobs_core-2.0.0.dev6.tar.gz", hash = "sha256:ee8f98c4299064a2383666b349cf87af98f9c3de437048e8b56dcb2817e0024b", size = 299899, upload-time = "2026-06-30T17:39:36.203Z" }
1851
+ sdist = { url = "https://files.pythonhosted.org/packages/86/ce/29738c727e1a5ccc723365892f308b24641ff3211f2718a40beb56f62b9e/pyobs_core-2.0.0.dev20.tar.gz", hash = "sha256:aceee8391e9f16520004c2bd08da0e5c2ab3550901777410feeff9535845c8c1", size = 323624, upload-time = "2026-07-15T08:59:47.278Z" }
1852
1852
  wheels = [
1853
- { url = "https://files.pythonhosted.org/packages/17/b6/3875a77f1206ef5d02d5ac43ae9fd90ba96be7857fe4308dfc0c599eec16/pyobs_core-2.0.0.dev6-py3-none-any.whl", hash = "sha256:542a78b069cac525cc72b9fc5fce8983629f8f0a240ff5ee722617886a8c9c13", size = 508486, upload-time = "2026-06-30T17:39:34.739Z" },
1853
+ { url = "https://files.pythonhosted.org/packages/e2/2e/a28066bd81ff4995502d35a4a855fa1e5b9f724c828defab67c6430a4eaf/pyobs_core-2.0.0.dev20-py3-none-any.whl", hash = "sha256:501e91bc9f2a30b216180d7a1e25ecd214fcc512f905c7b9950c2c0a1f903f23", size = 541148, upload-time = "2026-07-15T08:59:45.826Z" },
1854
1854
  ]
1855
1855
 
1856
1856
  [[package]]
@@ -1,3 +0,0 @@
1
- BROTlib module for *pyobs*
2
- ==========================
3
-
File without changes