diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d0ce156 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +de421.bsp +photometrie1.txt +requirements.txt + +# fichiers mac +.DS_Store diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..d51712e --- /dev/null +++ b/LICENCE @@ -0,0 +1,31 @@ +Copyright (c) 2022-2022, Astroguita Developers + +All rights reserved. + +Redistribution and use in source and binary forms, +with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +Neither the name of the Astroguita Team nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..74215c3 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include README.md +include LICENSE \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e77a9ab --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# Guitastro Camera BASLER library + +GUITAstro stands for General Use of Instruments and Telescopes in ASTROnomy. + +GuitAstro is a Python module that provides classes and methods to write easily Python scripts for astronomical observations. + +[GIT repository: https://gitlab.irap.omp.eu/guitastrolib/guitastro.git](https://gitlab.irap.omp.eu/guitastrolib/guitastro.git) + +Guitastro Camera BASLER complete Guitastro to provide access to BASLER camera drivers: + +[GIT repository: https://gitlab.irap.omp.eu/guitastrolib/guitastro_device_deltatau.git](https://gitlab.irap.omp.eu/guitastrolib/guitastro_device_deltatau.git) + +## Few basic examples of use + +First example: To connect a DeltaTau controler and slew a telescope: +``` +import guitastro +import guitastro_device_deltatau + +dev = guitastro_device_deltatau.Device_Deltatau() +dev.open(False) +dev.commandstring("mount SET target 'RADEC 12h56m -10d23m'") +dev.commandstring("mount DO RADEC_GOTO") +``` + +## Guitastro functionalities + +GuitAstro device DeltaTau wraps the driver functions dispatched into the classe: + +- **Device_Deltatau**: Manage device DeltaTau drivers. + +This class inheritate from the classes Component* of Guitastro. +As a consequece, it is needed to install Guitastro before using Guitastro DeltaTau. + +A complete documentation can be generated from .rst files in the folder doc/doc_rst + +## Support and contact + +The main author is alain.klotz@irap.omp.eu + diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +build diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..ab0f031 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,49 @@ +@echo off + +echo This batch must be launched with PowerShell in administrator mode. +call :ResolvePath path_guitastro %cd%\.. +echo Guitastro Camera ASCOM in the directory %path_guitastro% + +rem Search where is Anaconda +set path_anacondas=c:\Users\%USERNAME%\Anaconda3 C:\ProgramData\Anaconda3 +for %%p in (%path_anacondas%) do ( + rem echo %%p + if exist %%p ( + rem file exists + set path_anaconda=%%p + ) +) +echo Anaconda found in the directory %path_anaconda% + +rem pyreverse +set pyreverse=%path_anaconda%\Scripts\pyreverse +echo ===== Analyze source code with %pyreverse% +echo cd %path_guitastro%\src +cd %path_guitastro%\src +echo %pyreverse% -p guitastro_device_deltatau -o png guitastro_device_deltatau +%pyreverse% -p guitastro_device_deltatau -o png guitastro_device_deltatau +echo move classes_guitastro_device_deltatau.png %path_guitastro%\docs\source\doc_images\generated +move classes_guitastro_device_deltatau.png %path_guitastro%\docs\source\doc_images\generated +echo move packages_guitastro_device_deltatau.png %path_guitastro%\docs\source\doc_images\generated +move packages_guitastro_device_deltatau.png %path_guitastro%\docs\source\doc_images\generated + +rem sphinx +echo Compile doc with sphinx +set sphinx=%path_anaconda%\Scripts\sphinx-build.exe +echo ===== Compile doc with %sphinx% +echo cd %path_guitastro%\docs +cd %path_guitastro%\docs +echo %sphinx% -b html .\source .\build\html +%sphinx% -b html .\source .\build\html +%sphinx% -b pdf .\source .\build\pdf + +exit /b +rem === Functions === + +rem Resolve path to absolute. +rem Param 1: Name of output variable. +rem Param 2: Path to resolve. +rem Return: Resolved absolute path. +:ResolvePath + set %1=%~dpfn2 + exit /b diff --git a/docs/make_doc b/docs/make_doc new file mode 100644 index 0000000..50deff0 --- /dev/null +++ b/docs/make_doc @@ -0,0 +1,29 @@ +#!/bin/bash + +# Step 1) (if not done) change the file attribute: +# > chmod +x make_doc +# Step 2) execute the file: +# > ./make_doc + +echo +echo "-- generating guitastro_device_deltatau UML class diagrams (with pyreverse)" +echo +cd ../src +pyreverse -p guitastro_device_deltatau -o png guitastro_device_deltatau +mv classes_guitastro_device_deltatau.png ../docs/source/doc_images/generated/ +mv packages_guitastro_device_deltatau.png ../docs/source/doc_images/generated/ + +cd ../docs + +echo +echo "-- Generating guitastro_device_deltatau API doc in HTML format (from RST with sphinx)" +echo "-- You can open this doc by pointing your browser to docs/build/html/index.html (from guitastro_device_deltatau dir)" +echo +sphinx-build -b html ./source/ ./build/html/ + +echo +echo "-- Generating guitastro_device_deltatau API doc in PDF format (from RST with sphinx)" +echo "-- You can open this doc by opening docs/build/pdf/guitastro_device_deltatau.pdf (from guitastro_device_deltatau dir)" +echo +sphinx-build -b pdf ./source/ ./build/pdf/ + diff --git a/docs/source/autodoc_guitastro.rst b/docs/source/autodoc_guitastro.rst new file mode 100644 index 0000000..6442322 --- /dev/null +++ b/docs/source/autodoc_guitastro.rst @@ -0,0 +1,17 @@ +************************************* +Classes for GuitAstro Device DeltaTau +************************************* + +This section is the documentation for developpers of classes related to GuitAstro Device DeltaTau. + +This page is generated according the docstrings of the python code. +It displays only public methods of classes. + +.. image:: doc_images/generated/classes_guitastro_device_deltatau.png + +.. image:: doc_images/generated/packages_guitastro_device_deltatau.png + +Module guitastro_device_deltatau +================================ + +.. automodule:: guitastro_device_deltatau diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..e25362a --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,385 @@ +# astromecca documentation build configuration file, created by +# sphinx-quickstart on Sun Jun 26 00:00:43 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'GuitAstro Device DeltaTau' +copyright = u'2022, IRAP' +author = u'A. Klotz' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = u'1.0' +# The full version, including alpha/beta/rc tags. +release = u'1.0.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# These patterns also affect html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +# html_title = u'astromecca vastromecca' + +# A shorter title for the navigation bar. Default is the same as html_title. +# +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +# html_logo = None + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# Custom sidebar templates, maps document names to template names. +# +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +# html_domain_indices = True + +# If false, no index is generated. +# +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'guitastro_device_deltatau' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'guitastro_device_deltatau.tex', u'Guitastro Device DeltaTau Documentation', + u'guitastro_device_deltatau', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +# latex_logo = None + +# If true, show page references after internal links. +# +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# If false, no module index is generated. +# +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'guitastro_device_deltatau', u'guitastro Device DeltaTau Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'guitastro_device_deltatau', u'guitastro Device DeltaTau Documentation', + author, 'guitastro_device_deltatau', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False + +# -- A random example ----------------------------------------------------- + +import sys, os +sys.path.insert(0, os.path.abspath('../../src')) +sys.path.insert(0, os.path.abspath('../../../guitastro/src')) # guitastro must be also present +print(f"============ sys.path={sys.path}") +# exclude_patterns = ['zzz'] + +numfig = True +#language = 'ja' + +extensions.append('sphinx.ext.todo') +extensions.append('sphinx.ext.autodoc') +#extensions.append('sphinx.ext.autosummary') +extensions.append('sphinx.ext.intersphinx') +extensions.append('sphinx.ext.mathjax') +extensions.append('sphinx.ext.viewcode') +extensions.append('sphinx.ext.graphviz') +try: + extensions.append('sphinx_pyreverse') +except ModuleNotFoundError: + pass # pip install sphinx_pyreverse + +try: + import rst2pdf + extensions.append('rst2pdf.pdfbuilder') +except ModuleNotFoundError: + pass # no rst2pdf for you +extensions.append('sphinx.ext.napoleon') +# Napoleon settings +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_init_with_doc = False +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True +napoleon_preprocess_types = False +napoleon_type_aliases = None +napoleon_attr_annotations = True + +autodoc_typehints = "description" + +pdf_documents = [ + ('index', u'guitastro_device_deltatau', u'Guitastro Device DeltaTau', u'Alain Klotz'), +] + +pdf_documents = [('index', u'guitastro_device_deltatau', u'Guitastro Device DeltaTau', u'Alain Klotz')] + +# A comma-separated list of custom stylesheets. Example: +pdf_stylesheets = ['sphinx', 'kerning', 'a4', 'twocolumn'] + +# pip install sphinx rst2pdf build pdf docs +pdf_use_index = False + +autosummary_generate = True +html_theme = 'default' +#html_theme = "nature" +#html_theme = "alabaster" +#source_suffix = ['.rst', '.txt'] diff --git a/docs/source/doc_images/.gitignore b/docs/source/doc_images/.gitignore new file mode 100644 index 0000000..600a3b2 --- /dev/null +++ b/docs/source/doc_images/.gitignore @@ -0,0 +1,2 @@ +classes_guitastro.png +packages_guitastro.png \ No newline at end of file diff --git a/docs/source/doc_images/deltatau1.jpg b/docs/source/doc_images/deltatau1.jpg new file mode 100644 index 0000000..232d632 Binary files /dev/null and b/docs/source/doc_images/deltatau1.jpg differ diff --git a/docs/source/doc_images/generated/.gitignore b/docs/source/doc_images/generated/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/docs/source/doc_images/generated/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/docs/source/generate_documentation.rst b/docs/source/generate_documentation.rst new file mode 100644 index 0000000..a0d0122 --- /dev/null +++ b/docs/source/generate_documentation.rst @@ -0,0 +1,74 @@ +******************************************** +Generate this documentation +******************************************** + +This documentation is generated by the use of Sphinx and Pyreverse. +Sphinx uses the `Restructured Text format `_. +The following links gives some informations about the syntax: + + * `Tutorial Sphinx 1 `_. + * `Tutorial Sphinx 2 `_. + * `Tutorial documentation `_. + * `Tutorial reST `_. + * `Tutorial Napoleon extension `_. + * `Pandoc to convert many formats into reST `_. + +Installation of Sphinx and Pyreverse +*********************************************** + +For Linux users +=============== + +.. code-block:: bash + + sudo apt-get install graphviz graphviz-dev + cd ~/Documents/guitastro/install + python3 -m pip install -r requirements_dev.txt + +For Windows users +================= + +First you must download and install `Graphviz `_. + +Open a Powershell as administrator. +A quick way to open Powershell as administrator is +Win+R (execute commands) and put: + +.. code-block:: bash + + powershell Start-Process powershell -Verb runAs + +Then, in the Powershell terminal: + +.. code-block:: bash + + cd C:\Users\xxx\Documents\guitastro\install + python -m pip install -r requirements_dev.txt + +Generate the documentation +*********************************************** + +To generate the documentation you must use the doc_rst batch. It starts to execute pyreverse +and then sphinx. + +Procedure for Linux. Open a terminal: + +.. code-block:: bash + + cd ~/Documents/guitastro/doc/doc_rst/ + ./make_doc + +make_doc will generate UML diagrams from the Python code, the html and the PDF documentations. +To generate only html and pdf documentation, you can use: + +.. code-block:: bash + + cd ~/Documents/guitastro/doc/doc_rst/ + make html + +Procedure for Windows. Open a PowerShell as administrator: + +.. code-block:: bash + + cd C:\Users\xxx\Documents\guitastro\doc\doc_rst + .\make_doc diff --git a/docs/source/guitastro_examples.rst b/docs/source/guitastro_examples.rst new file mode 100644 index 0000000..b3a0912 --- /dev/null +++ b/docs/source/guitastro_examples.rst @@ -0,0 +1,53 @@ +******************************************** +Guitastro Device DeltaTau examples +******************************************** + + +To execute the simple tests, first open a Python console and import guitastro and guitastro_device_deltatau: + +For Linux: + +.. code-block:: bash + + cd ~/Documents/guitastro_device_deltatau/src + python3 + +.. code-block:: python + + >>> import guitastro + >>> import guitastro_device_deltatau + +For Windows (using powershell): + +.. code-block:: bash + + cd C:\Users\xxx\Documents\guitastro_device_deltatau\src + python + +.. code-block:: python + + >>> import guitastro + >>> import guitastro_device_deltatau + + +1. List Components of a device +************************************** + +.. code-block:: python + + >>> dev = guitastro_device_deltatau.Device_Deltatau("TCA") + >>> print("Components are:") + >>> for key, val in dev.components().items(): + >>> print(f" * {key} of type {val[0]}") + +2. Open the connection and send commands +****************************************** + +.. code-block:: python + + >>> dev = guitastro_device_deltatau.Device_Deltatau("TCA") + >>> dev.open(False) + >>> dev.commandstring("mount SET target 'RADEC 12h56m -10d23m'") + >>> dev.commandstring("mount DO RADEC_GOTO") + >>> res = dev.commandstring("mount GET motion") + >>> res = dev.commandstring("focuser GET motion") diff --git a/docs/source/guitastro_simple_examples.rst b/docs/source/guitastro_simple_examples.rst new file mode 100644 index 0000000..d28e7b0 --- /dev/null +++ b/docs/source/guitastro_simple_examples.rst @@ -0,0 +1,53 @@ +******************************************** +Guitastro Device DeltaTau simple examples +******************************************** + + +To execute the simple tests, first open a Python console and import guitastro and guitastro_device_deltatau: + +For Linux: + +.. code-block:: bash + + cd ~/Documents/guitastro_device_deltatau/src + python3 + +.. code-block:: python + + >>> import guitastro + >>> import guitastro_device_deltatau + +For Windows (using powershell): + +.. code-block:: bash + + cd C:\Users\xxx\Documents\guitastro_device_deltatau\src + python + +.. code-block:: python + + >>> import guitastro + >>> import guitastro_device_deltatau + + +1. List Components of a device +************************************** + +.. code-block:: python + + >>> dev = guitastro_device_deltatau.Device_Deltatau("TCA") + >>> print("Components are:") + >>> for key, val in dev.components().items(): + >>> print(f" * {key} of type {val[0]}") + +2. Open the connection and send commands +****************************************** + +.. code-block:: python + + >>> dev = guitastro_device_deltatau.Device_Deltatau("TCA") + >>> dev.open(False) + >>> dev.commandstring("mount SET target 'RADEC 12h56m -10d23m'") + >>> dev.commandstring("mount DO RADEC_GOTO") + >>> res = dev.commandstring("mount GET motion") + >>> res = dev.commandstring("focuser GET motion") diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..f909a3c --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,81 @@ +************************************************************* +Welcome in the GuitAstro Device DeltaTau module documentation +************************************************************* + +1. What is GuitAstro Device DeltaTau? +************************************* + +GuitAstro is a Python module that provides classes and methods +to write scripts for astronomical observations. GuitAstro wraps +the classical astronomical Python modules (AstroPy, etc.) and +adds functionalities. + +All information are provided in the Git repository `https://gitlab.irap.omp.eu/aklotz/guitastro.git `_. + +GuitAstro Device DeltaTau is a complement of GuitAstro to add +the class device_deltatau. By this way, it is possible to +use mount, filter wheel and focuser driven by DeltaTau. + +`DeltaTau `_ provides a motion controler between application +(as GuitAstro) to drive telescope motors. + +.. figure:: doc_images/deltatau1.jpg + :height: 100px + :align: center + + DeltaTau Logo. + +2. Installation of Guitastro Device DeltaTau +********************************************* + +See the documentation of `GuitAstro `_. +The principles are exactly the same. The main folder guitastro_device_deltatau must lie at +the same tree level than guitastro as shown below: + +.. code-block:: bash + + guitastro_packages/ + |---guitastro/ + | ... + |---guitastro_device_deltatau/ + | ... + +3. External resources +********************* + +No external source is needed. + +4. Some very simple tests +************************* + +.. toctree:: + :maxdepth: 3 + + guitastro_simple_examples + +5. Example collection +********************* + +.. toctree:: + :maxdepth: 3 + + guitastro_examples + +6. Class and method documentation +*********************************** + +For developers of Python code of GuitAstro: + +.. toctree:: + :maxdepth: 3 + + generate_documentation + +The classes of GuitAstro Devices DeltaTau. + +.. toctree:: + :maxdepth: 3 + + autodoc_guitastro + + diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..378b59c --- /dev/null +++ b/setup.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# === To install with setup.py +# git https://gitlab.irap.omp.eu/aklotz/guitastro_camera_basler.git +# cd guitastro_camera_basler +# python setup.py install +# +# === To check it is installed: +# Windows: pip freeze | findstr guitastro_camera_basler +# Linux: pip freeze | grep guitastro_camera_basler +# +# === To uninstall: +# pip uninstall guitastro_camera_basler +# +from setuptools import setup, find_packages +import os + +__version__ = '0.1' +python_cmd='python' + +def copy_file(file_in, file_out): + # used by generate_requirements + with open(file_in, 'r') as fid: + lines = fid.readlines() + with open(file_out, 'w') as fid: + fid.writelines(lines) + +def compile_requirements(python_cmd='python', requirement_in_file='requirements.in'): + # used by generate_requirements + os.system('python -m pip install --no-input pip-tools') + import piptools + #infile = os.path.join(os.getcwd(), requirement_in_file) + command = f"{python_cmd} -m piptools compile {requirement_in_file}" + print(f"compile_requirements: {command}") + os.system(command) + root, ext = os.path.splitext(requirement_in_file) + requirement_file = root + ".txt" + print(f"compile_requirements: {requirement_file} is generated.") + return requirement_file + +def read_requirements(requirement_file='requirements.txt'): + # used by generate_requirements + requirements = [] + with open(requirement_file, 'r') as fid: + lines = fid.readlines() + for line in lines: + line = line.strip() + if len(line) < 1: + continue + if line[0] == "#": + continue + requirements.append(line) + return requirements + +def generate_requirements(python_cmd='python', requirement_gen = 'requirements'): + # copy .in from install + requirement_in_file = requirement_gen + ".in" + copy_file(os.path.join('install', requirement_in_file), requirement_in_file) + # compile .in + requirement_file = compile_requirements(python_cmd, requirement_in_file) + # read .txt + requirements = read_requirements(requirement_file) + os.remove(requirement_in_file) + return requirements + +requirements = generate_requirements(python_cmd, 'requirements') + +setup( + name='guitastro_camera_basler', + version=__version__, + description='General Use of Instruments and Telescopes in ASTROnomy Camera BALSER', + author='Alain klotz', + author_email='aklotz@irap.omp.eu', + url='https://gitlab.irap.omp.eu/aklotz/guitastro_camera_basler.git', + install_requires=requirements, + package_dir = {'': 'src'}, + packages=['guitastro_camera_basler'], +) diff --git a/src/guitastro_device_deltatau/__init__.py b/src/guitastro_device_deltatau/__init__.py new file mode 100644 index 0000000..e8b1c84 --- /dev/null +++ b/src/guitastro_device_deltatau/__init__.py @@ -0,0 +1,15 @@ +""" +guitastro_device_deltatau.device_deltatau +------------------------------------------- +.. automodule:: guitastro_device_deltatau.device_deltatau + :members: + +""" +from __future__ import (absolute_import, division, print_function, + unicode_literals) + +import glob +import os + +from .device_deltatau import Device_Deltatau + diff --git a/src/guitastro_device_deltatau/component_detector_focuser_deltatau.py b/src/guitastro_device_deltatau/component_detector_focuser_deltatau.py new file mode 100644 index 0000000..3026989 --- /dev/null +++ b/src/guitastro_device_deltatau/component_detector_focuser_deltatau.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +import os +import sys + +try: + # guitastro is installed with setup.py + from guitastro import ComponentDetectorFocuser, ComponentException +except: + # guitastro is installed with only requirements.in + # guitastro_camera_* folders must be copied at the same root folder than guitastro + pwd = os.getcwd() + short_paths = ['../../../guitastro/src'] + for short_path in short_paths: + path = os.path.abspath(os.path.join(pwd, short_path)) + if path not in sys.path: + sys.path.insert(0, path) + from guitastro.component import ComponentException + from guitastro.component_detector_focuser import ComponentDetectorFocuser + +# ##################################################################### +# ##################################################################### +# ##################################################################### +# Class Component Detector Focuser DeltaTau +# ##################################################################### +# ##################################################################### +# ##################################################################### + +class ComponentDetectorFocuserDeltatau(ComponentDetectorFocuser): + """Component for Detector focuser Deltatau + + Usage : ComponentDetectorFocuserDeltatau("Z", name="test") + """ + + def _my_do(self, *args, **kwargs): + value = None + operation = args[0].upper() + operations = list(self.prop()['DO'].keys()) + if operation not in operations: + msg = f"{operation} not found amongst {operations}" + raise ComponentException(ComponentException.ERR_OPERATION_NOT_FOUND, msg) + # --- + axis_foc = self._param["CONTROLLER_FOCUS_ID"] + if operation == "GOTO": + self._verify_chan() + target = float(args[1]) + # transform to native command to start the goto + cmd = f"#{axis_foc}p={target}" + self.log = cmd + self._chan.put_chan(cmd) + # Launch a thread to wait the end of pointing and trig the drift + elif operation == "COORD": + # transform to native command to get coords + cmd = f"#{axis_foc}p" + self.log = cmd + value = float(self._chan.put_chan(cmd)) + if operation == "STOP": + self._verify_chan() + # transform to native command to stop + cmd = f"#{axis_foc}k" + self.log = cmd + self._chan.put_chan(cmd) + return value + +# ##################################################################### +# ##################################################################### +# ##################################################################### +# Main +# ##################################################################### +# ##################################################################### +# ##################################################################### + +if __name__ == "__main__": + default = 0 + example = input(f"Select the example (0 to 0) ({default}) ") + try: + example = int(example) + except: + example = default + + print("Example = {}".format(example)) + + if example == 0: + """ + Basic example + """ + comp = ComponentDetectorFocuserDeltatau("Z", name="test") + comp.verbose = 1 + res = comp.command("DO", "STOP") diff --git a/src/guitastro_device_deltatau/component_mount_pointing_deltatau.py b/src/guitastro_device_deltatau/component_mount_pointing_deltatau.py new file mode 100644 index 0000000..55c3340 --- /dev/null +++ b/src/guitastro_device_deltatau/component_mount_pointing_deltatau.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- +import os +import sys + +try: + # guitastro is installed with setup.py + from guitastro import ComponentMountPointing, ComponentException +except: + # guitastro is installed with only requirements.in + # guitastro_camera_* folders must be copied at the same root folder than guitastro + pwd = os.getcwd() + short_paths = ['../../../guitastro/src'] + for short_path in short_paths: + path = os.path.abspath(os.path.join(pwd, short_path)) + if path not in sys.path: + sys.path.insert(0, path) + from guitastro.component import ComponentException + from guitastro.component_mount_pointing import ComponentMountPointing + +# ##################################################################### +# ##################################################################### +# ##################################################################### +# Class Component Mount Pointing DeltaTau +# ##################################################################### +# ##################################################################### +# ##################################################################### + +class ComponentMountPointingDeltatau(ComponentMountPointing): + """Component for Mount Pointing Deltatau + + Usage : ComponentMountPointingDeltatau("HADEC", name="test") + """ + + def _my_do(self, *args, **kwargs): + value = None + operation = args[0].upper() + operations = list(self.prop()['DO'].keys()) + if operation not in operations: + msg = f"{operation} not found amongst {operations}" + raise ComponentException(ComponentException.ERR_OPERATION_NOT_FOUND, msg) + # --- + axis_ha = self._param["CONTROLLER_BASE_ID"] + axis_dec = self._param["CONTROLLER_POLAR_ID"] + if operation == "RADEC_GOTO": + self._verify_chan() + #target = self._param["target"] + ra, dec, equinox, epoch, dra, ddec = kwargs['computed'] + # transform to native command to start the goto + cmd = f"#{axis_ha}p=123456 #{axis_dec}p=123456" + self.log = cmd + self._chan.put_chan(cmd) + # Launch a thread to wait the end of pointing and trig the drift + elif operation == "RADEC_COORD": + # transform to native command to get coords + cmd = f"#{axis_ha}p #{axis_dec}p" + self.log = cmd + values = self._chan.put_chan(cmd) + ha_adu = float(values[0]) + dec_adu = float(values[1]) + value = f"{ha_adu} {dec_adu}" + value = "12h00m45.78s -06d55m23.2s" + if operation == "STOP": + self._verify_chan() + # transform to native command to stop + cmd = f"#{axis_ha}k #{axis_dec}k" + self.log = cmd + self._chan.put_chan(cmd) + return value + +# ##################################################################### +# ##################################################################### +# ##################################################################### +# Main +# ##################################################################### +# ##################################################################### +# ##################################################################### + +if __name__ == "__main__": + default = 0 + example = input(f"Select the example (0 to 0) ({default}) ") + try: + example = int(example) + except: + example = default + + print("Example = {}".format(example)) + + if example == 0: + """ + Basic example + """ + comp = ComponentMountPointingDeltatau("HADEC", name="test") + comp.verbose = 1 + res = comp.command("DO", "STOP") diff --git a/src/guitastro_device_deltatau/device_deltatau.py b/src/guitastro_device_deltatau/device_deltatau.py new file mode 100644 index 0000000..0cdb4b8 --- /dev/null +++ b/src/guitastro_device_deltatau/device_deltatau.py @@ -0,0 +1,244 @@ +# -*- coding: utf-8 -*- +import os +import sys +import shlex + +try: + from .component_detector_focuser_deltatau import ComponentDetectorFocuserDeltatau +except: + from component_detector_focuser_deltatau import ComponentDetectorFocuserDeltatau + +try: + from .component_mount_pointing_deltatau import ComponentMountPointingDeltatau +except: + from component_mount_pointing_deltatau import ComponentMountPointingDeltatau + +try: + # guitastro is installed with setup.py + from guitastro import Communication, GuitastroException, GuitastroTools, Ephemeris +except: + # guitastro is installed with only requirements.in + # guitastro_camera_* folders must be copied at the same root folder than guitastro + pwd = os.getcwd() + short_paths = ['../../../guitastro/src'] + for short_path in short_paths: + path = os.path.abspath(os.path.join(pwd, short_path)) + if path not in sys.path: + sys.path.insert(0, path) + from guitastro.communications import Communication + from guitastro.guitastrotools import GuitastroException, GuitastroTools + from guitastro.ephemeris import Ephemeris + +# ##################################################################### +# ##################################################################### +# ##################################################################### +# Class Device_Deltatau +# ##################################################################### +# ##################################################################### +# ##################################################################### + +class Device_DeltatauException(GuitastroException): + + ERR_FILE_NOT_EXISTS = 0 + ERR_COMMAND = 1 + ERR_COMPONENT_NOT_FOUND = 2 + + errors = [""]*3 + errors[ERR_FILE_NOT_EXISTS] = "The named file was not found" + errors[ERR_COMMAND] = "Command error" + errors[ERR_COMPONENT_NOT_FOUND] = "Component not found" + + +class Device_Deltatau(Device_DeltatauException, GuitastroTools): + """Driver for device DeltaTau + + All commands are linked to the same communication channel + """ + + _real = False + _chan = None + +# ===================================================================== +# ===================================================================== +# Private methods +# ===================================================================== +# ===================================================================== + +# ===================================================================== +# ===================================================================== +# Methods for experimented users (debug, etc) +# ===================================================================== +# ===================================================================== + +# ===================================================================== +# ===================================================================== +# Methods for users +# ===================================================================== +# ===================================================================== + + def open(self, real:bool): + self._real = real + if self._chan == None: + host = dev._unit_params["HOST"] + port = dev._unit_params["PORT"] + chan = Communication("TCP", HOSTNAME = host, PORT = port, DELAY_PUT_READ = 0.1, REAL = real) + chan.open_chan() + self._chan = chan + # - set the channel to all components + components = self.components(True) + for component in components: + self._comp[component].channel = chan + + def close(self): + if self._real == True: + del(self._chan) + self._chan = None + # - reset the channel to all components + components = self.components(True) + for component in components: + self._comp[component].channel = None + + def components(self, just_names: bool=False): + """ Return a dictionary of components + + The key is the name of the component. + The value is a tupple: + + * category + * Python access to the object + + """ + if just_names==True: + return list(self._comp.keys()) + dico = {} + for name, comp in self._comp.items(): + category = comp.category + dico[name] = (category, comp) + return dico + + def commandstring(self, cmd:str): + """Execute a command as a string entry + """ + cmds = shlex.split(cmd) + component_name = cmds[0] + action = cmds[1].upper() + args = cmds[2:] + return self.command(component_name, action, *args) + + def command(self, component_name:str, action:str, *args, **kwargs): + """Execute a command as a string entry + """ + components = self.components(True) + if component_name not in components: + msg = f"Component {component_name} not found amongst {components}" + raise Device_DeltatauException(Device_DeltatauException.ERR_COMPONENT_NOT_FOUND, msg) + try: + result = self._comp[component_name].command(action, *args, **kwargs) + except: + msg = f"Problem with component {component_name} command {action} {args} {kwargs}" + raise Device_DeltatauException(Device_DeltatauException.ERR_COMMAND, msg) + return result + +# ===================================================================== +# ===================================================================== +# Special methods +# ===================================================================== +# ===================================================================== + + def __init__(self, *args, **kwargs): + """ + Conversion from Uniform Python object into protocol language + Usage : Mountastro("HADEC", name="SCX11") + """ + # === Decode params + # --- Use the __init__ of the parent class Mountastro + #super(Device_Deltatau,self).__init__(*args, **kwargs) + # --- Special params for this mount + # --- Dicos of optional and mandatory parameters + params_optional = {} + # --- special SCX11 for TALK function + params_optional["NAME"] = (str, "Unknown") + params_optional["CONTROLLER_BASE_ID"] = (int, 1) + params_optional["CONTROLLER_POLAR_ID"] = (int, 2) + params_optional["CONTROLLER_FOCUS_ID"] = (int, 3) + params_optional["CONTROLLER_FILTER_ID"] = (int, 4) + + # --- Dico of unit_types and their parameters + unit_types = {} + # --- unit choice + unit_types["TCA"] = {"MANDATORY" : {}, "OPTIONAL" : {"HOST":[str,"192.168.30.41"], "PORT":[int,1025]} } + unit_types["TCH"] = {"MANDATORY" : {}, "OPTIONAL" : {"HOST":[str,"192.168.10.46"], "PORT":[int,1025]} } + # --- Decode args and kwargs parameters + self._unit_params = self.decode_args_kwargs(0, unit_types, params_optional, *args, **kwargs) + # === + self.unit_type = self._unit_params["SELECTED_ARG"] + name = self._unit_params["NAME"] + # --- init ephemeris + eph = Ephemeris() + if self.unit_type=="TCA": + eph.set_home("910") + name = self.unit_type + lim_inf = 1000 + lim_sup = 33000 + elif self.unit_type=="TCH": + eph.set_home("262") + name = self.unit_type + lim_inf = 1000 + lim_sup = 33000 + else: + name = self._unit_params["NAME"] + lim_inf = 1000 + lim_sup = 33000 + # === Instanciate components of the device + self._comp = {} + # --- init component detector focuser + self._comp["focuser"] = ComponentDetectorFocuserDeltatau("Z", name=name, model="Umac", manufacturer="DeltaTau", description="4 axis controler", lim_inf=lim_inf, lim_sup=lim_sup) + self._comp["focuser"].command("SET", "lim_inf", lim_inf) + self._comp["focuser"].command("SET", "lim_sup", lim_sup) + self._comp["focuser"].command("SET", "CONTROLLER_FOCUS_ID", self._unit_params["CONTROLLER_FOCUS_ID"]) + # --- init component mount pointing + self._comp["mount"] = ComponentMountPointingDeltatau("HADEC", name=name, model="Umac", manufacturer="DeltaTau", description="4 axis controler", configuration="fork") + self._comp["mount"]._eph.set_home(eph.home.gps) + self._comp["mount"].command("SET", "CONTROLLER_BASE_ID", self._unit_params["CONTROLLER_BASE_ID"]) + self._comp["mount"].command("SET", "CONTROLLER_POLAR_ID", self._unit_params["CONTROLLER_POLAR_ID"]) + + def __del__(self): + try: + self.close() + except: + pass + +# ##################################################################### +# ##################################################################### +# ##################################################################### +# Main +# ##################################################################### +# ##################################################################### +# ##################################################################### + +if __name__ == "__main__": + default = 0 + example = input(f"Select the example (0 to 0) ({default}) ") + try: + example = int(example) + except: + example = default + + print("Example = {}".format(example)) + + if example == 0: + """ + Basic example + """ + #home = Home("GPS 2.0375 E 43.6443484725 136.9") + #site = Siteobs(home) + dev = Device_Deltatau("TCA") + print("Components are:") + for key, val in dev.components().items(): + print(f" * {key} of type {val[0]}") + dev.open(False) + dev.commandstring("mount SET target 'RADEC 12h56m -10d23m'") + dev.commandstring("mount DO RADEC_GOTO") + res = dev.commandstring("mount GET motion") + res = dev.commandstring("focuser GET motion") + -- libgit2 0.21.2