From 54dcb2cba3b7b8b7efd821063d0fd3215c8b5cd2 Mon Sep 17 00:00:00 2001
From: Fabio Manganiello <blacklight86@gmail.com>
Date: Sat, 23 Jun 2018 01:00:43 +0200
Subject: [PATCH] Documentation v0.1

---
 .gitignore                                    |   1 +
 docs/Makefile                                 |  20 ++
 docs/source/conf.py                           | 192 ++++++++++++++++++
 docs/source/index.rst                         |  16 ++
 .../plugins/assistant.google.pushtotalk.rst   |   8 +
 .../platypush/plugins/assistant.google.rst    |   6 +
 .../platypush/plugins/calendar.ical.rst       |   6 +
 docs/source/platypush/plugins/calendar.rst    |   6 +
 docs/source/platypush/plugins/camera.pi.rst   |   6 +
 docs/source/platypush/plugins/db.rst          |   6 +
 .../platypush/plugins/google.calendar.rst     |   6 +
 docs/source/platypush/plugins/google.mail.rst |   6 +
 docs/source/platypush/plugins/google.maps.rst |   6 +
 docs/source/platypush/plugins/google.rst      |   7 +
 docs/source/platypush/plugins/gpio.rst        |   6 +
 docs/source/plugins.rst                       |  19 ++
 .../plugins/assistant/google/__init__.py      |  16 ++
 .../plugins/assistant/google/pushtotalk.py    |  16 ++
 platypush/plugins/calendar/__init__.py        |  58 +++++-
 platypush/plugins/calendar/ical.py            |  17 ++
 platypush/plugins/camera/pi.py                |  22 ++
 platypush/plugins/db/__init__.py              | 124 +++++++++--
 platypush/plugins/google/__init__.py          |  20 +-
 platypush/plugins/google/calendar.py          |  13 ++
 platypush/plugins/google/mail.py              |  30 +++
 platypush/plugins/google/maps.py              |  23 +++
 platypush/plugins/gpio/__init__.py            |  56 ++++-
 platypush/plugins/weather/forecast.py         |   1 +
 28 files changed, 691 insertions(+), 22 deletions(-)
 create mode 100644 docs/Makefile
 create mode 100644 docs/source/conf.py
 create mode 100644 docs/source/index.rst
 create mode 100644 docs/source/platypush/plugins/assistant.google.pushtotalk.rst
 create mode 100644 docs/source/platypush/plugins/assistant.google.rst
 create mode 100644 docs/source/platypush/plugins/calendar.ical.rst
 create mode 100644 docs/source/platypush/plugins/calendar.rst
 create mode 100644 docs/source/platypush/plugins/camera.pi.rst
 create mode 100644 docs/source/platypush/plugins/db.rst
 create mode 100644 docs/source/platypush/plugins/google.calendar.rst
 create mode 100644 docs/source/platypush/plugins/google.mail.rst
 create mode 100644 docs/source/platypush/plugins/google.maps.rst
 create mode 100644 docs/source/platypush/plugins/google.rst
 create mode 100644 docs/source/platypush/plugins/gpio.rst
 create mode 100644 docs/source/plugins.rst

diff --git a/.gitignore b/.gitignore
index 4d5002226..2c46d0bb0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ dist/
 package.sh
 .pypirc
 platypush/backend/http/static/resources/*
+docs/build
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 000000000..74f7fb94a
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+SPHINXPROJ    = platypush
+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)
\ No newline at end of file
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 000000000..bdf32d7a7
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,192 @@
+import os
+import sys
+
+# -*- coding: utf-8 -*-
+#
+# Configuration file for the Sphinx documentation builder.
+#
+# This file does only contain a selection of the most common options. For a
+# full list see the documentation:
+# http://www.sphinx-doc.org/en/master/config
+
+# -- Path setup --------------------------------------------------------------
+
+# 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('.'))
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'platypush'
+copyright = '2018, BlackLight'
+author = 'BlackLight'
+
+# The short X.Y version
+version = ''
+# The full version, including alpha/beta/rc tags
+release = ''
+
+
+# -- 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.intersphinx',
+    'sphinx.ext.todo',
+    'sphinx.ext.imgmath',
+    'sphinx.ext.ifconfig',
+    'sphinx.ext.viewcode',
+    '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 master toctree document.
+master_doc = 'index'
+
+# 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
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path .
+exclude_patterns = []
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# -- 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'
+html_theme = 'nature'
+
+html_domain_indices = True
+
+# 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 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']
+
+# Custom sidebar templates, must be a dictionary that maps document names
+# to template names.
+#
+# The default sidebars (for documents that don't match any pattern) are
+# defined by theme itself.  Builtin themes are using these templates by
+# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
+# 'searchbox.html']``.
+#
+# html_sidebars = {}
+
+
+# -- Options for HTMLHelp output ---------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'platypushdoc'
+
+
+# -- 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, 'platypush.tex', 'platypush Documentation',
+     'BlackLight', 'manual'),
+]
+
+
+# -- 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, 'platypush', 'platypush Documentation',
+     [author], 1)
+]
+
+
+# -- 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, 'platypush', 'platypush Documentation',
+     author, 'platypush', 'One line description of project.',
+     'Miscellaneous'),
+]
+
+
+# -- Extension configuration -------------------------------------------------
+
+# -- Options for intersphinx extension ---------------------------------------
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {'https://docs.python.org/': None}
+
+# -- Options for todo extension ----------------------------------------------
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = True
+
+sys.path.insert(0, os.path.abspath('../..'))
+
+def skip(app, what, name, obj, skip, options):
+    if name == "__init__":
+        return False
+    return skip
+
+def setup(app):
+    app.connect("autodoc-skip-member", skip)
+
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 000000000..9800dafb6
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,16 @@
+Platypush
+#########
+
+.. toctree::
+    :maxdepth: 3
+    :caption: Contents:
+
+    plugins
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/docs/source/platypush/plugins/assistant.google.pushtotalk.rst b/docs/source/platypush/plugins/assistant.google.pushtotalk.rst
new file mode 100644
index 000000000..19f03e144
--- /dev/null
+++ b/docs/source/platypush/plugins/assistant.google.pushtotalk.rst
@@ -0,0 +1,8 @@
+``platypush.plugins.assistant.google.pushtotalk``
+=================================================
+
+.. automodule:: platypush.plugins.assistant.google.pushtotalk
+    :members:
+
+
+
diff --git a/docs/source/platypush/plugins/assistant.google.rst b/docs/source/platypush/plugins/assistant.google.rst
new file mode 100644
index 000000000..9b5525403
--- /dev/null
+++ b/docs/source/platypush/plugins/assistant.google.rst
@@ -0,0 +1,6 @@
+``platypush.plugins.assistant.google``
+======================================
+
+.. automodule:: platypush.plugins.assistant.google
+    :members:
+
diff --git a/docs/source/platypush/plugins/calendar.ical.rst b/docs/source/platypush/plugins/calendar.ical.rst
new file mode 100644
index 000000000..b9cdd19b6
--- /dev/null
+++ b/docs/source/platypush/plugins/calendar.ical.rst
@@ -0,0 +1,6 @@
+``platypush.plugins.calendar.ical``
+======================================
+
+.. automodule:: platypush.plugins.calendar.ical
+    :members:
+
diff --git a/docs/source/platypush/plugins/calendar.rst b/docs/source/platypush/plugins/calendar.rst
new file mode 100644
index 000000000..75db80153
--- /dev/null
+++ b/docs/source/platypush/plugins/calendar.rst
@@ -0,0 +1,6 @@
+``platypush.plugins.calendar``
+==============================
+
+.. automodule:: platypush.plugins.calendar
+    :members:
+
diff --git a/docs/source/platypush/plugins/camera.pi.rst b/docs/source/platypush/plugins/camera.pi.rst
new file mode 100644
index 000000000..a08a575f8
--- /dev/null
+++ b/docs/source/platypush/plugins/camera.pi.rst
@@ -0,0 +1,6 @@
+``platypush.plugins.camera.pi``
+======================================
+
+.. automodule:: platypush.plugins.camera.pi
+    :members:
+
diff --git a/docs/source/platypush/plugins/db.rst b/docs/source/platypush/plugins/db.rst
new file mode 100644
index 000000000..93b840132
--- /dev/null
+++ b/docs/source/platypush/plugins/db.rst
@@ -0,0 +1,6 @@
+``platypush.plugins.db``
+========================
+
+.. automodule:: platypush.plugins.db
+   :members:
+
diff --git a/docs/source/platypush/plugins/google.calendar.rst b/docs/source/platypush/plugins/google.calendar.rst
new file mode 100644
index 000000000..4b4f14ebe
--- /dev/null
+++ b/docs/source/platypush/plugins/google.calendar.rst
@@ -0,0 +1,6 @@
+``platypush.plugins.google.calendar``
+=====================================
+
+.. automodule:: platypush.plugins.google.calendar
+    :members:
+
diff --git a/docs/source/platypush/plugins/google.mail.rst b/docs/source/platypush/plugins/google.mail.rst
new file mode 100644
index 000000000..1b894036f
--- /dev/null
+++ b/docs/source/platypush/plugins/google.mail.rst
@@ -0,0 +1,6 @@
+``platypush.plugins.google.mail``
+=================================
+
+.. automodule:: platypush.plugins.google.mail
+    :members:
+
diff --git a/docs/source/platypush/plugins/google.maps.rst b/docs/source/platypush/plugins/google.maps.rst
new file mode 100644
index 000000000..c283c29f5
--- /dev/null
+++ b/docs/source/platypush/plugins/google.maps.rst
@@ -0,0 +1,6 @@
+``platypush.plugins.google.maps``
+=================================
+
+.. automodule:: platypush.plugins.google.maps
+    :members:
+
diff --git a/docs/source/platypush/plugins/google.rst b/docs/source/platypush/plugins/google.rst
new file mode 100644
index 000000000..27e12194c
--- /dev/null
+++ b/docs/source/platypush/plugins/google.rst
@@ -0,0 +1,7 @@
+``platypush.plugins.google``
+============================
+
+.. automodule:: platypush.plugins.google
+   :members:
+
+
diff --git a/docs/source/platypush/plugins/gpio.rst b/docs/source/platypush/plugins/gpio.rst
new file mode 100644
index 000000000..8de28ec6a
--- /dev/null
+++ b/docs/source/platypush/plugins/gpio.rst
@@ -0,0 +1,6 @@
+``platypush.plugins.gpio``
+==========================
+
+.. automodule:: platypush.plugins.gpio
+    :members:
+
diff --git a/docs/source/plugins.rst b/docs/source/plugins.rst
new file mode 100644
index 000000000..6946b7f34
--- /dev/null
+++ b/docs/source/plugins.rst
@@ -0,0 +1,19 @@
+Plugins
+=======
+
+.. toctree::
+    :maxdepth: 2
+    :caption: Plugins:
+
+    platypush/plugins/assistant.google.rst
+    platypush/plugins/assistant.google.pushtotalk.rst
+    platypush/plugins/calendar.rst
+    platypush/plugins/calendar.ical.rst
+    platypush/plugins/camera.pi.rst
+    platypush/plugins/db.rst
+    platypush/plugins/google.rst
+    platypush/plugins/google.calendar.rst
+    platypush/plugins/google.mail.rst
+    platypush/plugins/google.maps.rst
+    platypush/plugins/gpio.rst
+
diff --git a/platypush/plugins/assistant/google/__init__.py b/platypush/plugins/assistant/google/__init__.py
index a3589284d..aa29242e3 100644
--- a/platypush/plugins/assistant/google/__init__.py
+++ b/platypush/plugins/assistant/google/__init__.py
@@ -1,15 +1,31 @@
+"""
+.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
+"""
+
 from platypush.context import get_backend
 from platypush.message.response import Response
 
 from platypush.plugins import Plugin
 
 class AssistantGooglePlugin(Plugin):
+    """
+    Google assistant plugin.
+    It acts like a wrapper around the :mod:`platypush.backend.assistant.google`
+    backend to programmatically control the conversation status.
+    """
+
     def start_conversation(self):
+        """
+        Programmatically start a conversation with the assistant
+        """
         assistant = get_backend('assistant.google')
         assistant.start_conversation()
         return Response(output='', errors=[])
 
     def stop_conversation(self):
+        """
+        Programmatically stop a running conversation with the assistant
+        """
         assistant = get_backend('assistant.google')
         assistant.stop_conversation()
         return Response(output='', errors=[])
diff --git a/platypush/plugins/assistant/google/pushtotalk.py b/platypush/plugins/assistant/google/pushtotalk.py
index 41bedccc7..cd01b06e7 100644
--- a/platypush/plugins/assistant/google/pushtotalk.py
+++ b/platypush/plugins/assistant/google/pushtotalk.py
@@ -1,15 +1,31 @@
+"""
+.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
+"""
+
 from platypush.context import get_backend
 from platypush.message.response import Response
 
 from platypush.plugins import Plugin
 
 class AssistantGooglePushtotalkPlugin(Plugin):
+    """
+    Plugin for the Google assistant pushtotalk API.  It acts as a wrapper to
+    programmatically control a
+    :mod:`platypush.backend.assistant.google.pushtotalk` backend.
+    """
+
     def start_conversation(self):
+        """
+        Programmatically start a conversation with the assistant
+        """
         assistant = get_backend('assistant.google.pushtotalk')
         assistant.start_conversation()
         return Response(output='', errors=[])
 
     def stop_conversation(self):
+        """
+        Programmatically stop a running conversation with the assistant
+        """
         assistant = get_backend('assistant.google.pushtotalk')
         assistant.stop_conversation()
         return Response(output='', errors=[])
diff --git a/platypush/plugins/calendar/__init__.py b/platypush/plugins/calendar/__init__.py
index b82ea335d..760cbde29 100644
--- a/platypush/plugins/calendar/__init__.py
+++ b/platypush/plugins/calendar/__init__.py
@@ -1,3 +1,7 @@
+"""
+.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
+"""
+
 import dateutil.parser
 import importlib
 
@@ -17,16 +21,21 @@ class CalendarInterface:
 
 class CalendarPlugin(Plugin, CalendarInterface):
     """
-    The CalendarPlugin will allow you to keep track of multiple calendars
-    (Google or iCal URLs) and get joined events from all of them
+    The CalendarPlugin allows you to keep track of multiple calendars (Google or
+    iCal URLs) and get joined events from all of them.
+
+    Requires:
+        * **dateutil** (``pip install python-dateutil``)
     """
 
     def __init__(self, calendars=[], *args, **kwargs):
         """
-        Example calendars format:
+        :param calendars: List of calendars to be queried. Supported types so far: Google Calendar and iCal URLs.
+        :type calendars: list
 
-        ```
-            [
+        Example format::
+
+            calendars = [
                 {
                     "type": "platypush.plugins.google.calendar.GoogleCalendarPlugin"
                 },
@@ -56,6 +65,45 @@ class CalendarPlugin(Plugin, CalendarInterface):
 
 
     def get_upcoming_events(self, max_results=10):
+        """
+        Get a list of upcoming events merging all the available calendars.
+
+        :param max_results: Maximum number of results to be returned (default: 10)
+        :type max_results: int
+
+        :returns: platypush.message.Response -- Response object with the list of events in the Google calendar API format.
+
+        Example::
+
+            output = [
+                {
+                    "id": "123456abcdef",
+                    "kind": "calendar#event",
+                    "status": "confirmed",
+                    "htmlLink": "...",
+                    "created": "2018-06-01T01:23:45.000Z",
+                    "updated": "2018-06-01T01:23:45.000Z",
+                    "creator": {
+                        "email": "...",
+                        "displayName": "...",
+                        "self": true
+                    },
+                    "organizer" {
+                        "email": "...",
+                        "displayName": "...",
+                        "self": true
+                    },
+                    "start": {
+                        "dateTime": "2018-06-02T10:00:00.000Z",
+                    },
+                    "end": {
+                        "dateTime": "2018-06-02T12:00:00.000Z",
+                    },
+                },
+                ...
+            ]
+        """
+
         events = []
 
         for calendar in self.calendars:
diff --git a/platypush/plugins/calendar/ical.py b/platypush/plugins/calendar/ical.py
index 96b94265d..1373355ce 100644
--- a/platypush/plugins/calendar/ical.py
+++ b/platypush/plugins/calendar/ical.py
@@ -1,3 +1,7 @@
+"""
+.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
+"""
+
 import datetime
 import dateutil.parser
 import requests
@@ -11,7 +15,15 @@ from platypush.plugins.calendar import CalendarInterface
 
 
 class IcalCalendarPlugin(Plugin, CalendarInterface):
+    """
+    iCal calendars plugin. Interact with remote calendars in iCal format.
+    """
+
     def __init__(self, url, *args, **kwargs):
+        """
+        :param url: iCal URL to parse
+        :type url: str
+        """
         super().__init__(*args, **kwargs)
         self.url = url
 
@@ -46,6 +58,11 @@ class IcalCalendarPlugin(Plugin, CalendarInterface):
 
 
     def get_upcoming_events(self, max_results=10, only_participating=True):
+        """
+        Get the upcoming events. See
+        :func:`~platypush.plugins.calendar.CalendarPlugin.get_upcoming_events`.
+        """
+
         events = []
         response = requests.get(self.url)
 
diff --git a/platypush/plugins/camera/pi.py b/platypush/plugins/camera/pi.py
index 4fb65aa81..7ed993d6b 100644
--- a/platypush/plugins/camera/pi.py
+++ b/platypush/plugins/camera/pi.py
@@ -1,3 +1,7 @@
+"""
+.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
+"""
+
 from platypush.context import get_backend
 from platypush.message.response import Response
 
@@ -5,17 +9,35 @@ from platypush.plugins import Plugin
 
 
 class CameraPiPlugin(Plugin):
+    """
+    Plugin to control a Pi camera.
+    It acts as a wrapper around the :ref:`platypush.backend.camera.pi` backend
+    to programmatically control the status.
+    """
+
     def start_recording(self):
+        """
+        Start recording
+        """
         camera = get_backend('camera.pi')
         camera.send_camera_action(camera.CameraAction.START_RECORDING)
         return Response(output={'status':'ok'})
 
     def stop_recording(self):
+        """
+        Stop recording
+        """
         camera = get_backend('camera.pi')
         camera.send_camera_action(camera.CameraAction.STOP_RECORDING)
         return Response(output={'status':'ok'})
 
     def take_picture(self, image_file):
+        """
+        Take a picture.
+
+        :param image_file: Path where the output image will be stored.
+        :type image_file: str
+        """
         camera = get_backend('camera.pi')
         camera.send_camera_action(camera.CameraAction.TAKE_PICTURE, image_file=image_file)
         return Response(output={'image_file':image_file})
diff --git a/platypush/plugins/db/__init__.py b/platypush/plugins/db/__init__.py
index 5630ef7be..b945523e2 100644
--- a/platypush/plugins/db/__init__.py
+++ b/platypush/plugins/db/__init__.py
@@ -1,3 +1,7 @@
+"""
+.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
+"""
+
 from sqlalchemy import create_engine, Table, MetaData
 
 from platypush.message.response import Response
@@ -5,20 +9,26 @@ from platypush.message.response import Response
 from .. import Plugin
 
 class DbPlugin(Plugin):
-    """ Database plugin. It allows you to programmatically select, insert,
-        update and delete records on a database backend through requests,
-        procedures and event hooks """
+    """
+    Database plugin. It allows you to programmatically select, insert, update
+    and delete records on a database backend through requests, procedures and
+    event hooks.
+
+    Requires:
+        * **sqlalchemy** (``pip install sqlalchemy``)
+
+    .. todo::
+        Implement ``update`` and ``delete`` methods
+    """
 
     engine = None
 
     def __init__(self, engine=None, *args, **kwargs):
         """
-        Params:
-            engine -- Default SQLAlchemy connection engine string
-            (e.g. sqlite:///:memory: or mysql://user:pass@localhost/test)
-            that will be used. You can override this value in your statement actions
-
-            args, kwargs -- Extra arguments for sqlalchemy.create_engine
+        :param engine: Default SQLAlchemy connection engine string (e.g.  ``sqlite:///:memory:`` or ``mysql://user:pass@localhost/test``) that will be used. You can override the default engine in the db actions.
+        :type engine: str
+        :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html)
+        :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html)
         """
 
         self.engine = self._get_engine(engine, *args, **kwargs)
@@ -31,7 +41,23 @@ class DbPlugin(Plugin):
             return self.engine
 
     def execute(self, statement, engine=None, *args, **kwargs):
-        """ Executes a raw SQL statement """
+        """
+        Executes a raw SQL statement.
+
+        .. warning::
+            Avoid calling this method directly if possible.  Use ``insert``,
+            ``update`` and ``delete`` methods instead if possible.  Don't use this
+            method if you need to select records, use the ``select`` method
+            instead, as this method is mostly meant to execute raw SQL without
+            returning anything.
+
+        :param statement: SQL to be executed
+        :type statement: str
+        :param engine: Engine to be used (default: default class engine)
+        :type engine: str
+        :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html)
+        :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html)
+        """
 
         engine = self._get_engine(engine, *args, **kwargs)
 
@@ -43,7 +69,45 @@ class DbPlugin(Plugin):
 
 
     def select(self, query, engine=None, *args, **kwargs):
-        """ Returns rows (as a list of dicts) given a query """
+        """
+        Returns rows (as a list of hashes) given a query.
+
+        :param query: SQL to be executed
+        :type query: str
+        :param engine: Engine to be used (default: default class engine)
+        :type engine: str
+        :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html)
+        :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html)
+        :returns: List of hashes representing the result rows.
+
+        Example:
+
+            Request::
+
+                {
+                    "type": "request",
+                    "target": "your_host",
+                    "action": "db.select",
+                    "args": {
+                        "engine": "sqlite:///:memory:",
+                        "query": "SELECT id, name FROM table"
+                    }
+                }
+
+            Response::
+
+                [
+                    {
+                        "id": 1,
+                        "name": foo
+                    },
+
+                    {
+                        "id": 2,
+                        "name": bar
+                    }
+                ]
+        """
 
         engine = self._get_engine(engine, *args, **kwargs)
 
@@ -59,7 +123,43 @@ class DbPlugin(Plugin):
 
 
     def insert(self, table, records, engine=None, *args, **kwargs):
-        """ Inserts records (as a list of dicts) into a table """
+        """
+        Inserts records (as a list of hashes) into a table.
+
+        :param table: Table name
+        :type table: str
+        :param records: Records to be inserted (as a list of hashes)
+        :type records: list
+        :param engine: Engine to be used (default: default class engine)
+        :type engine: str
+        :param args: Extra arguments that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html)
+        :param kwargs: Extra kwargs that will be passed to ``sqlalchemy.create_engine`` (see http://docs.sqlalchemy.org/en/latest/core/engines.html)
+
+        Example:
+
+            Request::
+
+                {
+                    "type": "request",
+                    "target": "your_host",
+                    "action": "db.insert",
+                    "args": {
+                        "table": "table",
+                        "engine": "sqlite:///:memory:",
+                        "records": [
+                            {
+                                "id": 1,
+                                "name": foo
+                            },
+
+                            {
+                                "id": 2,
+                                "name": bar
+                            }
+                        ]
+                    }
+                }
+        """
 
         engine = self._get_engine(engine, *args, **kwargs)
 
diff --git a/platypush/plugins/google/__init__.py b/platypush/plugins/google/__init__.py
index a2761bd80..95707b554 100644
--- a/platypush/plugins/google/__init__.py
+++ b/platypush/plugins/google/__init__.py
@@ -1,3 +1,7 @@
+"""
+.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
+"""
+
 import os
 
 from platypush.plugins import Plugin
@@ -7,6 +11,7 @@ from platypush.plugins.google.credentials import get_credentials
 class GooglePlugin(Plugin):
     """
     Executes calls to the Google APIs using the google-api-python-client.
+    This class is extended by ``GoogleMailPlugin``, ``GoogleCalendarPlugin`` etc.
     In order to use Google services (like GMail, Maps, Calendar etc.) with
     your account you need to:
 
@@ -19,12 +24,23 @@ class GooglePlugin(Plugin):
 
         4. Click on the "Download JSON" icon next to your newly created client ID
 
-        5. Generate a credentials file for the needed scope:
+        5. Generate a credentials file for the needed scope::
 
-            $ python -m platypush.plugins.google.credentials 'https://www.googleapis.com/auth/gmail.compose' ~/client_secret.json
+            python -m platypush.plugins.google.credentials 'https://www.googleapis.com/auth/gmail.compose' ~/client_secret.json
+
+    Requires:
+
+        * **google-api-python-client** (``pip install google-api-python-client``)
     """
 
     def __init__(self, scopes, *args, **kwargs):
+        """
+        Initialized the Google plugin with the required scopes.
+
+        :param scopes: List of required scopes
+        :type scopes: list
+        """
+
         super().__init__(*args, **kwargs)
         self.credentials = {}
 
diff --git a/platypush/plugins/google/calendar.py b/platypush/plugins/google/calendar.py
index 4d6881b43..d35c1e600 100644
--- a/platypush/plugins/google/calendar.py
+++ b/platypush/plugins/google/calendar.py
@@ -1,3 +1,7 @@
+"""
+.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
+"""
+
 import base64
 import datetime
 import httplib2
@@ -11,6 +15,10 @@ from platypush.plugins.calendar import CalendarInterface
 
 
 class GoogleCalendarPlugin(GooglePlugin, CalendarInterface):
+    """
+    Google calendar plugin
+    """
+
     scopes = ['https://www.googleapis.com/auth/calendar.readonly']
 
     def __init__(self, *args, **kwargs):
@@ -18,6 +26,11 @@ class GoogleCalendarPlugin(GooglePlugin, CalendarInterface):
 
 
     def get_upcoming_events(self, max_results=10):
+        """
+        Get the upcoming events. See
+        :func:`~platypush.plugins.calendar.CalendarPlugin.get_upcoming_events`.
+        """
+
         now = datetime.datetime.utcnow().isoformat() + 'Z'
         service = self._get_service()
         result = service.events().list(calendarId='primary', timeMin=now,
diff --git a/platypush/plugins/google/mail.py b/platypush/plugins/google/mail.py
index a2e6254ba..8cb45ce2c 100644
--- a/platypush/plugins/google/mail.py
+++ b/platypush/plugins/google/mail.py
@@ -1,3 +1,7 @@
+"""
+.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
+"""
+
 import base64
 import httplib2
 import mimetypes
@@ -18,6 +22,10 @@ from platypush.plugins.google import GooglePlugin
 
 
 class GoogleMailPlugin(GooglePlugin):
+    """
+    GMail plugin. It allows you to programmatically compose and (TODO) get emails
+    """
+
     scopes = ['https://www.googleapis.com/auth/gmail.modify']
 
     def __init__(self, *args, **kwargs):
@@ -25,6 +33,25 @@ class GoogleMailPlugin(GooglePlugin):
 
 
     def compose(self, sender, to, subject, body, files=None):
+        """
+        Compose a message.
+
+        :param sender: Sender email/name
+        :type sender: str
+
+        :param to: Recipient email or comma-separated list of recipient emails
+        :type to: str
+
+        :param subject: Email subject
+        :type subject: str
+
+        :param body: Email body
+        :type body: str
+
+        :param files: Optional list of files to attach
+        :type files: list
+        """
+
         message = MIMEMultipart() if files else MIMEText(body)
         message['to'] = to
         message['from'] = sender
@@ -68,6 +95,9 @@ class GoogleMailPlugin(GooglePlugin):
 
 
     def get_labels(self):
+        """
+        Returns the available labels on the GMail account
+        """
         service = self._get_service()
         results = service.users().labels().list(userId='me').execute()
         labels = results.get('labels', [])
diff --git a/platypush/plugins/google/maps.py b/platypush/plugins/google/maps.py
index 4d0806219..6f38676fa 100644
--- a/platypush/plugins/google/maps.py
+++ b/platypush/plugins/google/maps.py
@@ -1,3 +1,7 @@
+"""
+.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
+"""
+
 import json
 import requests
 
@@ -6,14 +10,33 @@ from platypush.plugins.google import GooglePlugin
 
 
 class GoogleMapsPlugin(GooglePlugin):
+    """
+    Plugins that provides utilities to interact with Google Maps API services.
+    """
+
     scopes = []
 
     def __init__(self, api_key, *args, **kwargs):
+        """
+        :param api_key: Server-side API key to be used for the requests, get one at https://console.developers.google.com
+        :type api_key: str
+        """
+
         super().__init__(scopes=self.scopes, *args, **kwargs)
         self.api_key = api_key
 
 
     def get_address_from_latlng(self, latitude, longitude):
+        """
+        Get an address information given lat/long
+
+        :param latitude: Latitude
+        :type latitude: float
+
+        :param longitude: Longitude
+        :type longitude: float
+        """
+
         response = requests.get('https://maps.googleapis.com/maps/api/geocode/json',
                                 params = {
                                     'latlng': '{},{}'.format(latitude, longitude),
diff --git a/platypush/plugins/gpio/__init__.py b/platypush/plugins/gpio/__init__.py
index d7b1a18af..99f331cbb 100644
--- a/platypush/plugins/gpio/__init__.py
+++ b/platypush/plugins/gpio/__init__.py
@@ -1,14 +1,45 @@
+"""
+.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
+"""
+
 import threading
 import time
 
-import RPi.GPIO as gpio
-
 from platypush.message.response import Response
 from platypush.plugins import Plugin
 
 
 class GpioPlugin(Plugin):
+    """
+    Plugin to handle raw read/write operation on the Raspberry Pi GPIO pins.
+
+    Requires:
+        * **RPi.GPIO** (`pip install RPi.GPIO`)
+    """
+
     def write(self, pin, val):
+        """
+        Write a byte value to a pin.
+
+        :param pin: PIN number
+        :type pin: int
+
+        :param val: Value to write
+        :type val: int
+
+        :returns: dict
+
+        Response::
+
+            output = {
+                "pin": <pin>,
+                "val": <val>,
+                "method": "write"
+            }
+        """
+
+        import RPi.GPIO as gpio
+
         gpio.setmode(gpio.BCM)
         gpio.setup(pin, gpio.OUT)
         gpio.output(pin, val)
@@ -19,7 +50,26 @@ class GpioPlugin(Plugin):
             'method': 'write',
         })
 
-    def read(self, pin, val):
+    def read(self, pin):
+        """
+        Reads a value from a PIN.
+
+        :param pin: PIN number
+        :type pin: int
+
+        :returns: dict
+
+        Response::
+
+            output = {
+                "pin": <pin>,
+                "val": <val>,
+                "method": "read"
+            }
+        """
+
+        import RPi.GPIO as gpio
+
         gpio.setmode(gpio.BCM)
         gpio.setup(pin, gpio.IN)
         val = gpio.input(pin)
diff --git a/platypush/plugins/weather/forecast.py b/platypush/plugins/weather/forecast.py
index c4b078ad3..bacb9bdec 100644
--- a/platypush/plugins/weather/forecast.py
+++ b/platypush/plugins/weather/forecast.py
@@ -15,6 +15,7 @@ class WeatherForecastPlugin(HttpRequestPlugin):
 
     def get_current_weather(self, **kwargs):
         response = self.get(self.url)
+        print(response)
         return Response(output=response.output['currently'])
 
     def get_hourly_forecast(self, **kwargs):