added doc source files (sphinx) [ci skip]

This commit is contained in:
Rossen Georgiev 2016-01-20 09:25:34 +00:00
parent 5ea606ef1a
commit c6b1042701
7 changed files with 998 additions and 135 deletions

View File

@ -3,152 +3,30 @@ APRS library for Python
|pypi| |coverage| |master_build|
A tiny library for dealing with APRS. It can be used to connect and listen to the APRS-IS feed as well as upload.
Parsing of packets is also possible, but the entire spec is not fully implemented yet.
The following is supported:
A python library for dealing with APRS.
It can be used to interact with APRS-IS servers, sending and receiving.
Parsing functionally is also included, but currently doesn't implement the full spec.
- normal/compressed position reports
- objects
- mic-e position report
- messages (inc. telemetry, bulletins, etc)
- base91 comment telemetry extension
- altitude extension
- beacons
See `full documentation <http://rgp.io/aprs-python/>`_.
Packets can often contain characters outside of 7-bit ASCII.
``aprslib.parse()`` will attempt to guess the charset and return ``unicode`` strings using these steps and in that order:
Installation
============
1. Attempt to decode string as ``utf-8``
2. Attempt to guess the charset using ``chardet`` module (if installed), decode if confidence factor is sufficient
3. Finally, decode as ``latin-1``
Install
-----------
You can grab the latest release from https://pypi.python.org/pypi/aprslib or via ``pip``
.. code:: bash
To install the latest release from ``pypi``::
pip install aprslib
Examples
-----------
To install the latest dev version from the `Github repo <https://github.com/rossengeorgiev/aprs-python://github.com/rossengeorgiev/aprs-python/>`_::
Parsing
^^^^^^^
.. code:: python
import aprslib
packet = aprslib.parse("M0XER-4>APRS64,TF3RPF,WIDE2*,qAR,TF3SUT-2:!/.(M4I^C,O `DXa/A=040849|#B>@\"v90!+|")
.. code:: python
{'altitude': 12450.7752,
'comment': 'Xa',
'format': 'compressed',
'from': 'M0XER-4',
'gpsfixstatus': 1,
'latitude': 64.11987367625208,
'longitude': -19.070654142799384,
'messagecapable': False,
'path': ['TF3RPF', 'WIDE2*', 'qAR', 'TF3SUT-2'],
'raw': 'M0XER-4>APRS64,TF3RPF,WIDE2*,qAR,TF3SUT-2:!/.(M4I^C,O `DXa/A=040849|#B>@"v90!+|',
'symbol': 'O',
'symbol_table': '/',
'telemetry': {'bits': '00000000',
'seq': 215,
'vals': [2670, 176, 2199, 10, 0]},
'to': 'APRS64',
'via': 'TF3SUT-2'}
Keep in mind that this function raises exceptions if the packet format is invalid or not supported.
.. code:: python
try:
packet = aprslib.parse("M0XER-4>APRS64,TF3RPF,WIDE2*,qAR,TF3SUT-2:!/.(M4I^C,O `DXa/A=040849|#B>@\"v90!+|")
except (aprslib.ParseError, aprslib.UnknownFormat) as exp:
pass
pip install git+https://github.com/rossengeorgiev/aprs-python
APRS-IS
^^^^^^^
Contribution
============
.. code:: python
| Suggestions, issues and pull requests are welcome.
| Just visit the repository at https://github.com/rossengeorgiev/aprs-python
import aprslib
def callback(packet):
print packet
AIS = aprslib.IS("N0CALL")
AIS.connect()
# by default `raw` is False, then each line is ran through aprslib.parse()
AIS.consumer(callback, raw=True)
.. code:: text
VK2TRL>APU25N,qAR,VK3KAW:;AWARC *270052z3602.24S/14656.26E-Albury/Wodonga A.R.C. see www.awarc.org
DL1TMF-1>APRS,TCPIP*,qAS,DL1TMF:!5022.38N/01146.58E- http://www.dl1tmf.de
KF4HFE-1>S3SX9S,K4TQR-1,WIDE1,AB4KN-2*,WIDE2,qAR,W4GR-10:`r,^l\Lk/"5h}
...
The ``IS`` class makes use of the ``logging`` module.
There are various levels of verbosity available for ``IS``.
The only non-standard levels are 9 (unknown format errors) and 11 (parse errors).
Here is a simple example:
.. code:: python
import aprslib
import logging
logging.basicConfig(level=logging.DEBUG) # level=10
AIS = aprslib.IS("N0CALL")
AIS.connect()
AIS.consumer(lambda x: None, raw=True)
.. code:: text
INFO:aprslib.IS:Attempting connection to rotate.aprs.net:10152
INFO:aprslib.IS:Connected to 205.233.35.52:10152
DEBUG:aprslib.IS:Banner: # aprsc 2.0.14-g28c5a6a
INFO:aprslib.IS:Sending login information
DEBUG:aprslib.IS:Server: # logresp N0CALL unverified, server EIGHTH
INFO:aprslib.IS:Login successful (receive only)
DEBUG:aprslib.parse:Parsing: PY4MM-15>Q8U11W,PU4YRM-15*,WIDE3-2,qAR,PP2MD-1:'L.Kl #/"=h}APRS DIGI - Uberlandia - MG
DEBUG:aprslib.parse:Attempting to parse as mic-e packet
DEBUG:aprslib.parse:Parsed ok.
...
Uploading packets to APRS-IS is possible through the ``sendall()`` method in ``IS``.
The method assumes a single line/packet per call. The parameters may end with ``\r\n``, but it's not required.
.. code:: python
import aprslib
# a valid passcode for the callsign is required in order to send
AIS = aprslib.IS("N0CALL", passcode="123456", port=14580)
AIS.connect()
# send a single status message
AIS.sendall("N0CALL>APRS,TCPIP*:>status text")
A passcode generation function is also provided.
CHANGES
^^^^^^^
You can find the latest changes between versions in the CHANGES file.
Docs
^^^^
.. code:: bash
$ python -m pydoc aprslib
.. |pypi| image:: https://img.shields.io/pypi/v/aprslib.svg?style=flat&label=latest%20version
:target: https://pypi.python.org/pypi/aprslib

3
docs/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
_build
_static
_templates

216
docs/Makefile Normal file
View File

@ -0,0 +1,216 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/aprslib.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/aprslib.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/aprslib"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/aprslib"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

289
docs/conf.py Normal file
View File

@ -0,0 +1,289 @@
# -*- coding: utf-8 -*-
#
# aprslib documentation build configuration file, created by
# sphinx-quickstart on Wed Jan 20 07:25:05 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.
import sys
import os
# 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.
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 = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.githubpages',
]
# 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'aprslib'
copyright = u'2016, Rossen Georgiev'
author = u'Rossen Georgiev'
# 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'0.6.42'
# The full version, including alpha/beta/rc tags.
release = u'0.6.42'
# 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 = None
# 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.
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 = 'classic'
# 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.
# "<project> v<release> documentation" by default.
#html_title = u'aprslib v0.6.42'
# 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 (within the static path) to use as 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
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# 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 <link> 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 = 'aprslibdoc'
# -- 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, 'aprslib.tex', u'aprslib Documentation',
u'Rossen Georgiev', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# 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, 'aprslib', u'aprslib 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, 'aprslib', u'aprslib Documentation',
author, 'aprslib', '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

130
docs/examples.rst Normal file
View File

@ -0,0 +1,130 @@
Example usage
*************
This section includes examples of basic usage
Parsing a packet
================
.. code:: python
>>> import aprslib
>>> aprslib.parse("M0XER-4>APRS64,TF3RPF,WIDE2*,qAR,TF3SUT-2:!/.(M4I^C,O `DXa/A=040849|#B>@\"v90!+|")
{'altitude': 12450.7752,
'comment': 'Xa',
'format': 'compressed',
'from': 'M0XER-4',
'gpsfixstatus': 1,
'latitude': 64.11987367625208,
'longitude': -19.070654142799384,
'messagecapable': False,
'path': ['TF3RPF', 'WIDE2*', 'qAR', 'TF3SUT-2'],
'raw': 'M0XER-4>APRS64,TF3RPF,WIDE2*,qAR,TF3SUT-2:!/.(M4I^C,O `DXa/A=040849|#B>@"v90!+|',
'symbol': 'O',
'symbol_table': '/',
'telemetry': {'bits': '00000000',
'seq': 215,
'vals': [2670, 176, 2199, 10, 0]},
'to': 'APRS64',
'via': 'TF3SUT-2'}
.. note::
Keep in mind that this function raises exceptions
if the packet format is invalid or not supported.
.. code:: python
try:
packet = aprslib.parse("M0XER-4>APRS64,TF3RPF,WIDE2*,qAR,TF3SUT-2:!/.(M4I^C,O `DXa/A=040849|#B>@\"v90!+|")
except (aprslib.ParseError, aprslib.UnknownFormat) as exp:
pass
APRS-IS
=======
Connect to a feed
-----------------
Connecting to APRS-IS is done using the :py:class:`aprslib.IS` module.
.. code:: python
import aprslib
def callback(packet):
print packet
AIS = aprslib.IS("N0CALL")
AIS.connect()
# by default `raw` is False, then each line is ran through aprslib.parse()
AIS.consumer(callback, raw=True)
Program output:
.. code:: text
VK2TRL>APU25N,qAR,VK3KAW:;AWARC *270052z3602.24S/14656.26E-Albury/Wodonga A.R.C. see www.awarc.org
DL1TMF-1>APRS,TCPIP*,qAS,DL1TMF:!5022.38N/01146.58E- http://www.dl1tmf.de
KF4HFE-1>S3SX9S,K4TQR-1,WIDE1,AB4KN-2*,WIDE2,qAR,W4GR-10:`r,^l\Lk/"5h}
...
Logging
-------
The :py:class:`aprslib.IS` module makes use of the ``logging`` module.
There are various levels of verbosity available for ``IS``.
The only non-standard levels are 9 (unknown format errors) and 11 (parse errors).
Here is a simple example:
.. code:: python
import aprslib
import logging
logging.basicConfig(level=logging.DEBUG) # level=10
AIS = aprslib.IS("N0CALL")
AIS.connect()
AIS.consumer(lambda x: None, raw=True)
Program output:
.. code:: text
INFO:aprslib.IS:Attempting connection to rotate.aprs.net:10152
INFO:aprslib.IS:Connected to 205.233.35.52:10152
DEBUG:aprslib.IS:Banner: # aprsc 2.0.14-g28c5a6a
INFO:aprslib.IS:Sending login information
DEBUG:aprslib.IS:Server: # logresp N0CALL unverified, server EIGHTH
INFO:aprslib.IS:Login successful (receive only)
DEBUG:aprslib.parse:Parsing: PY4MM-15>Q8U11W,PU4YRM-15*,WIDE3-2,qAR,PP2MD-1:'L.Kl #/"=h}APRS DIGI - Uberlandia - MG
DEBUG:aprslib.parse:Attempting to parse as mic-e packet
DEBUG:aprslib.parse:Parsed ok.
...
Sending a packet
----------------
Uploading packets to APRS-IS is possible through the ``sendall()`` method in ``IS``.
The method assumes a single line/packet per call. The parameters may end with ``\r\n``, but it's not required.
.. code:: python
import aprslib
# a valid passcode for the callsign is required in order to send
AIS = aprslib.IS("N0CALL", passcode="123456", port=14580)
AIS.connect()
# send a single status message
AIS.sendall("N0CALL>APRS,TCPIP*:>status text")
Passcodes
---------
In order for the server to accept your packets, you need to send a valid passcode.
See :py:func:`aprslib.passcode`

49
docs/index.rst Normal file
View File

@ -0,0 +1,49 @@
aprslib documentation
*********************
|pypi| |coverage|
A python library for dealing with APRS.
It can be used to interact with APRS-IS servers, sending and receiving.
Parsing functionally is also included, but currently doesn't implement the full spec.
See the section for :ref:`supported formats<sup_formats>`.
Installation
============
To install the latest release from ``pypi``::
pip install aprslib
To install the latest dev version from the `Github repo <https://github.com/rossengeorgiev/aprs-python://github.com/rossengeorgiev/aprs-python/>`_::
pip install git+https://github.com/rossengeorgiev/aprs-python
Contents
========
| Version: |version|
| Generated on: |today|
.. toctree::
:maxdepth: 3
examples
parse_formats
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
.. |pypi| image:: https://img.shields.io/pypi/v/aprslib.svg?style=flat&label=pypi%20version
:target: https://pypi.python.org/pypi/aprslib
:alt: Latest version released on PyPi
.. |coverage| image:: https://img.shields.io/coveralls/rossengeorgiev/aprs-python/master.svg?style=flat
:target: https://coveralls.io/r/rossengeorgiev/aprs-python?branch=master
:alt: Test coverage

298
docs/parse_formats.rst Normal file
View File

@ -0,0 +1,298 @@
Packet parsing
**************
An overview of the parsing functionality.
APRS Reference
==============
The implementation follows the APRS Protocol Reference
* Version 1.0: http://www.aprs.org/doc/APRS101.PDF
* Version 1.1: http://www.aprs.org/aprs11.html
* Version 1.2: http://www.aprs.org/aprs12.html
Encodings
=========
Packets can often contain characters outside of 7-bit ASCII.
:py:func:`aprslib.parse` will attempt to guess the charset and return ``unicode`` strings using these steps and in that order:
1. Attempt to decode string as ``utf-8``
2. Attempt to guess the charset using ``chardet`` module (if installed), decode if confidence factor is sufficient
3. Finally, decode as ``latin-1``
.. _sup_formats:
Supported formats
=================
- normal/compressed position reports
- mic-e position reports
- objects reports
- weather reports
- status reports
- messages (inc. telemetry, bulletins, etc)
- base91 comment telemetry extension
- altitude extension
- beacons
Position reports
================
Normal
------
.. code:: python
>>> aprslib.parse("FROMCALL>TOCALL:!4903.50N/07201.75W-Test /A=001234")
{'altitude': 376.1232,
'comment': u'Test',
'format': 'uncompressed',
'from': u'FROMCALL',
'latitude': 49.05833333333333,
'longitude': -72.02916666666667,
'messagecapable': False,
'path': [],
'posambiguity': 0,
'raw': u'FROMCALL>TOCALL:!4903.50N/07201.75W-Test /A=001234',
'symbol': u'-',
'symbol_table': u'/',
'to': u'TOCALL',
'via': ''}
Compressed
----------
.. code:: python
>>> aprslib.parse("M0XER-4>APRS64,TF3RPF,WIDE2*,qAR,TF3SUT-2:!/.(M4I^C,O `DXa/A=040849|#B>@\"v90!+|")
{'altitude': 12450.7752,
'comment': u'Xa',
'format': 'compressed',
'from': u'M0XER-4',
'gpsfixstatus': 1,
'latitude': 64.11987367625208,
'longitude': -19.070654142799384,
'messagecapable': False,
'path': [u'TF3RPF', u'WIDE2*', u'qAR', u'TF3SUT-2'],
'raw': u'M0XER-4>APRS64,TF3RPF,WIDE2*,qAR,TF3SUT-2:!/.(M4I^C,O `DXa/A=040849|#B>@"v90!+|',
'symbol': u'O',
'symbol_table': u'/',
'telemetry': {'bits': '00000000',
'seq': 215,
'vals': [2670, 176, 2199, 10, 0]},
'to': u'APRS64',
'via': u'TF3SUT-2'}
With timestamp:
.. code:: python
>>> aprslib.parse("FROMCALL>TOCALL:/092345z4903.50N/07201.75W>Test1234")
{'comment': u'Test1234',
'format': 'uncompressed',
'from': u'FROMCALL',
'latitude': 49.05833333333333,
'longitude': -72.02916666666667,
'messagecapable': False,
'path': [],
'posambiguity': 0,
'raw': u'FROMCALL>TOCALL:/092345z4903.50N/07201.75W>Test1234',
'raw_timestamp': u'092345z',
'symbol': u'>',
'symbol_table': u'/',
'timestamp': 1452383100,
'to': u'TOCALL',
'via': ''}
Mic-E
-----
.. code:: python
>>> aprslib.parse('FROMCALL>SUSUR1:`CF"l#![/`"3z}_ ')
{'altitude': 8,
'comment': u'`_',
'course': 305,
'format': 'mic-e',
'from': u'FROMCALL',
'latitude': 35.58683333333333,
'longitude': 139.701,
'mbits': u'111',
'mtype': 'M0: Off Duty',
'path': [],
'posambiguity': 0,
'raw': u'FROMCALL>SUSUR1:`CF"l#![/`"3z}_ ',
'speed': 0.0,
'symbol': u'[',
'symbol_table': u'/',
'to': u'SUSUR1',
'via': ''}
Objects
=======
.. code:: python
>>> aprslib.parse('FROMCALL>TOCALL:;LEADER *092345z4903.50N/07201.75W>088/036')
{'alive': True,
'comment': u'',
'course': 88,
'format': 'object',
'from': u'FROMCALL',
'latitude': 49.05833333333333,
'longitude': -72.02916666666667,
'object_format': 'uncompressed',
'object_name': u'LEADER ',
'path': [],
'posambiguity': 0,
'raw': u'FROMCALL>TOCALL:;LEADER *092345z4903.50N/07201.75W>088/036',
'raw_timestamp': u'092345z',
'speed': 66.672,
'symbol': u'>',
'symbol_table': u'/',
'timestamp': 1452383100,
'to': u'TOCALL',
'via': ''}
Weather
=======
Positionless
------------
.. code:: python
>>> aprslib.parse('FROMCALL>TOCALL:_10090556c220s004g005t077r000p000P000h50b09900wRSW')
{'comment': u'wRSW',
'format': 'wx',
'from': u'FROMCALL',
'path': [],
'raw': u'FROMCALL>TOCALL:_10090556c220s004g005t077r000p000P000h50b09900wRSW',
'to': u'TOCALL',
'via': '',
'weather': {'humidity': 50,
'pressure': 990.0,
'rain_1h': 0.0,
'rain_24h': 0.0,
'rain_since_midnight': 0.0,
'temperature': 25.0,
'wind_direction': 220,
'wind_gust': 2.2352,
'wind_speed': 1.78816},
'wx_raw_timestamp': u'10090556'}
Comment field
-------------
.. code:: python
>>> aprslib.parse("FROMCALL>TOCALL:=4903.50N/07201.75W_225/000g000t050r000p001...h00b10138dU2k")
{'comment': u'...dU2k',
'format': 'uncompressed',
'from': u'FROMCALL',
'latitude': 49.05833333333333,
'longitude': -72.02916666666667,
'messagecapable': True,
'path': [],
'posambiguity': 0,
'raw': u'FROMCALL>TOCALL:=4903.50N/07201.75W_225/000g000t050r000p001...h00b10138dU2k',
'symbol': u'_',
'symbol_table': u'/',
'to': u'TOCALL',
'via': '',
'weather': {'humidity': 0,
'pressure': 1013.8,
'rain_1h': 0.0,
'rain_24h': 0.254,
'temperature': 10.0,
'wind_direction': 225,
'wind_gust': 0.0,
'wind_speed': 0.0}}
Status report
=============
.. code:: python
>>> aprslib.parse('FROMCALL>TOCALL:>status text')
{'format': 'status',
'from': u'FROMCALL',
'path': [],
'raw': u'FROMCALL>TOCALL:>status text',
'status': u'status text',
'to': u'TOCALL',
'via': ''}
Messages
========
Regular
-------
.. code:: python
>>> aprslib.parse('FROMCALL>TOCALL::ADDRCALL :message text')
{'addresse': u'ADDRCALL',
'format': 'message',
'from': u'FROMCALL',
'message_text': u'message text',
'path': [],
'raw': u'FROMCALL>TOCALL::FROMCALL :message text',
'to': u'TOCALL',
'via': ''}
Telemetry configuration
-----------------------
.. code:: python
>>> aprslib.parse('FROMCALL>TOCALL::FROMCALL :PARM.Vin,Rx1h,Dg1h,Eff1h,A5,O1,O2,O3,O4,I1,I2,I3,I4')
{'addresse': 'FROMCALL',
'format': 'telemetry-message',
'from': 'FROMCALL',
'path': [],
'raw': 'FROMCALL>TOCALL::FROMCALL :PARM.Vin,Rx1h,Dg1h,Eff1h,A5,O1,O2,O3,O4,I1,I2,I3,I4',
'tPARM': ['Vin', 'Rx1h', 'Dg1h', 'Eff1h', 'A5', 'O1', 'O2', 'O3', 'O4', 'I1', 'I2', 'I3', 'I4'],
'to': 'TOCALL',
'via': ''}
>>> aprslib.parse('FROMCALL>TOCALL::FROMCALL :UNIT.Volt,Pkt,Pkt,Pcnt,None,On,On,On,On,Hi,Hi,Hi,Hi')
{'addresse': 'FROMCALL',
'format': 'telemetry-message',
'from': 'FROMCALL',
'path': [],
'raw': 'FROMCALL>TOCALL::FROMCALL :UNIT.Volt,Pkt,Pkt,Pcnt,None,On,On,On,On,Hi,Hi,Hi,Hi',
'tUNIT': ['Volt', 'Pkt', 'Pkt', 'Pcnt', 'None', 'On', 'On', 'On', 'On', 'Hi', 'Hi', 'Hi', 'Hi'],
'to': 'TOCALL',
'via': ''}
>>> aprslib.parse('FROMCALL>TOCALL::FROMCALL :EQNS.0,0.075,0,0,10,0,0,10,0,0,1,0,0,0,0')
{'addresse': 'FROMCALL',
'format': 'telemetry-message',
'from': 'FROMCALL',
'path': [],
'raw': 'FROMCALL>TOCALL::FROMCALL :EQNS.0,0.075,0,0,10,0,0,10,0,0,1,0,0,0,0',
'tEQNS': [[0, 0.075, 0], [0, 10, 0], [0, 10, 0], [0, 1, 0], [0, 0, 0]],
'to': 'TOCALL',
'via': ''}